reifydb_value/value/number/safe/
remainder.rs1pub trait SafeRemainder: Sized {
5 fn checked_rem(&self, r: &Self) -> Option<Self>;
6 fn saturating_rem(&self, r: &Self) -> Self;
7 fn wrapping_rem(&self, r: &Self) -> Self;
8 fn is_zero(&self) -> bool;
9}
10
11macro_rules! impl_safe_rem_signed {
12 ($($t:ty),*) => {
13 $(
14 impl SafeRemainder for $t {
15 fn checked_rem(&self, r: &Self) -> Option<Self> {
16 if *r == 0 || (*self == <$t>::MIN && *r == -1) {
17 None
18 } else {
19 Some(*self % *r)
20 }
21 }
22 fn saturating_rem(&self, r: &Self) -> Self {
23 if *r == 0 {
24 0
25 } else if *self == <$t>::MIN && *r == -1 {
26 0
27 } else {
28 *self % *r
29 }
30 }
31 fn wrapping_rem(&self, r: &Self) -> Self {
32 if *r == 0 {
33 0
34 } else {
35 (*self).wrapping_rem(*r)
36 }
37 }
38 fn is_zero(&self) -> bool {
39 *self == 0
40 }
41 }
42 )*
43 };
44}
45
46macro_rules! impl_safe_rem_unsigned {
47 ($($t:ty),*) => {
48 $(
49 impl SafeRemainder for $t {
50 fn checked_rem(&self, r: &Self) -> Option<Self> {
51 if *r == 0 {
52 None
53 } else {
54 Some(*self % *r)
55 }
56 }
57 fn saturating_rem(&self, r: &Self) -> Self {
58 if *r == 0 {
59 0
60 } else {
61 *self % *r
62 }
63 }
64 fn wrapping_rem(&self, r: &Self) -> Self {
65 if *r == 0 {
66 0
67 } else {
68 *self % *r
69 }
70 }
71 fn is_zero(&self) -> bool {
72 *self == 0
73 }
74 }
75 )*
76 };
77}
78
79impl_safe_rem_signed!(i8, i16, i32, i64, i128);
80impl_safe_rem_unsigned!(u8, u16, u32, u64, u128);
81
82use crate::value::decimal::Decimal;
83
84impl SafeRemainder for Decimal {
85 fn checked_rem(&self, r: &Self) -> Option<Self> {
86 Decimal::checked_rem(self, r)
87 }
88
89 fn saturating_rem(&self, r: &Self) -> Self {
90 Decimal::saturating_rem(self, r)
91 }
92
93 fn wrapping_rem(&self, r: &Self) -> Self {
94 Decimal::saturating_rem(self, r)
95 }
96
97 fn is_zero(&self) -> bool {
98 Decimal::is_zero(self)
99 }
100}
101
102impl SafeRemainder for f32 {
103 fn checked_rem(&self, r: &Self) -> Option<Self> {
104 if *r == 0.0 {
105 None
106 } else {
107 Some(*self % *r)
108 }
109 }
110
111 fn saturating_rem(&self, r: &Self) -> Self {
112 if *r == 0.0 || r.is_nan() || self.is_nan() {
113 0.0
114 } else {
115 let result = *self % *r;
116 if result.is_finite() {
117 result
118 } else {
119 0.0
120 }
121 }
122 }
123
124 fn wrapping_rem(&self, r: &Self) -> Self {
125 if *r == 0.0 {
126 0.0
127 } else {
128 let result = *self % *r;
129 if result.is_infinite() || result.is_nan() {
130 0.0
131 } else {
132 result
133 }
134 }
135 }
136
137 fn is_zero(&self) -> bool {
138 *self == 0.0
139 }
140}
141
142impl SafeRemainder for f64 {
143 fn checked_rem(&self, r: &Self) -> Option<Self> {
144 if *r == 0.0 {
145 None
146 } else {
147 Some(*self % *r)
148 }
149 }
150
151 fn saturating_rem(&self, r: &Self) -> Self {
152 if *r == 0.0 || r.is_nan() || self.is_nan() {
153 0.0
154 } else {
155 let result = *self % *r;
156 if result.is_finite() {
157 result
158 } else {
159 0.0
160 }
161 }
162 }
163
164 fn wrapping_rem(&self, r: &Self) -> Self {
165 if *r == 0.0 {
166 0.0
167 } else {
168 let result = *self % *r;
169 if result.is_infinite() || result.is_nan() {
170 0.0
171 } else {
172 result
173 }
174 }
175 }
176
177 fn is_zero(&self) -> bool {
178 *self == 0.0
179 }
180}
181
182#[cfg(test)]
183pub mod tests {
184 macro_rules! signed_unsigned {
185 ($($t:ty => $mod:ident),*) => {
186 $(
187 mod $mod {
188 use super::super::SafeRemainder;
189
190 #[test]
191 fn checked_rem_happy() {
192 let x: $t = 10;
193 let y: $t = 3;
194 assert_eq!(SafeRemainder::checked_rem(&x, &y), Some(1));
195 }
196
197 #[test]
198 fn checked_rem_zero() {
199 let x: $t = 10;
200 let y: $t = 0;
201 assert_eq!(SafeRemainder::checked_rem(&x, &y), None);
202 }
203
204 #[test]
205 fn saturating_rem_happy() {
206 let x: $t = 10;
207 let y: $t = 3;
208 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 1);
209 }
210
211 #[test]
212 fn saturating_rem_zero() {
213 let x: $t = 10;
214 let y: $t = 0;
215 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 0);
216 }
217
218 #[test]
219 fn wrapping_rem_happy() {
220 let x: $t = 10;
221 let y: $t = 3;
222 assert_eq!(SafeRemainder::wrapping_rem(&x, &y), 1);
223 }
224
225 #[test]
226 fn wrapping_rem_zero() {
227 let x: $t = 10;
228 let y: $t = 0;
229 assert_eq!(SafeRemainder::wrapping_rem(&x, &y), 0);
230 }
231 }
232 )*
233 };
234 }
235
236 signed_unsigned!(
237 i8 => i8,
238 i16 => i16,
239 i32 => i32,
240 i64 => i64,
241 i128 => i128,
242 u8 => u8,
243 u16 => u16,
244 u32 => u32,
245 u64 => u64,
246 u128 => u128
247 );
248
249 mod signed_overflow {
250 use crate::value::number::safe::remainder::SafeRemainder;
251
252 #[test]
253 fn checked_rem_min_negative_one() {
254 assert_eq!(SafeRemainder::checked_rem(&i8::MIN, &-1), None);
255 assert_eq!(SafeRemainder::checked_rem(&i16::MIN, &-1), None);
256 assert_eq!(SafeRemainder::checked_rem(&i32::MIN, &-1), None);
257 assert_eq!(SafeRemainder::checked_rem(&i64::MIN, &-1), None);
258 assert_eq!(SafeRemainder::checked_rem(&i128::MIN, &-1), None);
259 }
260
261 #[test]
262 fn saturating_rem_min_negative_one() {
263 assert_eq!(SafeRemainder::saturating_rem(&i8::MIN, &-1), 0);
264 assert_eq!(SafeRemainder::saturating_rem(&i16::MIN, &-1), 0);
265 assert_eq!(SafeRemainder::saturating_rem(&i32::MIN, &-1), 0);
266 assert_eq!(SafeRemainder::saturating_rem(&i64::MIN, &-1), 0);
267 assert_eq!(SafeRemainder::saturating_rem(&i128::MIN, &-1), 0);
268 }
269
270 #[test]
271 fn wrapping_rem_min_negative_one() {
272 assert_eq!(SafeRemainder::wrapping_rem(&i8::MIN, &-1), 0);
273 assert_eq!(SafeRemainder::wrapping_rem(&i16::MIN, &-1), 0);
274 assert_eq!(SafeRemainder::wrapping_rem(&i32::MIN, &-1), 0);
275 assert_eq!(SafeRemainder::wrapping_rem(&i64::MIN, &-1), 0);
276 assert_eq!(SafeRemainder::wrapping_rem(&i128::MIN, &-1), 0);
277 }
278 }
279
280 mod f32 {
281 use crate::value::number::safe::remainder::SafeRemainder;
282
283 #[test]
284 fn checked_rem_happy() {
285 let x: f32 = 10.5;
286 let y: f32 = 3.0;
287 assert_eq!(SafeRemainder::checked_rem(&x, &y), Some(1.5));
288 }
289
290 #[test]
291 fn checked_rem_zero() {
292 let x: f32 = 10.0;
293 let y: f32 = 0.0;
294 assert_eq!(SafeRemainder::checked_rem(&x, &y), None);
295 }
296
297 #[test]
298 fn checked_rem_nan() {
299 let x: f32 = f32::NAN;
302 let y: f32 = 3.0;
303 assert!(SafeRemainder::checked_rem(&x, &y).unwrap().is_nan());
304
305 let x: f32 = 10.0;
306 let y: f32 = f32::NAN;
307 assert!(SafeRemainder::checked_rem(&x, &y).unwrap().is_nan());
308 }
309
310 #[test]
311 fn saturating_rem_happy() {
312 let x: f32 = 10.5;
313 let y: f32 = 3.0;
314 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 1.5);
315 }
316
317 #[test]
318 fn saturating_rem_zero() {
319 let x: f32 = 10.0;
320 let y: f32 = 0.0;
321 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 0.0);
322 }
323
324 #[test]
325 fn saturating_rem_nan() {
326 let x: f32 = f32::NAN;
327 let y: f32 = 3.0;
328 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 0.0);
329 }
330
331 #[test]
332 fn wrapping_rem_happy() {
333 let x: f32 = 10.5;
334 let y: f32 = 3.0;
335 assert_eq!(SafeRemainder::wrapping_rem(&x, &y), 1.5);
336 }
337
338 #[test]
339 fn wrapping_rem_zero() {
340 let x: f32 = 10.0;
341 let y: f32 = 0.0;
342 assert_eq!(SafeRemainder::wrapping_rem(&x, &y), 0.0);
343 }
344
345 #[test]
346 fn wrapping_rem_infinity() {
347 let x: f32 = f32::INFINITY;
348 let y: f32 = 3.0;
349 let result = SafeRemainder::wrapping_rem(&x, &y);
350 assert_eq!(result, 0.0);
351 }
352 }
353
354 mod f64 {
355 use crate::value::number::safe::remainder::SafeRemainder;
356
357 #[test]
358 fn checked_rem_happy() {
359 let x: f64 = 10.5;
360 let y: f64 = 3.0;
361 assert_eq!(SafeRemainder::checked_rem(&x, &y), Some(1.5));
362 }
363
364 #[test]
365 fn checked_rem_zero() {
366 let x: f64 = 10.0;
367 let y: f64 = 0.0;
368 assert_eq!(SafeRemainder::checked_rem(&x, &y), None);
369 }
370
371 #[test]
372 fn checked_rem_nan() {
373 let x: f64 = f64::NAN;
376 let y: f64 = 3.0;
377 assert!(SafeRemainder::checked_rem(&x, &y).unwrap().is_nan());
378
379 let x: f64 = 10.0;
380 let y: f64 = f64::NAN;
381 assert!(SafeRemainder::checked_rem(&x, &y).unwrap().is_nan());
382 }
383
384 #[test]
385 fn saturating_rem_happy() {
386 let x: f64 = 10.5;
387 let y: f64 = 3.0;
388 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 1.5);
389 }
390
391 #[test]
392 fn saturating_rem_zero() {
393 let x: f64 = 10.0;
394 let y: f64 = 0.0;
395 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 0.0);
396 }
397
398 #[test]
399 fn saturating_rem_nan() {
400 let x: f64 = f64::NAN;
401 let y: f64 = 3.0;
402 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 0.0);
403 }
404
405 #[test]
406 fn wrapping_rem_happy() {
407 let x: f64 = 10.5;
408 let y: f64 = 3.0;
409 assert_eq!(SafeRemainder::wrapping_rem(&x, &y), 1.5);
410 }
411
412 #[test]
413 fn wrapping_rem_zero() {
414 let x: f64 = 10.0;
415 let y: f64 = 0.0;
416 assert_eq!(SafeRemainder::wrapping_rem(&x, &y), 0.0);
417 }
418
419 #[test]
420 fn wrapping_rem_infinity() {
421 let x: f64 = f64::INFINITY;
422 let y: f64 = 3.0;
423 let result = SafeRemainder::wrapping_rem(&x, &y);
424 assert_eq!(result, 0.0);
425 }
426 }
427}