fixed_bigint/fixeduint/
add_sub_impl.rs

1use super::{maybe_panic, FixedUInt, MachineWord, PanicReason};
2
3use num_traits::ops::overflowing::{OverflowingAdd, OverflowingSub};
4
5impl<T: MachineWord, const N: usize> num_traits::ops::overflowing::OverflowingAdd
6    for FixedUInt<T, N>
7{
8    fn overflowing_add(&self, other: &Self) -> (Self, bool) {
9        let mut ret = *self;
10        let overflow = Self::add_impl(&mut ret, other);
11        (ret, overflow)
12    }
13}
14
15impl<T: MachineWord, const N: usize> core::ops::Add for FixedUInt<T, N> {
16    type Output = Self;
17    fn add(self, other: Self) -> Self {
18        let (res, overflow) = self.overflowing_add(&other);
19        if overflow {
20            maybe_panic(PanicReason::Add);
21        }
22        res
23    }
24}
25
26impl<T: MachineWord, const N: usize> core::ops::Add<&'_ Self> for FixedUInt<T, N> {
27    type Output = Self;
28    fn add(self, other: &Self) -> Self {
29        let (res, overflow) = self.overflowing_add(other);
30        if overflow {
31            maybe_panic(PanicReason::Add);
32        }
33        res
34    }
35}
36
37impl<T: MachineWord, const N: usize> core::ops::Add<FixedUInt<T, N>> for &FixedUInt<T, N> {
38    type Output = FixedUInt<T, N>;
39    fn add(self, other: FixedUInt<T, N>) -> Self::Output {
40        let (res, overflow) = self.overflowing_add(&other);
41        if overflow {
42            maybe_panic(PanicReason::Add);
43        }
44        res
45    }
46}
47
48impl<T: MachineWord, const N: usize> core::ops::Add<Self> for &FixedUInt<T, N> {
49    type Output = FixedUInt<T, N>;
50    fn add(self, other: Self) -> Self::Output {
51        let (res, overflow) = self.overflowing_add(other);
52        if overflow {
53            maybe_panic(PanicReason::Add);
54        }
55        res
56    }
57}
58
59impl<T: MachineWord, const N: usize> num_traits::WrappingAdd for FixedUInt<T, N> {
60    fn wrapping_add(&self, other: &Self) -> Self {
61        self.overflowing_add(other).0
62    }
63}
64
65impl<T: MachineWord, const N: usize> num_traits::CheckedAdd for FixedUInt<T, N> {
66    fn checked_add(&self, other: &Self) -> Option<Self> {
67        let res = self.overflowing_add(other);
68        if res.1 {
69            None
70        } else {
71            Some(res.0)
72        }
73    }
74}
75
76impl<T: MachineWord, const N: usize> num_traits::ops::saturating::SaturatingAdd
77    for FixedUInt<T, N>
78{
79    /// Saturating addition operator. Returns a+b, saturating at the numeric bounds instead of overflowing.
80    fn saturating_add(&self, other: &Self) -> Self {
81        self.saturating_add_impl(other)
82    }
83}
84
85impl<T: MachineWord, const N: usize> core::ops::AddAssign<Self> for FixedUInt<T, N> {
86    fn add_assign(&mut self, other: Self) {
87        if Self::add_impl(self, &other) {
88            maybe_panic(PanicReason::Add);
89        }
90    }
91}
92
93impl<T: MachineWord, const N: usize> core::ops::AddAssign<&'_ Self> for FixedUInt<T, N> {
94    fn add_assign(&mut self, other: &Self) {
95        if Self::add_impl(self, other) {
96            maybe_panic(PanicReason::Add);
97        }
98    }
99}
100
101impl<T: MachineWord, const N: usize> num_traits::ops::overflowing::OverflowingSub
102    for FixedUInt<T, N>
103{
104    fn overflowing_sub(&self, other: &Self) -> (Self, bool) {
105        let mut ret = *self;
106        let overflow = Self::sub_impl(&mut ret, other);
107        (ret, overflow)
108    }
109}
110
111impl<T: MachineWord, const N: usize> core::ops::Sub for FixedUInt<T, N> {
112    type Output = Self;
113    fn sub(self, other: Self) -> <Self as core::ops::Sub<Self>>::Output {
114        let (res, overflow) = self.overflowing_sub(&other);
115        if overflow {
116            maybe_panic(PanicReason::Sub);
117        }
118        res
119    }
120}
121
122impl<T: MachineWord, const N: usize> core::ops::Sub<&'_ Self> for FixedUInt<T, N> {
123    type Output = Self;
124    fn sub(self, other: &Self) -> Self {
125        let (res, overflow) = self.overflowing_sub(other);
126        if overflow {
127            maybe_panic(PanicReason::Sub);
128        }
129        res
130    }
131}
132
133impl<T: MachineWord, const N: usize> core::ops::Sub<FixedUInt<T, N>> for &FixedUInt<T, N> {
134    type Output = FixedUInt<T, N>;
135    fn sub(self, other: FixedUInt<T, N>) -> Self::Output {
136        let (res, overflow) = self.overflowing_sub(&other);
137        if overflow {
138            maybe_panic(PanicReason::Sub);
139        }
140        res
141    }
142}
143
144impl<T: MachineWord, const N: usize> core::ops::Sub<Self> for &FixedUInt<T, N> {
145    type Output = FixedUInt<T, N>;
146    fn sub(self, other: Self) -> Self::Output {
147        let (res, overflow) = self.overflowing_sub(other);
148        if overflow {
149            maybe_panic(PanicReason::Sub);
150        }
151        res
152    }
153}
154
155impl<T: MachineWord, const N: usize> num_traits::WrappingSub for FixedUInt<T, N> {
156    fn wrapping_sub(&self, other: &Self) -> Self {
157        self.overflowing_sub(other).0
158    }
159}
160
161impl<T: MachineWord, const N: usize> num_traits::CheckedSub for FixedUInt<T, N> {
162    fn checked_sub(&self, other: &Self) -> Option<Self> {
163        let res = self.overflowing_sub(other);
164        if res.1 {
165            None
166        } else {
167            Some(res.0)
168        }
169    }
170}
171
172impl<T: MachineWord, const N: usize> num_traits::ops::saturating::SaturatingSub
173    for FixedUInt<T, N>
174{
175    /// Saturating subtraction operator. Returns a-b, saturating at the numeric bounds instead of overflowing.
176    fn saturating_sub(&self, other: &Self) -> Self {
177        self.saturating_sub_impl(other)
178    }
179}
180
181impl<T: MachineWord, const N: usize> core::ops::SubAssign<Self> for FixedUInt<T, N> {
182    fn sub_assign(&mut self, other: Self) {
183        if Self::sub_impl(self, &other) {
184            maybe_panic(PanicReason::Sub);
185        }
186    }
187}
188
189impl<T: MachineWord, const N: usize> core::ops::SubAssign<&'_ Self> for FixedUInt<T, N> {
190    fn sub_assign(&mut self, other: &Self) {
191        if Self::sub_impl(self, other) {
192            maybe_panic(PanicReason::Sub);
193        }
194    }
195}
196
197/// Note: This is marked deprecated, but still used by PrimInt
198impl<T: MachineWord, const N: usize> num_traits::Saturating for FixedUInt<T, N> {
199    /// Saturating addition operator. Returns a+b, saturating at the numeric bounds instead of overflowing.
200    fn saturating_add(self, other: Self) -> Self {
201        self.saturating_add_impl(&other)
202    }
203
204    /// Saturating subtraction operator. Returns a-b, saturating at the numeric bounds instead of overflowing.
205    fn saturating_sub(self, other: Self) -> Self {
206        self.saturating_sub_impl(&other)
207    }
208}
209
210#[cfg(test)]
211mod tests {
212    use super::*;
213
214    #[test]
215    fn test_add_combinations() {
216        let a = FixedUInt::<u8, 2>::from(12u8);
217        let b = FixedUInt::<u8, 2>::from(3u8);
218        let expected = FixedUInt::<u8, 2>::from(15u8);
219
220        // value + value
221        assert_eq!(a + b, expected);
222        // value + ref
223        assert_eq!(a + &b, expected);
224        // ref + value
225        assert_eq!(&a + b, expected);
226        // ref + ref
227        assert_eq!(&a + &b, expected);
228    }
229
230    #[test]
231    fn test_sub_combinations() {
232        let a = FixedUInt::<u8, 2>::from(15u8);
233        let b = FixedUInt::<u8, 2>::from(3u8);
234        let expected = FixedUInt::<u8, 2>::from(12u8);
235
236        // value - value
237        assert_eq!(a - b, expected);
238        // value - ref
239        assert_eq!(a - &b, expected);
240        // ref - value
241        assert_eq!(&a - b, expected);
242        // ref - ref
243        assert_eq!(&a - &b, expected);
244    }
245}