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
170impl_checked_mul_div_signed!(i128 as BInt<4>);