Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dividing a const by a generic in Rust

I have a struct Vec3<T>, how can I implement the following method ?

impl<T: num::Num + num::Float> Not<Vec3<T>> for Vec3<T> {
    fn not(&self) -> Vec3<T> {
        *self * (1.0 / (*self % *self).sqrt())
    }
}

error: mismatched types: expected _, found T (expected floating-point variable, found type parameter)

Type of 1.0 is _ while type of (*self % *self).sqrt() is T. And it seems it can't divide a _ by a T.

I tried various casting for 1.0 :

*self * ((1.0 as T) / (*self % *self).sqrt())

error: non-scalar cast: _ as T

*self * (1.0.div((*self % *self).sqrt()))

error: mismatched types: expected &_, found T (expected &-ptr, found type parameter)

What is the sleekest way to implement this method ?

Edit 1: As requested, here is my full code :

use std::num::Float;

pub struct Vec3<T> {
    pub x: T,
    pub y: T,
    pub z: T,
}

impl<T> Vec3<T> {
    pub fn new(x: T, y: T, z: T) -> Vec3<T> {
        Vec3 { x: x, y: y, z: z }
    }
}

impl<T: Float> Add<T, Vec3<T>> for Vec3<T> {
    fn add(&self, rhs: &T) -> Vec3<T> {
        Vec3 { x: self.x + *rhs, y: self.y + *rhs, z: self.z + *rhs }
    }
}

impl<T: Float> Add<Vec3<T>, Vec3<T>> for Vec3<T> {
    fn add(&self, rhs: &Vec3<T>) -> Vec3<T> {
        Vec3 { x: self.x + rhs.x, y: self.y + rhs.y, z: self.z + rhs.z }
    }
}

impl<T: Float> Mul<T, Vec3<T>> for Vec3<T> {
    fn mul(&self, rhs: &T) -> Vec3<T> {
        Vec3 { x: self.x * *rhs, y: self.y * *rhs, z: self.z * *rhs }
    }
}

// x % y : dot-product
impl<T: Float> Rem<Vec3<T>, T> for Vec3<T> {
    fn rem(&self, rhs: &Vec3<T>) -> T {
        self.x + rhs.x * self.y + rhs.y * self.z + rhs.z
    }
}

// x ^ y : cross-product
impl<T: Float> BitXor<Vec3<T>, Vec3<T>> for Vec3<T> {
    fn bitxor(&self, rhs: &Vec3<T>) -> Vec3<T> {
        Vec3 { x: self.y * rhs.z - self.z * rhs.y,
               y: self.z * rhs.x - self.x * rhs.z,
               z: self.x * rhs.y - self.y * rhs.x }
    }
}

// !x : Norm
impl Not<Vec3<f32>> for Vec3<f32> {
    fn not(&self) -> Vec3<f32> {
        *self * (1.0f32 / (*self % *self).sqrt())
    }
}

impl Not<Vec3<f64>> for Vec3<f64> {
    fn not(&self) -> Vec3<f64> {
        *self * (1.0f64 / (*self % *self).sqrt())
    }
}

I would have used Num instead of Float to be able to have integer vectors, but since it's deprecated, I think the better option is to use macro to duplicate code for all types. Here I duplicated Not for f32 and f64

like image 616
Shengis Avatar asked Dec 12 '14 10:12

Shengis


1 Answers

Literals can only be of primitive types. You can't cast a literal to some generic type.

For constants like 1.0 you can use methods like Float::one(), so your specific example could be rewritten as

impl<T: num::Float> Not<Vec3<T>> for Vec3<T> {
    fn not(&self) -> Vec3<T> {
        *self * (num::Float::one() / (*self % *self).sqrt())
    }
}

(note that I removed Num bound because it is deprecated and in this case it is entirely superseded by Float)

To convert arbitrary values to instances of some specific Float type you can use NumCast::from() method:

let x: T = num::NumCast::from(3.14f64);

BTW, you may find this accepted RFC interesting.

Update

It is likely that you won't be able to implement Float for your structure because it has a lot of methods specific to bare floats, like mantissa size. I guess you will have to add methods like one() and zero() and probably casts from numbers yourself. Then you will be able to write

impl<T: num::Float> Not<Vec3<T>> for Vec3<T> {
    fn not(&self) -> Vec3<T> {
        *self * (Vec3::one() / (*self % *self).sqrt())
    }
}
like image 164
Vladimir Matveev Avatar answered Oct 24 '22 22:10

Vladimir Matveev