Add new traits for reference and assignment operators
There are two new "utility" traits covering the basic operators: `Add`, `Sub`, `Mul`, `Div`, and `Rem`. - `NumOps<Rhs, Output>`: operators with an arbitrary operand and output. - `NumAssignOps<Rhs>`: assignment operators with an arbitrary operand. Then the new collection of numeric traits are: - `Num`: effectively unchanged, just taking operands by value. - `NumRef`: `Num` adding reference operands on the right side. - `RefNum`: `&T` operators, with either `T` or `&T` on the right side. - This does not specify `T: Num`, as rust-lang/rust#20671 means that could only add a constraint, without implying its presence for use. - `NumAssign`: `Num` adding assignment operators by value. - `NumAssignRef`: `NumAssign` adding reference assignment operators. - Nothing actually implements this yet! Acknowledgement: this is roughly based on [@andersk's suggestion][1]. [1] https://github.com/rust-num/num/issues/94#issuecomment-269073071
This commit is contained in:
parent
ef08fe2f96
commit
21b520ea15
|
@ -15,6 +15,7 @@
|
|||
html_playground_url = "http://play.integer32.com/")]
|
||||
|
||||
use std::ops::{Add, Sub, Mul, Div, Rem};
|
||||
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
|
||||
use std::num::Wrapping;
|
||||
|
||||
pub use bounds::Bounded;
|
||||
|
@ -37,10 +38,9 @@ pub mod cast;
|
|||
pub mod int;
|
||||
pub mod pow;
|
||||
|
||||
/// The base trait for numeric types
|
||||
pub trait Num: PartialEq + Zero + One
|
||||
+ Add<Output = Self> + Sub<Output = Self>
|
||||
+ Mul<Output = Self> + Div<Output = Self> + Rem<Output = Self>
|
||||
/// The base trait for numeric types, covering `0` and `1` values,
|
||||
/// comparisons, basic numeric operations, and string conversion.
|
||||
pub trait Num: PartialEq + Zero + One + NumOps
|
||||
{
|
||||
type FromStrRadixErr;
|
||||
|
||||
|
@ -60,6 +60,72 @@ pub trait Num: PartialEq + Zero + One
|
|||
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
|
||||
}
|
||||
|
||||
/// The trait for types implementing basic numeric operations
|
||||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait NumOps<Rhs = Self, Output = Self>
|
||||
: Add<Rhs, Output = Output>
|
||||
+ Sub<Rhs, Output = Output>
|
||||
+ Mul<Rhs, Output = Output>
|
||||
+ Div<Rhs, Output = Output>
|
||||
+ Rem<Rhs, Output = Output>
|
||||
{}
|
||||
|
||||
impl<T, Rhs, Output> NumOps<Rhs, Output> for T
|
||||
where T: Add<Rhs, Output = Output>
|
||||
+ Sub<Rhs, Output = Output>
|
||||
+ Mul<Rhs, Output = Output>
|
||||
+ Div<Rhs, Output = Output>
|
||||
+ Rem<Rhs, Output = Output>
|
||||
{}
|
||||
|
||||
/// The trait for `Num` types which also implement numeric operations taking
|
||||
/// the second operand by reference.
|
||||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait NumRef: Num + for<'r> NumOps<&'r Self> {}
|
||||
impl<T> NumRef for T where T: Num + for<'r> NumOps<&'r T> {}
|
||||
|
||||
/// The trait for references which implement numeric operations, taking the
|
||||
/// second operand either by value or by reference.
|
||||
///
|
||||
/// This is automatically implemented for all `&T` implementing the operators.
|
||||
pub trait RefNum<Base>: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
|
||||
impl<'a, T> RefNum<T> for &'a T where &'a T: NumOps<T, T> + for<'r> NumOps<&'r T, T> {}
|
||||
|
||||
/// The trait for types implementing numeric assignment operators (like `+=`).
|
||||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait NumAssignOps<Rhs = Self>
|
||||
: AddAssign<Rhs>
|
||||
+ SubAssign<Rhs>
|
||||
+ MulAssign<Rhs>
|
||||
+ DivAssign<Rhs>
|
||||
+ RemAssign<Rhs>
|
||||
{}
|
||||
|
||||
impl<T, Rhs> NumAssignOps<Rhs> for T
|
||||
where T: AddAssign<Rhs>
|
||||
+ SubAssign<Rhs>
|
||||
+ MulAssign<Rhs>
|
||||
+ DivAssign<Rhs>
|
||||
+ RemAssign<Rhs>
|
||||
{}
|
||||
|
||||
/// The trait for `Num` types which also implement assignment operators.
|
||||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait NumAssign: Num + NumAssignOps {}
|
||||
impl<T> NumAssign for T where T: Num + NumAssignOps {}
|
||||
|
||||
/// The trait for `NumAssign` types which also implement assignment operations
|
||||
/// taking the second operand by reference.
|
||||
///
|
||||
/// This is automatically implemented for types which implement the operators.
|
||||
pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {}
|
||||
impl<T> NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {}
|
||||
|
||||
|
||||
macro_rules! int_trait_impl {
|
||||
($name:ident for $($t:ty)*) => ($(
|
||||
impl $name for $t {
|
||||
|
@ -315,3 +381,55 @@ fn wrapping_is_num() {
|
|||
fn wrapping_from_str_radix() {
|
||||
test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_num_ops() {
|
||||
fn compute<T: Num + Copy>(x: T, y: T) -> T {
|
||||
x * y / y % y + y - y
|
||||
}
|
||||
assert_eq!(compute(1, 2), 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_numref_ops() {
|
||||
fn compute<T: NumRef>(x: T, y: &T) -> T {
|
||||
x * y / y % y + y - y
|
||||
}
|
||||
assert_eq!(compute(1, &2), 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_refnum_ops() {
|
||||
fn compute<T: Copy>(x: &T, y: T) -> T
|
||||
where for<'a> &'a T: RefNum<T>
|
||||
{
|
||||
&(&(&(&(x * y) / y) % y) + y) - y
|
||||
}
|
||||
assert_eq!(compute(&1, 2), 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_refref_ops() {
|
||||
fn compute<T>(x: &T, y: &T) -> T
|
||||
where for<'a> &'a T: RefNum<T>
|
||||
{
|
||||
&(&(&(&(x * y) / y) % y) + y) - y
|
||||
}
|
||||
assert_eq!(compute(&1, &2), 1)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn check_numassign_ops() {
|
||||
fn compute<T: NumAssign + Copy>(mut x: T, y: T) -> T {
|
||||
x *= y;
|
||||
x /= y;
|
||||
x %= y;
|
||||
x += y;
|
||||
x -= y;
|
||||
x
|
||||
}
|
||||
assert_eq!(compute(1, 2), 1)
|
||||
}
|
||||
|
||||
// TODO test `NumAssignRef`, but even the standard numeric types don't
|
||||
// implement this yet. (see rust pr41336)
|
||||
|
|
Loading…
Reference in New Issue