Crate operator_sugar

Source
Expand description

This crate provides simple macros that serve as syntactic sugar to make overloading operators in Rust easier.

The basic syntax for binary operators is in this format:

struct Left(i32);
struct Right(i32);
struct Answer(i32);

operator!(Left, Right: a + b -> Answer {
    // Implementation of the operator function here
    Answer(a.0 + b.0)
});

For unary operators:

struct Operand(i32);
struct Answer(i32);

operator!(Operand: -a -> Answer {
    Answer(-a.0)
});

§Meta Attributes

Attributes can be applied to the impl block (which implements e.g. Add) and the fn block respectively:

struct Left(i32);
struct Right(i32);
struct Answer(i32);

operator!(
    #[doc("This attribute will be applied on the `impl` block")] Left, Right:
    #[doc("This attribute will be applied on the `fn` block")] a + b -> Answer {
        Answer(a.0 + b.0)
    });

§Generics

Generics can be used on the three types and on the impl block.

Due to disambiguation, generic parameters for the impl block must be written in {} rather than <>.

use core::ops::Add;
struct Left<T>(T) where T: Add<i32, Output = i32>;
struct Right(i32);
struct Answer(i32);

operator!(
    {T: Add<i32, Output = i32>}
    Left<T>, Right: a + b -> Answer {
        Answer(a.0 + b.0)
    });

§List of operators

For conciseness, these definitions are defined for each of the following examples:

use operator_sugar::*;
#[derive(Debug)] struct Left(i32);
#[derive(Debug)] struct Right(i32);
#[derive(Debug, Eq, PartialEq)] struct Answer(i32);

§Addition

operator!(Left, Right: a + b -> Answer {
    Answer(a.0 + b.0)
});

fn main() {
    assert_eq!(Left(1) + Right(2), Answer(3));
}

§Subtraction

operator!(Left, Right: a - b -> Answer {
    Answer(a.0 - b.0)
});

fn main() {
    assert_eq!(Left(1) - Right(2), Answer(-1));
}

§Multiplication

operator!(Left, Right: a * b -> Answer {
    Answer(a.0 * b.0)
});

fn main() {
    assert_eq!(Left(3) * Right(2), Answer(6));
}

§Division

operator!(Left, Right: a / b -> Answer {
    Answer(a.0 / b.0)
});

fn main() {
    assert_eq!(Left(8) / Right(2), Answer(4));
}

§Remainder

operator!(Left, Right: a % b -> Answer {
    Answer(a.0 % b.0)
});

fn main() {
    assert_eq!(Left(9) % Right(5), Answer(4));
}

§Bitwise AND

operator!(Left, Right: a & b -> Answer {
    Answer(a.0 & b.0)
});

fn main() {
    assert_eq!(Left(5) & Right(6), Answer(4));
}

§Bitwise OR

operator!(Left, Right: a | b -> Answer {
    Answer(a.0 | b.0)
});

fn main() {
    assert_eq!(Left(5) | Right(6), Answer(7));
}

§Bitwise XOR

operator!(Left, Right: a ^ b -> Answer {
    Answer(a.0 ^ b.0)
});

fn main() {
    assert_eq!(Left(5) ^ Right(6), Answer(3));
}

§Shift-left

operator!(Left, Right: a << b -> Answer {
    Answer(a.0 << b.0)
});

fn main() {
    assert_eq!(Left(5) << Right(3), Answer(40));
}

§Shift-right

operator!(Left, Right: a >> b -> Answer {
    Answer(a.0 >> b.0)
});

fn main() {
    assert_eq!(Left(43) >> Right(3), Answer(5));
}

§Index

#[derive(Debug)] struct Left(Vec<i32>);
#[derive(Debug)] struct Right(usize);

operator!(Left, Right: a[b] -> &i32 {
    // The & is required to remind developers that a reference is to be returned.
    &a.0[b.0]
});

fn main() {
    // We check for 6 not &6, because while the impl returns &6, the [] operator from Rust dereferences it.
    assert_eq!(Left(vec![5, 6, 7])[Right(1)], 6);
}

§Negative (-)


operator!(Left: -a -> Answer {
    Answer(-a.0)
});

fn main() {
    assert_eq!(-Left(43), Answer(-43));
}

§Not (!)


operator!(Left: !a -> Answer {
    Answer(!a.0)
});

fn main() {
    assert_eq!(!Left(43), Answer(!43));
}

Macros§

operator