diff --git a/traits/src/lib.rs b/traits/src/lib.rs index 083fe41..f4dbee2 100644 --- a/traits/src/lib.rs +++ b/traits/src/lib.rs @@ -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 + Sub - + Mul + Div + Rem +/// 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; } +/// The trait for types implementing basic numeric operations +/// +/// This is automatically implemented for types which implement the operators. +pub trait NumOps + : Add + + Sub + + Mul + + Div + + Rem +{} + +impl NumOps for T +where T: Add + + Sub + + Mul + + Div + + Rem +{} + +/// 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 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: NumOps + for<'r> NumOps<&'r Base, Base> {} +impl<'a, T> RefNum for &'a T where &'a T: NumOps + 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 + : AddAssign + + SubAssign + + MulAssign + + DivAssign + + RemAssign +{} + +impl NumAssignOps for T +where T: AddAssign + + SubAssign + + MulAssign + + DivAssign + + RemAssign +{} + +/// 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 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 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(x: T, y: T) -> T { + x * y / y % y + y - y + } + assert_eq!(compute(1, 2), 1) +} + +#[test] +fn check_numref_ops() { + fn compute(x: T, y: &T) -> T { + x * y / y % y + y - y + } + assert_eq!(compute(1, &2), 1) +} + +#[test] +fn check_refnum_ops() { + fn compute(x: &T, y: T) -> T + where for<'a> &'a T: RefNum + { + &(&(&(&(x * y) / y) % y) + y) - y + } + assert_eq!(compute(&1, 2), 1) +} + +#[test] +fn check_refref_ops() { + fn compute(x: &T, y: &T) -> T + where for<'a> &'a T: RefNum + { + &(&(&(&(x * y) / y) % y) + y) - y + } + assert_eq!(compute(&1, &2), 1) +} + +#[test] +fn check_numassign_ops() { + fn compute(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)