Crate impl_ops [] [src]

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:

#[derive(Clone, Debug, PartialEq)]
struct DonkeyKong {
    pub bananas: i32,
}
impl DonkeyKong {
    pub fn new(bananas: i32) -> DonkeyKong {
        DonkeyKong { bananas: bananas }
    }
}

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
 
#[macro_use] extern crate impl_ops;
use std::ops;

impl_op!(- |a: DonkeyKong, b: i32| -> DonkeyKong { DonkeyKong::new(a.bananas - b) });
impl_op!(+ |a: &DonkeyKong, b: &DonkeyKong| -> i32 { a.bananas + b.bananas });

fn main() {
    let dk = DonkeyKong::new(3) - 1;
    assert_eq!(DonkeyKong::new(2), dk);
    let total_bananas = &dk + &DonkeyKong::new(4);
    assert_eq!(6, total_bananas);
}

Assignment operators

// impl_op!(OP |a: &mut LHS, b: RHS| {...});
// impl_op!(op |a: &mut LHS, b: &RHS| {...})
// where
// op  : +=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=
// a, b: variable names
 
#[macro_use] extern crate impl_ops;
use std::ops;

impl_op!(+= |a: &mut DonkeyKong, b: DonkeyKong| { a.bananas += b.bananas });
impl_op!(+= |a: &mut DonkeyKong, b: &DonkeyKong| { a.bananas += b.bananas });

fn main() {
    let mut dk = DonkeyKong::new(3);
    dk += DonkeyKong::new(1);
    assert_eq!(DonkeyKong::new(4), dk);
    dk += &DonkeyKong::new(1);
    assert_eq!(DonkeyKong::new(5), dk);
}

Unary operators

// impl_op!(OP |a: LHS| -> OUT {...});
// impl_op!(op |a: &LHS| -> OUT {...})
// where
// OP: !, -
// a : variable name

#[macro_use] extern crate impl_ops;
use std::ops;

impl_op!(- |a: DonkeyKong| -> DonkeyKong { DonkeyKong::new(-a.bananas) });
impl_op!(- |a: &DonkeyKong| -> DonkeyKong { DonkeyKong::new(-a.bananas) });

fn main() {
    let dk = -DonkeyKong::new(3);
    assert_eq!(DonkeyKong::new(-3), dk);
    assert_eq!(DonkeyKong::new(3), -&dk);
}

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

Macros

impl_op

Overloads an operator using the given closure as its body.

impl_op_commutative

Overloads a binary operator commutatively using the given closure as its body.

impl_op_ex

Overloads an operator using the given closure as its body. Generates overloads for both owned and borrowed variants where possible.

impl_op_ex_commutative

Overloads a binary operator commutatively using the given closure as its body. Generates overloads for both owned and borrowed variants where possible.