1use crate::fixed::Fixed;
6
7pub struct DivExpression<L, R> {
12 pub numerator: L,
14 pub denominator: R,
16}
17
18#[derive(Clone, Copy)]
24pub struct MulExpression<L, R> {
25 pub lhs: L,
27 pub rhs: R,
29}
30
31impl<IL, const FL: usize, IR, const FR: usize> core::ops::Div<Fixed<IR, FR>> for Fixed<IL, FL> {
33 type Output = DivExpression<Fixed<IL, FL>, Fixed<IR, FR>>;
34
35 fn div(self, rhs: Fixed<IR, FR>) -> Self::Output {
36 DivExpression { numerator: self, denominator: rhs }
37 }
38}
39
40macro_rules! impl_div_by_int {
42 ($I_R:ty) => {
43 impl<IL, const FL: usize> core::ops::Div<$I_R> for Fixed<IL, FL> {
44 type Output = DivExpression<Fixed<IL, FL>, Fixed<$I_R, 0>>;
45
46 fn div(self, rhs: $I_R) -> Self::Output {
47 DivExpression { numerator: self, denominator: Fixed::from_raw(rhs) }
48 }
49 }
50 };
51}
52
53impl_div_by_int!(i8);
54impl_div_by_int!(i16);
55impl_div_by_int!(i32);
56impl_div_by_int!(i64);
57impl_div_by_int!(u8);
58impl_div_by_int!(u16);
59impl_div_by_int!(u32);
60impl_div_by_int!(u64);
61
62impl<I, const TARGET_FRAC: usize, IL, const FL: usize, IR, const FR: usize>
64 From<DivExpression<Fixed<IL, FL>, Fixed<IR, FR>>> for Fixed<I, TARGET_FRAC>
65where
66 I: crate::num_traits::Bounded + TryFrom<i128> + Copy,
67 IL: Into<i128> + Copy,
68 IR: Into<i128> + Copy,
69{
70 fn from(expr: DivExpression<Fixed<IL, FL>, Fixed<IR, FR>>) -> Self {
71 let num_raw: i128 = expr.numerator.raw_value().into();
72 let denom_raw: i128 = expr.denominator.raw_value().into();
73
74 let src_frac = FL;
75 let dst_frac = TARGET_FRAC + FR;
76
77 let num_scaled = if src_frac > dst_frac {
78 let delta = src_frac - dst_frac;
79 let rounded = crate::utility::round_half_to_even::<i128>(num_raw, delta);
80 if let Some(power) = 1i128.checked_shl(delta as u32) { rounded / power } else { 0 }
81 } else if src_frac < dst_frac {
82 let delta = dst_frac - src_frac;
83 crate::utility::saturating_shl_i128(num_raw, delta)
87 } else {
88 num_raw
89 };
90
91 if denom_raw == 0 {
92 panic!("Division by zero in DivExpression");
93 }
94
95 let quotient = num_scaled.checked_div(denom_raw).unwrap_or(i128::MAX);
96
97 let val: I = crate::utility::clamp_cast(quotient);
98 Self::from_raw(val)
99 }
100}
101
102pub fn from_ratio<IL: Copy, IR: Copy>(
104 numerator: IL,
105 denominator: IR,
106) -> DivExpression<Fixed<IL, 0>, Fixed<IR, 0>> {
107 DivExpression {
108 numerator: Fixed::from_raw(numerator),
109 denominator: Fixed::from_raw(denominator),
110 }
111}
112
113pub fn to_resolution<const TARGET_FRAC: usize, I, L, R>(
115 expr: DivExpression<L, R>,
116) -> Fixed<I, TARGET_FRAC>
117where
118 Fixed<I, TARGET_FRAC>: From<DivExpression<L, R>>,
119{
120 Fixed::from(expr)
121}