Skip to content

Commit f9d36e6

Browse files
committed
Auto merge of #283 - cuviper:more-num, r=cuviper
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](#94 (comment)).
2 parents ef08fe2 + 3ead4a1 commit f9d36e6

File tree

1 file changed

+122
-4
lines changed

1 file changed

+122
-4
lines changed

traits/src/lib.rs

Lines changed: 122 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
html_playground_url = "http://play.integer32.com/")]
1616

1717
use std::ops::{Add, Sub, Mul, Div, Rem};
18+
use std::ops::{AddAssign, SubAssign, MulAssign, DivAssign, RemAssign};
1819
use std::num::Wrapping;
1920

2021
pub use bounds::Bounded;
@@ -37,10 +38,9 @@ pub mod cast;
3738
pub mod int;
3839
pub mod pow;
3940

40-
/// The base trait for numeric types
41-
pub trait Num: PartialEq + Zero + One
42-
+ Add<Output = Self> + Sub<Output = Self>
43-
+ Mul<Output = Self> + Div<Output = Self> + Rem<Output = Self>
41+
/// The base trait for numeric types, covering `0` and `1` values,
42+
/// comparisons, basic numeric operations, and string conversion.
43+
pub trait Num: PartialEq + Zero + One + NumOps
4444
{
4545
type FromStrRadixErr;
4646

@@ -60,6 +60,72 @@ pub trait Num: PartialEq + Zero + One
6060
fn from_str_radix(str: &str, radix: u32) -> Result<Self, Self::FromStrRadixErr>;
6161
}
6262

63+
/// The trait for types implementing basic numeric operations
64+
///
65+
/// This is automatically implemented for types which implement the operators.
66+
pub trait NumOps<Rhs = Self, Output = Self>
67+
: Add<Rhs, Output = Output>
68+
+ Sub<Rhs, Output = Output>
69+
+ Mul<Rhs, Output = Output>
70+
+ Div<Rhs, Output = Output>
71+
+ Rem<Rhs, Output = Output>
72+
{}
73+
74+
impl<T, Rhs, Output> NumOps<Rhs, Output> for T
75+
where T: Add<Rhs, Output = Output>
76+
+ Sub<Rhs, Output = Output>
77+
+ Mul<Rhs, Output = Output>
78+
+ Div<Rhs, Output = Output>
79+
+ Rem<Rhs, Output = Output>
80+
{}
81+
82+
/// The trait for `Num` types which also implement numeric operations taking
83+
/// the second operand by reference.
84+
///
85+
/// This is automatically implemented for types which implement the operators.
86+
pub trait NumRef: Num + for<'r> NumOps<&'r Self> {}
87+
impl<T> NumRef for T where T: Num + for<'r> NumOps<&'r T> {}
88+
89+
/// The trait for references which implement numeric operations, taking the
90+
/// second operand either by value or by reference.
91+
///
92+
/// This is automatically implemented for types which implement the operators.
93+
pub trait RefNum<Base>: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
94+
impl<T, Base> RefNum<Base> for T where T: NumOps<Base, Base> + for<'r> NumOps<&'r Base, Base> {}
95+
96+
/// The trait for types implementing numeric assignment operators (like `+=`).
97+
///
98+
/// This is automatically implemented for types which implement the operators.
99+
pub trait NumAssignOps<Rhs = Self>
100+
: AddAssign<Rhs>
101+
+ SubAssign<Rhs>
102+
+ MulAssign<Rhs>
103+
+ DivAssign<Rhs>
104+
+ RemAssign<Rhs>
105+
{}
106+
107+
impl<T, Rhs> NumAssignOps<Rhs> for T
108+
where T: AddAssign<Rhs>
109+
+ SubAssign<Rhs>
110+
+ MulAssign<Rhs>
111+
+ DivAssign<Rhs>
112+
+ RemAssign<Rhs>
113+
{}
114+
115+
/// The trait for `Num` types which also implement assignment operators.
116+
///
117+
/// This is automatically implemented for types which implement the operators.
118+
pub trait NumAssign: Num + NumAssignOps {}
119+
impl<T> NumAssign for T where T: Num + NumAssignOps {}
120+
121+
/// The trait for `NumAssign` types which also implement assignment operations
122+
/// taking the second operand by reference.
123+
///
124+
/// This is automatically implemented for types which implement the operators.
125+
pub trait NumAssignRef: NumAssign + for<'r> NumAssignOps<&'r Self> {}
126+
impl<T> NumAssignRef for T where T: NumAssign + for<'r> NumAssignOps<&'r T> {}
127+
128+
63129
macro_rules! int_trait_impl {
64130
($name:ident for $($t:ty)*) => ($(
65131
impl $name for $t {
@@ -315,3 +381,55 @@ fn wrapping_is_num() {
315381
fn wrapping_from_str_radix() {
316382
test_wrapping_from_str_radix!(usize u8 u16 u32 u64 isize i8 i16 i32 i64);
317383
}
384+
385+
#[test]
386+
fn check_num_ops() {
387+
fn compute<T: Num + Copy>(x: T, y: T) -> T {
388+
x * y / y % y + y - y
389+
}
390+
assert_eq!(compute(1, 2), 1)
391+
}
392+
393+
#[test]
394+
fn check_numref_ops() {
395+
fn compute<T: NumRef>(x: T, y: &T) -> T {
396+
x * y / y % y + y - y
397+
}
398+
assert_eq!(compute(1, &2), 1)
399+
}
400+
401+
#[test]
402+
fn check_refnum_ops() {
403+
fn compute<T: Copy>(x: &T, y: T) -> T
404+
where for<'a> &'a T: RefNum<T>
405+
{
406+
&(&(&(&(x * y) / y) % y) + y) - y
407+
}
408+
assert_eq!(compute(&1, 2), 1)
409+
}
410+
411+
#[test]
412+
fn check_refref_ops() {
413+
fn compute<T>(x: &T, y: &T) -> T
414+
where for<'a> &'a T: RefNum<T>
415+
{
416+
&(&(&(&(x * y) / y) % y) + y) - y
417+
}
418+
assert_eq!(compute(&1, &2), 1)
419+
}
420+
421+
#[test]
422+
fn check_numassign_ops() {
423+
fn compute<T: NumAssign + Copy>(mut x: T, y: T) -> T {
424+
x *= y;
425+
x /= y;
426+
x %= y;
427+
x += y;
428+
x -= y;
429+
x
430+
}
431+
assert_eq!(compute(1, 2), 1)
432+
}
433+
434+
// TODO test `NumAssignRef`, but even the standard numeric types don't
435+
// implement this yet. (see rust pr41336)

0 commit comments

Comments
 (0)