reifydb_value/value/number/safe/
sub.rs1pub trait SafeSub: Sized {
5 fn checked_sub(&self, r: &Self) -> Option<Self>;
6 fn saturating_sub(&self, r: &Self) -> Self;
7 fn wrapping_sub(&self, r: &Self) -> Self;
8}
9
10macro_rules! impl_safe_sub {
11 ($($t:ty),*) => {
12 $(
13 impl SafeSub for $t {
14 fn checked_sub(&self, r: &Self) -> Option<Self> {
15 <$t>::checked_sub(*self, *r)
16 }
17 fn saturating_sub(&self, r: &Self) -> Self {
18 <$t>::saturating_sub(*self, *r)
19 }
20 fn wrapping_sub(&self, r: &Self) -> Self {
21 <$t>::wrapping_sub(*self, *r)
22 }
23 }
24 )*
25 };
26}
27
28impl_safe_sub!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128);
29
30use num_bigint::BigInt;
31
32use crate::value::{decimal::Decimal, int::Int, uint::Uint};
33
34impl SafeSub for Int {
35 fn checked_sub(&self, r: &Self) -> Option<Self> {
36 Some(Int::from(&self.0 - &r.0))
37 }
38
39 fn saturating_sub(&self, r: &Self) -> Self {
40 Int::from(&self.0 - &r.0)
41 }
42
43 fn wrapping_sub(&self, r: &Self) -> Self {
44 Int::from(&self.0 - &r.0)
45 }
46}
47
48impl SafeSub for Uint {
49 fn checked_sub(&self, r: &Self) -> Option<Self> {
50 let result = &self.0 - &r.0;
51 if result < BigInt::from(0) {
52 None
53 } else {
54 Some(Uint::from(result))
55 }
56 }
57
58 fn saturating_sub(&self, r: &Self) -> Self {
59 let result = &self.0 - &r.0;
60 if result < BigInt::from(0) {
61 Uint::from(0u64)
62 } else {
63 Uint::from(result)
64 }
65 }
66
67 fn wrapping_sub(&self, r: &Self) -> Self {
68 let result = &self.0 - &r.0;
69 if result < BigInt::from(0) {
70 Uint::from(0u64)
71 } else {
72 Uint::from(result)
73 }
74 }
75}
76
77impl SafeSub for Decimal {
78 fn checked_sub(&self, r: &Self) -> Option<Self> {
79 let result = self.inner() - r.inner();
80 Some(Decimal::from(result))
81 }
82
83 fn saturating_sub(&self, r: &Self) -> Self {
84 let result = self.inner() - r.inner();
85 Decimal::from(result)
86 }
87
88 fn wrapping_sub(&self, r: &Self) -> Self {
89 let result = self.inner() - r.inner();
90 Decimal::from(result)
91 }
92}
93
94impl SafeSub for f32 {
95 fn checked_sub(&self, r: &Self) -> Option<Self> {
96 let result = *self - *r;
97 if result.is_finite() {
98 Some(result)
99 } else {
100 None
101 }
102 }
103
104 fn saturating_sub(&self, r: &Self) -> Self {
105 let result = *self - *r;
106 if result.is_infinite() {
107 if result.is_sign_negative() {
108 f32::MIN
109 } else {
110 f32::MAX
111 }
112 } else {
113 result
114 }
115 }
116
117 fn wrapping_sub(&self, r: &Self) -> Self {
118 *self - *r
119 }
120}
121
122impl SafeSub for f64 {
123 fn checked_sub(&self, r: &Self) -> Option<Self> {
124 let result = *self - *r;
125 if result.is_finite() {
126 Some(result)
127 } else {
128 None
129 }
130 }
131
132 fn saturating_sub(&self, r: &Self) -> Self {
133 let result = *self - *r;
134 if result.is_infinite() {
135 if result.is_sign_negative() {
136 f64::MIN
137 } else {
138 f64::MAX
139 }
140 } else {
141 result
142 }
143 }
144
145 fn wrapping_sub(&self, r: &Self) -> Self {
146 *self - *r
147 }
148}
149
150#[cfg(test)]
151pub mod tests {
152 macro_rules! define_tests {
153 ($($t:ty => $mod:ident),*) => {
154 $(
155 mod $mod {
156 use super::super::SafeSub;
157
158 #[test]
159 fn checked_sub_happy() {
160 let x: $t = 20;
161 let y: $t = 10;
162 assert_eq!(SafeSub::checked_sub(&x, &y), Some(10));
163 }
164
165 #[test]
166 fn checked_sub_unhappy() {
167 let x: $t = <$t>::MIN;
168 let y: $t = 1;
169 assert_eq!(SafeSub::checked_sub(&x, &y), None);
170 }
171
172 #[test]
173 fn saturating_sub_happy() {
174 let x: $t = 20;
175 let y: $t = 10;
176 assert_eq!(SafeSub::saturating_sub(&x, &y), 10);
177 }
178
179 #[test]
180 fn saturating_sub_unhappy() {
181 let x: $t = <$t>::MIN;
182 let y: $t = 1;
183 assert_eq!(SafeSub::saturating_sub(&x, &y), <$t>::MIN);
184 }
185
186 #[test]
187 fn wrapping_sub_happy() {
188 let x: $t = 20;
189 let y: $t = 10;
190 assert_eq!(SafeSub::wrapping_sub(&x, &y), 10);
191 }
192
193 #[test]
194 fn wrapping_sub_unhappy() {
195 let x: $t = <$t>::MIN;
196 let y: $t = 1;
197 assert_eq!(SafeSub::wrapping_sub(&x, &y), <$t>::MAX);
198 }
199 }
200 )*
201 };
202 }
203
204 define_tests!(
205 i8 => i8_tests,
206 i16 => i16_tests,
207 i32 => i32_tests,
208 i64 => i64_tests,
209 i128 => i128_tests,
210 u8 => u8_tests,
211 u16 => u16_tests,
212 u32 => u32_tests,
213 u64 => u64_tests,
214 u128 => u128_tests
215 );
216}