1macro_rules! number_trait {
6 ($name:ident, $method:ident, $output:ty, $test:stmt) => {
7 number_trait!($name, $method, $output, $test, [
8 u8, i8, u16, i16, u32, i32, u64, i64, usize, isize, u128, i128
9 ]);
10 };
11 ($name:ident, $method:ident, $output:ty, $test:stmt, [$($ty:ident),*]) => {
12 pub trait $name<Rhs = Self>: Sized {
13 type Output;
14 fn $method(self, rhs: Rhs) -> $output;
15 }
16
17 $(
18 impl<Rhs> $name<Rhs> for $ty
19 where $ty: UpcastFrom<Rhs>
20 {
21 type Output = Self;
22
23 fn $method(self, rhs: Rhs) -> $output {
24 $ty::$method(self, rhs.upcast())
25 }
26 }
27 )*
28
29 #[test]
30 fn $method() {
31 $({
32 type Type = $ty;
33 $test
34 })*
35 }
36 };
37}
38
39macro_rules! assign_trait {
41 ($name:ident, $method:ident, $delegate:expr, $output:ty) => {
42 assign_trait!($name, $method, $delegate, $output, [
43 u8, i8, u16, i16, u32, i32, u64, i64, usize, isize, u128, i128
44 ]);
45 };
46 ($name:ident, $method:ident, $delegate:expr, $output:ty, [$($ty:ident),*]) => {
47 pub trait $name<Rhs = Self> {
48 fn $method(&mut self, rhs: Rhs) -> $output;
49 }
50
51 $(
52 impl<Rhs> $name<Rhs> for $ty
53 where $ty: UpcastFrom<Rhs>
54 {
55 fn $method(&mut self, rhs: Rhs) -> $output {
56 let f: fn(&mut $ty, Rhs) -> $output = $delegate;
57 f(self, rhs)
58 }
59 }
60 )*
61 };
62}
63
64number_trait!(
65 CheckedAdd,
66 checked_add,
67 Option<Self::Output>,
68 assert!(Type::MAX.checked_add(Type::MAX).is_none())
69);
70
71number_trait!(
72 CheckedSub,
73 checked_sub,
74 Option<Self::Output>,
75 assert!(Type::MIN.checked_sub(Type::MAX).is_none())
76);
77
78number_trait!(
79 CheckedMul,
80 checked_mul,
81 Option<Self::Output>,
82 assert!(Type::MAX.checked_mul(Type::MAX).is_none())
83);
84
85number_trait!(
86 CheckedDiv,
87 checked_div,
88 Option<Self::Output>,
89 assert!(Type::MAX.checked_div(0).is_none())
90);
91
92assign_trait!(
93 CheckedAddAssign,
94 checked_add_assign,
95 |value, rhs| {
96 *value = CheckedAdd::checked_add(*value, rhs)?;
97 Some(())
98 },
99 Option<()>
100);
101
102assign_trait!(
103 CheckedSubAssign,
104 checked_sub_assign,
105 |value, rhs| {
106 *value = CheckedSub::checked_sub(*value, rhs)?;
107 Some(())
108 },
109 Option<()>
110);
111
112assign_trait!(
113 CheckedMulAssign,
114 checked_mul_assign,
115 |value, rhs| {
116 *value = CheckedMul::checked_mul(*value, rhs)?;
117 Some(())
118 },
119 Option<()>
120);
121
122number_trait!(
123 SaturatingAdd,
124 saturating_add,
125 Self::Output,
126 assert_eq!(Type::MAX.saturating_add(Type::MAX), Type::MAX)
127);
128
129number_trait!(
130 SaturatingSub,
131 saturating_sub,
132 Self::Output,
133 assert_eq!(Type::MIN.saturating_sub(Type::MAX), Type::MIN)
134);
135
136number_trait!(
137 SaturatingMul,
138 saturating_mul,
139 Self::Output,
140 assert_eq!(Type::MAX.saturating_mul(Type::MAX), Type::MAX)
141);
142
143assign_trait!(
144 SaturatingAddAssign,
145 saturating_add_assign,
146 |value, rhs| {
147 *value = SaturatingAdd::saturating_add(*value, rhs);
148 },
149 ()
150);
151
152assign_trait!(
153 SaturatingSubAssign,
154 saturating_sub_assign,
155 |value, rhs| {
156 *value = SaturatingSub::saturating_sub(*value, rhs);
157 },
158 ()
159);
160
161assign_trait!(
162 SaturatingMulAssign,
163 saturating_mul_assign,
164 |value, rhs| {
165 *value = SaturatingMul::saturating_mul(*value, rhs);
166 },
167 ()
168);
169
170pub trait UpcastFrom<T> {
172 fn upcast_from(value: T) -> Self;
173}
174
175pub trait Upcast<T> {
177 fn upcast(self) -> T;
178}
179
180impl<T, U> Upcast<T> for U
182where
183 T: UpcastFrom<U>,
184{
185 fn upcast(self) -> T {
186 UpcastFrom::upcast_from(self)
187 }
188}
189
190macro_rules! upcast_impl {
191 ($($ty:ident),*) => {
192 upcast_impl!(@impl [], [$($ty),*]);
193 };
194 (@impl [$($prev:ident),*], []) => {
195 };
197 (@impl [$($prev:ident),*], [$current:ident $(, $rest:ident)*]) => {
198 impl UpcastFrom<$current> for $current {
199 fn upcast_from(value: Self) -> Self {
200 value
201 }
202 }
203
204 impl UpcastFrom<&$current> for $current {
205 fn upcast_from(value: &Self) -> Self {
206 *value
207 }
208 }
209
210 $(
211 impl UpcastFrom<$prev> for $current {
212 fn upcast_from(value: $prev) -> Self {
213 value as $current
214 }
215 }
216
217 impl UpcastFrom<&$prev> for $current {
218 fn upcast_from(value: &$prev) -> Self {
219 (*value) as $current
220 }
221 }
222 )*
223
224 upcast_impl!(@impl [$current $(, $prev)*], [$($rest),*]);
225 };
226}
227
228upcast_impl!(u8, u16, u32, u64, u128);
229upcast_impl!(i8, i16, i32, i64, i128);
230
231macro_rules! upcast_usize {
232 ($target_width:literal, $unsigned:ident, $signed:ident) => {
233 #[cfg(target_pointer_width = $target_width)]
234 impl<Rhs> UpcastFrom<Rhs> for usize
235 where
236 $unsigned: UpcastFrom<Rhs>,
237 {
238 fn upcast_from(value: Rhs) -> Self {
239 $unsigned::upcast_from(value) as usize
240 }
241 }
242
243 #[cfg(target_pointer_width = $target_width)]
244 impl<Rhs> UpcastFrom<Rhs> for isize
245 where
246 $signed: UpcastFrom<Rhs>,
247 {
248 fn upcast_from(value: Rhs) -> Self {
249 $signed::upcast_from(value) as isize
250 }
251 }
252 };
253}
254
255upcast_usize!("8", u8, i8);
256upcast_usize!("16", u16, u16);
257upcast_usize!("32", u32, i32);
258upcast_usize!("64", u64, i64);
259upcast_usize!("128", u128, i128);