1use core::ops::{Sub, SubAssign};
4
5use num_traits::WrappingSub;
6use subtle::{Choice, ConstantTimeEq, CtOption};
7
8use crate::{Checked, CheckedSub, Int, Wrapping};
9
10impl<const LIMBS: usize> CheckedSub for Int<LIMBS> {
11 fn checked_sub(&self, rhs: &Self) -> CtOption<Self> {
12 let res = Self(self.0.wrapping_sub(&rhs.0));
14
15 let self_msb: Choice = self.is_negative().into();
22 let underflow =
23 self_msb.ct_ne(&rhs.is_negative().into()) & self_msb.ct_ne(&res.is_negative().into());
24
25 CtOption::new(res, !underflow)
27 }
28}
29
30impl<const LIMBS: usize> Sub for Int<LIMBS> {
31 type Output = Self;
32
33 fn sub(self, rhs: Self) -> Self {
34 self.sub(&rhs)
35 }
36}
37
38impl<const LIMBS: usize> Sub<&Int<LIMBS>> for Int<LIMBS> {
39 type Output = Self;
40
41 fn sub(self, rhs: &Self) -> Self {
42 self.checked_sub(rhs)
43 .expect("attempted to subtract with underflow")
44 }
45}
46
47impl<const LIMBS: usize> SubAssign for Wrapping<Int<LIMBS>> {
48 fn sub_assign(&mut self, other: Self) {
49 *self = *self - other;
50 }
51}
52
53impl<const LIMBS: usize> SubAssign<&Wrapping<Int<LIMBS>>> for Wrapping<Int<LIMBS>> {
54 fn sub_assign(&mut self, other: &Self) {
55 *self = *self - other;
56 }
57}
58
59impl<const LIMBS: usize> SubAssign for Checked<Int<LIMBS>> {
60 fn sub_assign(&mut self, other: Self) {
61 *self = *self - other;
62 }
63}
64
65impl<const LIMBS: usize> SubAssign<&Checked<Int<LIMBS>>> for Checked<Int<LIMBS>> {
66 fn sub_assign(&mut self, other: &Self) {
67 *self = *self - other;
68 }
69}
70
71impl<const LIMBS: usize> WrappingSub for Int<LIMBS> {
72 fn wrapping_sub(&self, v: &Self) -> Self {
73 Self(self.0.wrapping_sub(&v.0))
74 }
75}
76
77#[cfg(test)]
78mod tests {
79
80 #[cfg(test)]
81 mod tests {
82 use num_traits::WrappingSub;
83
84 use crate::{CheckedSub, Int, I128, U128};
85
86 #[test]
87 fn checked_sub() {
88 let min_plus_one = Int {
89 0: I128::MIN.0.wrapping_add(&I128::ONE.0),
90 };
91 let max_minus_one = Int {
92 0: I128::MAX.0.wrapping_sub(&I128::ONE.0),
93 };
94 let two = Int {
95 0: U128::from(2u32),
96 };
97 let min_plus_two = Int {
98 0: I128::MIN.0.wrapping_add(&two.0),
99 };
100
101 let result = I128::MIN.checked_sub(&I128::MIN);
104 assert_eq!(result.unwrap(), I128::ZERO);
105
106 let result = I128::MIN.checked_sub(&I128::MINUS_ONE);
107 assert_eq!(result.unwrap(), min_plus_one);
108
109 let result = I128::MIN.checked_sub(&I128::ZERO);
110 assert_eq!(result.unwrap(), I128::MIN);
111
112 let result = I128::MIN.checked_sub(&I128::ONE);
113 assert!(bool::from(result.is_none()));
114
115 let result = I128::MIN.checked_sub(&I128::MAX);
116 assert!(bool::from(result.is_none()));
117
118 let result = I128::MINUS_ONE.checked_sub(&I128::MIN);
121 assert_eq!(result.unwrap(), I128::MAX);
122
123 let result = I128::MINUS_ONE.checked_sub(&I128::MINUS_ONE);
124 assert_eq!(result.unwrap(), I128::ZERO);
125
126 let result = I128::MINUS_ONE.checked_sub(&I128::ZERO);
127 assert_eq!(result.unwrap(), I128::MINUS_ONE);
128
129 let result = I128::MINUS_ONE.checked_sub(&I128::ONE);
130 assert_eq!(result.unwrap(), two.wrapping_neg());
131
132 let result = I128::MINUS_ONE.checked_sub(&I128::MAX);
133 assert_eq!(result.unwrap(), I128::MIN);
134
135 let result = I128::ZERO.checked_sub(&I128::MIN);
138 assert!(bool::from(result.is_none()));
139
140 let result = I128::ZERO.checked_sub(&I128::MINUS_ONE);
141 assert_eq!(result.unwrap(), I128::ONE);
142
143 let result = I128::ZERO.checked_sub(&I128::ZERO);
144 assert_eq!(result.unwrap(), I128::ZERO);
145
146 let result = I128::ZERO.checked_sub(&I128::ONE);
147 assert_eq!(result.unwrap(), I128::MINUS_ONE);
148
149 let result = I128::ZERO.checked_sub(&I128::MAX);
150 assert_eq!(result.unwrap(), min_plus_one);
151
152 let result = I128::ONE.checked_sub(&I128::MIN);
155 assert!(bool::from(result.is_none()));
156
157 let result = I128::ONE.checked_sub(&I128::MINUS_ONE);
158 assert_eq!(result.unwrap(), two);
159
160 let result = I128::ONE.checked_sub(&I128::ZERO);
161 assert_eq!(result.unwrap(), I128::ONE);
162
163 let result = I128::ONE.checked_sub(&I128::ONE);
164 assert_eq!(result.unwrap(), I128::ZERO);
165
166 let result = I128::ONE.checked_sub(&I128::MAX);
167 assert_eq!(result.unwrap(), min_plus_two);
168
169 let result = I128::MAX.checked_sub(&I128::MIN);
172 assert!(bool::from(result.is_none()));
173
174 let result = I128::MAX.checked_sub(&I128::MINUS_ONE);
175 assert!(bool::from(result.is_none()));
176
177 let result = I128::MAX.checked_sub(&I128::ZERO);
178 assert_eq!(result.unwrap(), I128::MAX);
179
180 let result = I128::MAX.checked_sub(&I128::ONE);
181 assert_eq!(result.unwrap(), max_minus_one);
182
183 let result = I128::MAX.checked_sub(&I128::MAX);
184 assert_eq!(result.unwrap(), I128::ZERO);
185 }
186
187 #[test]
188 fn wrapping_sub() {
189 let min_plus_one = Int {
190 0: I128::MIN.0.wrapping_add(&I128::ONE.0),
191 };
192 let two = Int {
193 0: U128::from(2u32),
194 };
195 let max_minus_one = Int {
196 0: I128::MAX.0.wrapping_sub(&I128::ONE.0),
197 };
198
199 let result = I128::ONE.wrapping_sub(&I128::MIN);
201 assert_eq!(result, min_plus_one);
202
203 let result = I128::ZERO.wrapping_sub(&I128::MIN);
205 assert_eq!(result, I128::MIN);
206
207 let result = I128::MIN.wrapping_sub(&two);
209 assert_eq!(result, max_minus_one);
210 }
211 }
212}