Macros for easy operator overloading.
The primary macro to learn is impl_op!(<op> <closure>);
where <op>
is an operator and <closure>
is a closure with the same signature as the trait function associated with <op>
.
The macro you'll actually want to use most of the time, however, is impl_op_ex!
. It works the same way as impl_op!
but with some extra magic behind the scenes.
To use, include #[macro_use] extern crate impl_ops;
in your crate and use std::ops;
in your module. Remember that you can only overload operators between one or more types defined in the current crate.
Examples
All of the following examples are run with the following struct defined:
Binary operators
// impl_op!(op |a: LHS, b: RHS| -> OUT {...});
// impl_op!(op |a: LHS, b: &RHS| -> OUT {...});
// impl_op!(op |a: &LHS, b: RHS| -> OUT {...});
// impl_op!(op |a: &LHS, b: &RHS| -> OUT {...});
// where
// OP : +, -, *, /, %, &, |, ^, <<, >>
// a, b: variable names
extern crate impl_ops;
use ops;
#
#
#
impl_op!;
impl_op!;
Assignment operators
// impl_op!(OP |a: &mut LHS, b: RHS| {...});
// impl_op!(op |a: &mut LHS, b: &RHS| {...})
// where
// op : +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
// a, b: variable names
extern crate impl_ops;
use ops;
#
#
#
impl_op!;
impl_op!;
Unary operators
// impl_op!(OP |a: LHS| -> OUT {...});
// impl_op!(op |a: &LHS| -> OUT {...})
// where
// OP: !, -
// a : variable name
extern crate impl_ops;
use ops;
#
#
#
impl_op!;
impl_op!;
Limitations
- The output type of any operation must be an owned type (i.e.
impl_op!(+ |a: DonkeyKong b: i32| -> &DonkeyKong {...})
is invalid). - Types that have an unqualified lifetime or associated type are invalid
// impl_op!(+ |a: SomeType<'a>, b: SomeType<'a>| -> SomeType<'a> {...}) // INVALID
// impl_op!(+ |a: SomeType<T>, b: SomeType<T>| -> SomeType<T> {...}) // INVALID
impl_op!(+ |a: SomeType<i32>, b: SomeType<i32>| -> SomeType<i32> {...}) // VALID