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