3 releases
0.1.2 | Aug 12, 2019 |
---|---|
0.1.1 | Aug 12, 2019 |
0.1.0 | Aug 10, 2019 |
#383 in No standard library
16KB
199 lines
operator-sugar
Makes operator overloading in Rust more concise and intuitive.
See the documentation for details.
lib.rs
:
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));
}