Crate overload

Source
Expand description

Provides a macro to simplify operator overloading.

To use, include the following:

extern crate overload;
use overload::overload;
use std::ops; // <- don't forget this or you'll get nasty errors

§Introduction

Suppose we have the following struct definition:

#[derive(PartialEq, Debug)]
struct Val {
    v: i32
}

We can overload the addition of Vals like so:

overload!((a: Val) + (b: Val) -> Val { Val { v: a.v + b.v } });

The macro call above generates the following code:

impl ops::Add<Val> for Val {
    type Output = Val;
    fn add(self, b: Val) -> Self::Output {
        let a = self;
        Val { v: a.v + b.v }
    }
}

We are now able to add Vals:

assert_eq!(Val{v:3} + Val{v:5}, Val{v:8});

§Owned and borrowed types

If we also wanted to overload addition for the borrowed type &Val we could write:

overload!((a: &Val) + (b: &Val) -> Val { Val { v: a.v + b.v } });

We might also want to overload addition between the owned and borrowed types:

overload!((a: Val) + (b: &Val) -> Val { Val { v: a.v + b.v } });
overload!((a: &Val) + (b: Val) -> Val { Val { v: a.v + b.v } });

Let’s see how we can write these combinations more concisely.

We can include a ? in front of a type to indicate that it should stand in for both the owned and borrowed type.

To overload addition for all four combinations between Val and &Val we can therefore simply include a ? in front of both types:

overload!((a: ?Val) + (b: ?Val) -> Val { Val { v: a.v + b.v } });

The macro call above generates the following code:

impl ops::Add<Val> for Val {
    type Output = Val;
    fn add(self, b: Val) -> Self::Output {
        let a = self;
        Val { v: a.v + b.v }
    }
}
 
impl ops::Add<&Val> for Val {
    type Output = Val;
    fn add(self, b: &Val) -> Self::Output {
        let a = self;
        Val { v: a.v + b.v }
    }
}
 
impl ops::Add<Val> for &Val {
    type Output = Val;
    fn add(self, b: Val) -> Self::Output {
        let a = self;
        Val { v: a.v + b.v }
    }
}
 
impl ops::Add<&Val> for &Val {
    type Output = Val;
    fn add(self, b: &Val) -> Self::Output {
        let a = self;
        Val { v: a.v + b.v }
    }
}

We are now able to add Vals and &Vals in any combination:

assert_eq!(Val{v:3} + Val{v:5}, Val{v:8});
assert_eq!(Val{v:3} + &Val{v:5}, Val{v:8});
assert_eq!(&Val{v:3} + Val{v:5}, Val{v:8});
assert_eq!(&Val{v:3} + &Val{v:5}, Val{v:8});

§Binary operators

The general syntax to overload a binary operator between types <a_type> and <b_type> is:

overload!((<a_ident>: <a_type>) <op> (<b_ident>: <b_type>) -> <out_type> { /*body*/ });

Inside the body you can use <a_ident> and <b_ident> freely to perform any computation.

The last line of the body needs to be an expression (i.e. no ; at the end of the line) of type <out_type>.

OperatorExampleTrait
+overload!((a: A) + (b: B) -> C { /*...*/ );Add
-overload!((a: A) - (b: B) -> C { /*...*/ );Sub
*overload!((a: A) * (b: B) -> C { /*...*/ );Mul
/overload!((a: A) / (b: B) -> C { /*...*/ );Div
%overload!((a: A) % (b: B) -> C { /*...*/ );Rem
&overload!((a: A) & (b: B) -> C { /*...*/ );BitAnd
|overload!((a: A) | (b: B) -> C { /*…*/ );BitOr
^overload!((a: A) ^ (b: B) -> C { /*...*/ );BitXor
<<overload!((a: A) << (b: B) -> C { /*...*/ );Shl
>>overload!((a: A) >> (b: B) -> C { /*...*/ );Shr

§Assignment operators

The general syntax to overload an assignment operator between types <a_type> and <b_type> is:

overload!((<a_ident>: &mut <a_type>) <op> (<b_ident>: <b_type>) { /*body*/ });

Inside the body you can use <a_ident> and <b_ident> freely to perform any computation and mutate <a_ident> as desired.

OperatorExampleTrait
+=overload!((a: &mut A) += (b: B) { /*...*/ );AddAssign
-=overload!((a: &mut A) -= (b: B) { /*...*/ );SubAssign
*=overload!((a: &mut A) *= (b: B) { /*...*/ );MulAssign
/=overload!((a: &mut A) /= (b: B) { /*...*/ );DivAssign
%=overload!((a: &mut A) %= (b: B) { /*...*/ );RemAssign
&=overload!((a: &mut A) &= (b: B) { /*...*/ );BitAndAssign
|=overload!((a: &mut A) |= (b: B) { /*…*/ );BitOrAssign
^=overload!((a: &mut A) ^= (b: B) { /*...*/ );BitXorAssign
<<=overload!((a: &mut A) <<= (b: B) { /*...*/ );ShlAssign
>>=overload!((a: &mut A) >>= (b: B) { /*...*/ );ShrAssign

§Unary operators

The general syntax to overload a unary operator for type <a_type> is:

overload!(<op> (<a_ident>: <a_type>) -> <out_type> { /*body*/ });

Inside the body you can use <a_ident> freely to perform any computation.

The last line of the body needs to be an expression (i.e. no ; at the end of the line) of type <out_type>.

OperatorExampleTrait
-overload!(- (a: A) -> B { /*...*/ );Neg
!overload!(! (a: A) -> B { /*...*/ );Not

§Notes

Remember that you can only overload operators between one or more types if at least one of the types is defined in the current crate.

Macros§

overload
Overloads an operator. See the module level documentation for more information.