Auto deref when implementing add?

I want to implement the + operator for my struct, but right now I have to do :

impl<'a, T: Add<Output = T> + Copy, const SIZE: usize> Add for &'a Vector<T, SIZE> {
    type Output = Vector<T, SIZE>;

    fn add(self, rhs: Self) -> Self::Output {
        let mut i = 0;
        let mut coords: [T; SIZE] = self.coords.map(|e| {
            let val = (e + rhs.coords[i]);
            i += 1;
            return val;
        });
        Vector {
            coords
        }
    }
}

impl<T: Add<Output = T> + Copy, const SIZE: usize> Add for Vector<T, SIZE> {
    type Output = Vector<T, SIZE>;

    fn add(self, rhs: Self) -> Self::Output {
        let mut i = 0;
        let mut coords: [T; SIZE] = self.coords.map(|e| {
            let val = (e + rhs.coords[i]);
            i += 1;
            return val;
        });
        Vector {
            coords
        }
    }
}

To get both a + b and &a + &b working.
Is there a way for me to only implement Add once and for the rust compiler to add & or * automatically ? Maybe by adding some trait bound ?

You can do pretty well with macros that define several implementations in terms of one that you implement manually. This post has a few examples.

1 Like

Yeah macros are probably the way to go

I came up with this :

macro_rules! impl_operator_for_vector {
    ($self_vector_type: ty, $rhs_vector_type: ty, $operator_trait: tt, $function_name: ident, $operator_symbol: tt) => {
        impl<T: $operator_trait<Output = T> + Copy, const SIZE: usize> $operator_trait<$rhs_vector_type> for $self_vector_type {
            type Output = Vector<T, SIZE>;

            fn $function_name(self, rhs: $rhs_vector_type) -> Self::Output {
                let mut i = 0;
                let mut coords: [T; SIZE] = self.coords.map(|e| {
                    let val = (e $operator_symbol rhs.coords[i]);
                    i += 1;
                    return val;
                });
                Vector {
                    coords
                }
            }
        }
    }
}

macro_rules! impl_operator_for_vector_all {
    ($vector_type: ty, $operator_trait: tt, $function_name: ident, $operator_symbol: tt) => {
        impl_operator_for_vector!($vector_type, $vector_type, $operator_trait, $function_name, $operator_symbol);
        impl_operator_for_vector!(&$vector_type, $vector_type, $operator_trait, $function_name, $operator_symbol);
        impl_operator_for_vector!($vector_type, &$vector_type, $operator_trait, $function_name, $operator_symbol);
        impl_operator_for_vector!(&$vector_type, &$vector_type, $operator_trait, $function_name, $operator_symbol);
    }
}

impl_operator_for_vector_all!(Vector<T, SIZE>, Add, add, +);
impl_operator_for_vector_all!(Vector<T, SIZE>, Sub, sub, -);