s2n_quic_core/
number.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4/// Generates a generic number operation
5macro_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
39/// Generates a generic assign operation trait
40macro_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
170/// Losslessly upcasts from one type to another
171pub trait UpcastFrom<T> {
172    fn upcast_from(value: T) -> Self;
173}
174
175/// Losslessly upcasts one type into another
176pub trait Upcast<T> {
177    fn upcast(self) -> T;
178}
179
180/// Implement Upcast automatically for all types that implement UpcastFrom
181impl<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        // done!
196    };
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);