defuse_num_utils/
lib.rs

1use core::ops::Mul;
2
3use bnum::{BInt, BUint, cast::As};
4
5pub trait CheckedAdd<RHS = Self>: Sized {
6    fn checked_add(self, rhs: RHS) -> Option<Self>;
7}
8
9pub trait CheckedSub<RHS = Self>: Sized {
10    fn checked_sub(self, rhs: RHS) -> Option<Self>;
11}
12
13macro_rules! impl_checked_add {
14    ($unsigned:ty, $signed:ty) => {
15        impl CheckedAdd for $unsigned {
16            #[inline]
17            fn checked_add(self, rhs: Self) -> Option<Self> {
18                self.checked_add(rhs)
19            }
20        }
21
22        impl CheckedAdd<$signed> for $unsigned {
23            #[inline]
24            fn checked_add(self, rhs: $signed) -> Option<Self> {
25                self.checked_add_signed(rhs)
26            }
27        }
28
29        impl CheckedAdd for $signed {
30            #[inline]
31            fn checked_add(self, rhs: Self) -> Option<Self> {
32                self.checked_add(rhs)
33            }
34        }
35
36        impl CheckedAdd<$unsigned> for $signed {
37            #[inline]
38            fn checked_add(self, rhs: $unsigned) -> Option<Self> {
39                self.checked_add_unsigned(rhs)
40            }
41        }
42    };
43}
44
45macro_rules! impl_checked_sub {
46    ($unsigned:ty, $signed:ty) => {
47        impl CheckedSub for $unsigned {
48            #[inline]
49            fn checked_sub(self, rhs: Self) -> Option<Self> {
50                self.checked_sub(rhs)
51            }
52        }
53
54        impl CheckedSub for $signed {
55            #[inline]
56            fn checked_sub(self, rhs: Self) -> Option<Self> {
57                self.checked_sub(rhs)
58            }
59        }
60
61        impl CheckedSub<$unsigned> for $signed {
62            #[inline]
63            fn checked_sub(self, rhs: $unsigned) -> Option<Self> {
64                self.checked_sub_unsigned(rhs)
65            }
66        }
67    };
68}
69macro_rules! impl_checked_add_sub {
70    ($unsigned:ty, $signed:ty) => {
71        impl_checked_add!($unsigned, $signed);
72        impl_checked_sub!($unsigned, $signed);
73    };
74}
75impl_checked_add_sub!(u8, i8);
76impl_checked_add_sub!(u16, i16);
77impl_checked_add_sub!(u32, i32);
78impl_checked_add_sub!(u64, i64);
79impl_checked_add_sub!(u128, i128);
80
81pub trait CheckedMulDiv<RHS = Self>: Sized {
82    fn checked_mul_div(self, mul: RHS, div: RHS) -> Option<Self>;
83    fn checked_mul_div_ceil(self, mul: RHS, div: RHS) -> Option<Self>;
84    fn checked_mul_div_euclid(self, mul: RHS, div: RHS) -> Option<Self>;
85}
86
87macro_rules! impl_checked_mul_div_unsigned {
88    ($t:ty as $h:ty) => {
89        impl CheckedMulDiv for $t {
90            #[inline]
91            fn checked_mul_div(self, mul: Self, div: Self) -> Option<Self> {
92                self.as_::<$h>()
93                    .mul(mul.as_::<$h>())
94                    .checked_div(div.as_::<$h>())?
95                    .try_into()
96                    .ok()
97            }
98
99            #[inline]
100            fn checked_mul_div_ceil(self, mul: Self, div: Self) -> Option<Self> {
101                if div == 0 {
102                    return None;
103                }
104                self.as_::<$h>()
105                    .mul(mul.as_::<$h>())
106                    .div_ceil(div.as_::<$h>())
107                    .try_into()
108                    .ok()
109            }
110
111            #[inline]
112            fn checked_mul_div_euclid(self, mul: Self, div: Self) -> Option<Self> {
113                if div == 0 {
114                    return None;
115                }
116                self.as_::<$h>()
117                    .mul(mul.as_::<$h>())
118                    .div_euclid(div.as_::<$h>())
119                    .try_into()
120                    .ok()
121            }
122        }
123    };
124}
125impl_checked_mul_div_unsigned!(u8 as u16);
126impl_checked_mul_div_unsigned!(u16 as u32);
127impl_checked_mul_div_unsigned!(u32 as u64);
128impl_checked_mul_div_unsigned!(u64 as u128);
129impl_checked_mul_div_unsigned!(u128 as BUint<4>);
130
131macro_rules! impl_checked_mul_div_signed {
132    ($t:ty as $h:ty) => {
133        impl CheckedMulDiv for $t {
134            #[inline]
135            fn checked_mul_div(self, mul: Self, div: Self) -> Option<Self> {
136                self.as_::<$h>()
137                    .mul(mul.as_::<$h>())
138                    .checked_div(div.as_::<$h>())?
139                    .try_into()
140                    .ok()
141            }
142
143            #[inline]
144            fn checked_mul_div_ceil(self, mul: Self, div: Self) -> Option<Self> {
145                if div == 0 {
146                    return None;
147                }
148                self.as_::<$h>()
149                    .mul(mul.as_::<$h>())
150                    .div_ceil(div.as_::<$h>())
151                    .try_into()
152                    .ok()
153            }
154
155            #[inline]
156            fn checked_mul_div_euclid(self, mul: Self, div: Self) -> Option<Self> {
157                if div == 0 {
158                    return None;
159                }
160                self.as_::<$h>()
161                    .mul(mul.as_::<$h>())
162                    .div_euclid(div.as_::<$h>())
163                    .try_into()
164                    .ok()
165            }
166        }
167    };
168}
169
170// #![feature(int_roundings)]
171// const _: () = {
172//     impl_checked_mul_div_signed!(i8 as i16);
173//     impl_checked_mul_div_signed!(i16 as i32);
174//     impl_checked_mul_div_signed!(i32 as i64);
175//     impl_checked_mul_div_signed!(i64 as i128);
176// };
177impl_checked_mul_div_signed!(i128 as BInt<4>);