defuse_num_utils/
mul_div.rs1use core::ops::Mul;
2
3use bnum::{BInt, BUint, cast::As};
4
5pub trait CheckedMulDiv<RHS = Self>: Sized {
6 fn checked_mul_div(self, mul: RHS, div: RHS) -> Option<Self>;
7 fn checked_mul_div_ceil(self, mul: RHS, div: RHS) -> Option<Self>;
8 fn checked_mul_div_euclid(self, mul: RHS, div: RHS) -> Option<Self>;
9}
10
11macro_rules! impl_checked_mul_div {
12 ($t:ty as $h:ty) => {
13 impl CheckedMulDiv for $t {
14 #[inline]
15 fn checked_mul_div(self, mul: Self, div: Self) -> Option<Self> {
16 self.as_::<$h>()
17 .mul(mul.as_::<$h>())
18 .checked_div(div.as_::<$h>())?
19 .try_into()
20 .ok()
21 }
22
23 #[inline]
24 fn checked_mul_div_ceil(self, mul: Self, div: Self) -> Option<Self> {
25 if div == 0 {
26 return None;
27 }
28 self.as_::<$h>()
29 .mul(mul.as_::<$h>())
30 .div_ceil(div.as_::<$h>())
31 .try_into()
32 .ok()
33 }
34
35 #[inline]
36 fn checked_mul_div_euclid(self, mul: Self, div: Self) -> Option<Self> {
37 if div == 0 {
38 return None;
39 }
40 self.as_::<$h>()
41 .mul(mul.as_::<$h>())
42 .div_euclid(div.as_::<$h>())
43 .try_into()
44 .ok()
45 }
46 }
47 };
48}
49impl_checked_mul_div!(u8 as u16);
50impl_checked_mul_div!(u16 as u32);
51impl_checked_mul_div!(u32 as u64);
52impl_checked_mul_div!(u64 as u128);
53impl_checked_mul_div!(u128 as BUint<4>);
54
55impl_checked_mul_div!(i128 as BInt<4>);