As a way of learning about Rust's traits and generics I'm implementing a basic vector math library. My current idea for the vectors themselves was to create a Vector trait that defined and implemented all operations on vectors (dot, cross, ...) and then have specific vector types (Float2, Float3, Uint3, ...) implement that trait. This would let me only implement Vector methods and operator overloading on the actual Vector trait and then have some tiny TypeN, e.g. Float3, structs that implement the Vector trait. This is working so far for a specific Float3, but not quite as intended. Ideally I would like to use the std::ops::Index trait for indexing into the Vectors elements,
The code so far
pub trait Vector : Index<usize> {
fn element_count(&self) -> usize;
fn dot(&self, rhs: &Vector) -> f64 {
let mut res = 0.0;
for i in 0..self.element_count() {
res += self[i] * rhs[i];
}
res
}
}
#[derive(Copy, Clone)]
pub struct Float3 {
pub x: f64,
pub y: f64,
pub z: f64,
}
impl Index<usize> for Float3 {
type Output = f64;
#[inline]
fn index<'a>(&'a self, i: &usize) -> &'a f64 {
let slice: &[f64; 3] = unsafe { mem::transmute(self) };
&slice[*i]
}
}
impl Vector for Float3 {
fn element_count(&self) -> usize {
3
}
}
however, this fails with the compiler errors
error: binary operation *
cannot be applied to type <Self as core::ops::Index<usize>>::Output
error: the value of the associated type Output
(from the trait core::ops::Index
) must be specified
which makes perfect sense as output haven't been specified, but how do I do that? Is is possible to specify Index::Output as part of the Vector trait?
And what happens when I want to add the add, sub, mul and other traits that have their own Output type to Vector? Is that even possible? Or can I implement the Index and math operator traits for Vector instead of 'inherit' from them?
Is what I'm trying to do possible in Rust or is there a better / more idiomatic implementation.