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 Val
s 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 Val
s:
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 Val
s and &Val
s 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>
.
Operator | Example | Trait |
---|---|---|
+ | 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.
Operator | Example | Trait |
---|---|---|
+= | 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>
.
Operator | Example | Trait |
---|---|---|
- | 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
- Overloads an operator. See the module level documentation for more information.