1use crate::{Checked, CheckedSub, Choice, CtOption, Int, Sub, SubAssign, Wrapping, WrappingSub};
4
5impl<const LIMBS: usize> Int<LIMBS> {
6 #[must_use]
9 pub const fn underflowing_sub(&self, rhs: &Self) -> (Self, Choice) {
10 let res = Self(self.0.wrapping_sub(&rhs.0));
12
13 let self_msb = self.is_negative();
20 let underflow = self_msb
21 .ne(rhs.is_negative())
22 .and(self_msb.ne(res.is_negative()));
23
24 (res, underflow)
26 }
27
28 #[must_use]
31 pub const fn wrapping_sub(&self, rhs: &Self) -> Self {
32 self.underflowing_sub(rhs).0
33 }
34}
35
36impl<const LIMBS: usize> CheckedSub for Int<LIMBS> {
37 fn checked_sub(&self, rhs: &Self) -> CtOption<Self> {
38 let (res, underflow) = Self::underflowing_sub(self, rhs);
39 CtOption::new(res, underflow.not())
40 }
41}
42
43impl<const LIMBS: usize> Sub for Int<LIMBS> {
44 type Output = Self;
45
46 fn sub(self, rhs: Self) -> Self {
47 self.sub(&rhs)
48 }
49}
50
51impl<const LIMBS: usize> Sub<&Int<LIMBS>> for Int<LIMBS> {
52 type Output = Self;
53
54 fn sub(self, rhs: &Self) -> Self {
55 self.checked_sub(rhs)
56 .expect("attempted to subtract with underflow")
57 }
58}
59
60impl<const LIMBS: usize> SubAssign<Int<LIMBS>> for Int<LIMBS> {
61 fn sub_assign(&mut self, rhs: Int<LIMBS>) {
62 *self = self.sub(&rhs);
63 }
64}
65
66impl<const LIMBS: usize> SubAssign<&Int<LIMBS>> for Int<LIMBS> {
67 fn sub_assign(&mut self, rhs: &Int<LIMBS>) {
68 *self = self.sub(rhs);
69 }
70}
71
72impl<const LIMBS: usize> SubAssign for Wrapping<Int<LIMBS>> {
73 fn sub_assign(&mut self, other: Self) {
74 *self = *self - other;
75 }
76}
77
78impl<const LIMBS: usize> SubAssign<&Wrapping<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
79 fn sub_assign(&mut self, other: &Self) {
80 *self = *self - other;
81 }
82}
83
84impl<const LIMBS: usize> SubAssign for Checked<Int<LIMBS>> {
85 fn sub_assign(&mut self, other: Self) {
86 *self = *self - other;
87 }
88}
89
90impl<const LIMBS: usize> SubAssign<&Checked<Int<LIMBS>>> for Checked<Int<LIMBS>> {
91 fn sub_assign(&mut self, other: &Self) {
92 *self = *self - other;
93 }
94}
95
96impl<const LIMBS: usize> WrappingSub for Int<LIMBS> {
97 fn wrapping_sub(&self, v: &Self) -> Self {
98 Self(self.0.wrapping_sub(&v.0))
99 }
100}
101
102#[cfg(test)]
103#[allow(clippy::init_numbered_fields)]
104mod tests {
105 use crate::{CheckedSub, I128, Int, U128};
106
107 #[test]
108 fn checked_sub() {
109 let min_plus_one = Int {
110 0: I128::MIN.0.wrapping_add(&I128::ONE.0),
111 };
112 let max_minus_one = Int {
113 0: I128::MAX.0.wrapping_sub(&I128::ONE.0),
114 };
115 let two = Int {
116 0: U128::from(2u32),
117 };
118 let min_plus_two = Int {
119 0: I128::MIN.0.wrapping_add(&two.0),
120 };
121
122 let result = I128::MIN.checked_sub(&I128::MIN);
125 assert_eq!(result.unwrap(), I128::ZERO);
126
127 let result = I128::MIN.checked_sub(&I128::MINUS_ONE);
128 assert_eq!(result.unwrap(), min_plus_one);
129
130 let result = I128::MIN.checked_sub(&I128::ZERO);
131 assert_eq!(result.unwrap(), I128::MIN);
132
133 let result = I128::MIN.checked_sub(&I128::ONE);
134 assert!(bool::from(result.is_none()));
135
136 let result = I128::MIN.checked_sub(&I128::MAX);
137 assert!(bool::from(result.is_none()));
138
139 let result = I128::MINUS_ONE.checked_sub(&I128::MIN);
142 assert_eq!(result.unwrap(), I128::MAX);
143
144 let result = I128::MINUS_ONE.checked_sub(&I128::MINUS_ONE);
145 assert_eq!(result.unwrap(), I128::ZERO);
146
147 let result = I128::MINUS_ONE.checked_sub(&I128::ZERO);
148 assert_eq!(result.unwrap(), I128::MINUS_ONE);
149
150 let result = I128::MINUS_ONE.checked_sub(&I128::ONE);
151 assert_eq!(result.unwrap(), two.wrapping_neg());
152
153 let result = I128::MINUS_ONE.checked_sub(&I128::MAX);
154 assert_eq!(result.unwrap(), I128::MIN);
155
156 let result = I128::ZERO.checked_sub(&I128::MIN);
159 assert!(bool::from(result.is_none()));
160
161 let result = I128::ZERO.checked_sub(&I128::MINUS_ONE);
162 assert_eq!(result.unwrap(), I128::ONE);
163
164 let result = I128::ZERO.checked_sub(&I128::ZERO);
165 assert_eq!(result.unwrap(), I128::ZERO);
166
167 let result = I128::ZERO.checked_sub(&I128::ONE);
168 assert_eq!(result.unwrap(), I128::MINUS_ONE);
169
170 let result = I128::ZERO.checked_sub(&I128::MAX);
171 assert_eq!(result.unwrap(), min_plus_one);
172
173 let result = I128::ONE.checked_sub(&I128::MIN);
176 assert!(bool::from(result.is_none()));
177
178 let result = I128::ONE.checked_sub(&I128::MINUS_ONE);
179 assert_eq!(result.unwrap(), two);
180
181 let result = I128::ONE.checked_sub(&I128::ZERO);
182 assert_eq!(result.unwrap(), I128::ONE);
183
184 let result = I128::ONE.checked_sub(&I128::ONE);
185 assert_eq!(result.unwrap(), I128::ZERO);
186
187 let result = I128::ONE.checked_sub(&I128::MAX);
188 assert_eq!(result.unwrap(), min_plus_two);
189
190 let result = I128::MAX.checked_sub(&I128::MIN);
193 assert!(bool::from(result.is_none()));
194
195 let result = I128::MAX.checked_sub(&I128::MINUS_ONE);
196 assert!(bool::from(result.is_none()));
197
198 let result = I128::MAX.checked_sub(&I128::ZERO);
199 assert_eq!(result.unwrap(), I128::MAX);
200
201 let result = I128::MAX.checked_sub(&I128::ONE);
202 assert_eq!(result.unwrap(), max_minus_one);
203
204 let result = I128::MAX.checked_sub(&I128::MAX);
205 assert_eq!(result.unwrap(), I128::ZERO);
206 }
207
208 #[test]
209 fn wrapping_sub() {
210 let min_plus_one = Int {
211 0: I128::MIN.0.wrapping_add(&I128::ONE.0),
212 };
213 let two = Int {
214 0: U128::from(2u32),
215 };
216 let max_minus_one = Int {
217 0: I128::MAX.0.wrapping_sub(&I128::ONE.0),
218 };
219
220 let result = I128::ONE.wrapping_sub(&I128::MIN);
222 assert_eq!(result, min_plus_one);
223
224 let result = I128::ZERO.wrapping_sub(&I128::MIN);
226 assert_eq!(result, I128::MIN);
227
228 let result = I128::MIN.wrapping_sub(&two);
230 assert_eq!(result, max_minus_one);
231 }
232}