[][src]Crate overload

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:

This example is not tested
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:

This example is not tested
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:

This example is not tested
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:

This example is not tested
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:

This example is not tested
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.