//! 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: | |
//! ``` | |
//! # extern crate overload; | |
//! # use overload::overload; | |
//! # use std::ops; | |
//! # #[derive(PartialEq, Debug)] | |
//! # struct Val { | |
//! # v: i32 | |
//! # } | |
//! overload!((a: Val) + (b: Val) -> Val { Val { v: a.v + b.v } }); | |
//! ``` | |
//! The macro call above generates the following code: | |
//! ```ignore | |
//! 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: | |
//! ``` | |
//! # extern crate overload; | |
//! # use overload::overload; | |
//! # use std::ops; | |
//! # #[derive(PartialEq, Debug)] | |
//! # struct Val { | |
//! # v: i32 | |
//! # } | |
//! # overload!((a: Val) + (b: Val) -> Val { Val { v: a.v + b.v } }); | |
//! 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: | |
//! ``` | |
//! # extern crate overload; | |
//! # use overload::overload; | |
//! # use std::ops; | |
//! # #[derive(PartialEq, Debug)] | |
//! # struct Val { | |
//! # v: i32 | |
//! # } | |
//! 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: | |
//! ``` | |
//! # extern crate overload; | |
//! # use overload::overload; | |
//! # use std::ops; | |
//! # #[derive(PartialEq, Debug)] | |
//! # struct Val { | |
//! # v: i32 | |
//! # } | |
//! 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: | |
//! ``` | |
//! # extern crate overload; | |
//! # use overload::overload; | |
//! # use std::ops; | |
//! # #[derive(PartialEq, Debug)] | |
//! # struct Val { | |
//! # v: i32 | |
//! # } | |
//! overload!((a: ?Val) + (b: ?Val) -> Val { Val { v: a.v + b.v } }); | |
//! ``` | |
//! The macro call above generates the following code: | |
//! ```ignore | |
//! 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: | |
//! ``` | |
//! # extern crate overload; | |
//! # use overload::overload; | |
//! # use std::ops; | |
//! # #[derive(PartialEq, Debug)] | |
//! # struct Val { | |
//! # v: i32 | |
//! # } | |
//! # overload!((a: ?Val) + (b: ?Val) -> Val { Val { v: a.v + b.v } }); | |
//! 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: | |
//! ```ignore | |
//! 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 | | |
//! | \| | <code>overload!((a: A) | (b: B) -> C { /\*...*\/ );</code> | 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: | |
//! ```ignore | |
//! 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 | | |
//! | \|= | <code>overload!((a: &mut A) |= (b: B) { /\*...*\/ );</code> | 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: | |
//! ```ignore | |
//! 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. | |
#[macro_use] | |
mod unary; | |
#[macro_use] | |
mod assignment; | |
#[macro_use] | |
mod binary; | |
/// Overloads an operator. See the [module level documentation](index.html) for more information. | |
#[macro_export(local_inner_macros)] | |
macro_rules! overload { | |
// Unary (both owned and borrowed) | |
($op:tt ($i:ident : ? $t:ty) -> $out:ty $body:block) => ( | |
_overload_unary!($op, $i, $t, $out, $body); | |
_overload_unary!($op, $i, &$t, $out, $body); | |
); | |
// Unary (either owned or borrowed) | |
($op:tt ($i:ident : $t:ty) -> $out:ty $body:block) => ( | |
_overload_unary!($op, $i, $t, $out, $body); | |
); | |
// Assignment (both owned and borrowed) | |
(($li:ident : &mut $lt:ty) $op:tt ($ri:ident : ? $rt:ty) $body:block) => ( | |
_overload_assignment!($op, $li, $lt, $ri, $rt, $body); | |
_overload_assignment!($op, $li, $lt, $ri, &$rt, $body); | |
); | |
// Assignment (either owned or borrowed) | |
(($li:ident : &mut $lt:ty) $op:tt ($ri:ident : $rt:ty) $body:block) => ( | |
_overload_assignment!($op, $li, $lt, $ri, $rt, $body); | |
); | |
// Binary (both - both) | |
(($li:ident : ? $lt:ty) $op:tt ($ri:ident : ? $rt:ty) -> $out:ty $body:block) => ( | |
_overload_binary!($op, $li, $lt, $ri, $rt, $out, $body); | |
_overload_binary!($op, $li, $lt, $ri, &$rt, $out, $body); | |
_overload_binary!($op, $li, &$lt, $ri, $rt, $out, $body); | |
_overload_binary!($op, $li, &$lt, $ri, &$rt, $out, $body); | |
); | |
// Binary (both - either) | |
(($li:ident : ? $lt:ty) $op:tt ($ri:ident : $rt:ty) -> $out:ty $body:block) => ( | |
_overload_binary!($op, $li, $lt, $ri, $rt, $out, $body); | |
_overload_binary!($op, $li, &$lt, $ri, $rt, $out, $body); | |
); | |
// Binary (either - both) | |
(($li:ident : $lt:ty) $op:tt ($ri:ident : ? $rt:ty) -> $out:ty $body:block) => ( | |
_overload_binary!($op, $li, $lt, $ri, $rt, $out, $body); | |
_overload_binary!($op, $li, $lt, $ri, &$rt, $out, $body); | |
); | |
// Binary (either - either) | |
(($li:ident : $lt:ty) $op:tt ($ri:ident : $rt:ty) -> $out:ty $body:block) => ( | |
_overload_binary!($op, $li, $lt, $ri, $rt, $out, $body); | |
); | |
} |