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 bigdecimal::{BigDecimal, Zero};
83use num_bigint::BigInt;
84
85use crate::value::{decimal::Decimal, int::Int, uint::Uint};
86
87impl SafeRemainder for Int {
88 fn checked_rem(&self, r: &Self) -> Option<Self> {
89 if r.0 == BigInt::from(0) {
90 None
91 } else {
92 Some(Int::from(&self.0 % &r.0))
93 }
94 }
95
96 fn saturating_rem(&self, r: &Self) -> Self {
97 if r.0 == BigInt::from(0) {
98 Int::from(0)
99 } else {
100 Int::from(&self.0 % &r.0)
101 }
102 }
103
104 fn wrapping_rem(&self, r: &Self) -> Self {
105 if r.0 == BigInt::from(0) {
106 Int::from(0)
107 } else {
108 Int::from(&self.0 % &r.0)
109 }
110 }
111
112 fn is_zero(&self) -> bool {
113 self.0 == BigInt::from(0)
114 }
115}
116
117impl SafeRemainder for Uint {
118 fn checked_rem(&self, r: &Self) -> Option<Self> {
119 if r.0 == BigInt::from(0) {
120 None
121 } else {
122 Some(Uint::from(&self.0 % &r.0))
123 }
124 }
125
126 fn saturating_rem(&self, r: &Self) -> Self {
127 if r.0 == BigInt::from(0) {
128 Uint::from(0u64)
129 } else {
130 Uint::from(&self.0 % &r.0)
131 }
132 }
133
134 fn wrapping_rem(&self, r: &Self) -> Self {
135 if r.0 == BigInt::from(0) {
136 Uint::from(0u64)
137 } else {
138 Uint::from(&self.0 % &r.0)
139 }
140 }
141
142 fn is_zero(&self) -> bool {
143 self.0 == BigInt::from(0)
144 }
145}
146
147impl SafeRemainder for Decimal {
148 fn checked_rem(&self, r: &Self) -> Option<Self> {
149 if r.inner().is_zero() {
150 None
151 } else {
152 let result = self.inner() % r.inner();
153 Some(Decimal::from(result))
154 }
155 }
156
157 fn saturating_rem(&self, r: &Self) -> Self {
158 if r.inner().is_zero() {
159 Decimal::from(BigDecimal::from(0))
160 } else {
161 let result = self.inner() % r.inner();
162 Decimal::from(result)
163 }
164 }
165
166 fn wrapping_rem(&self, r: &Self) -> Self {
167 if r.inner().is_zero() {
168 Decimal::from(BigDecimal::from(0))
169 } else {
170 let result = self.inner() % r.inner();
171 Decimal::from(result)
172 }
173 }
174
175 fn is_zero(&self) -> bool {
176 self.inner().is_zero()
177 }
178}
179
180impl SafeRemainder for f32 {
181 fn checked_rem(&self, r: &Self) -> Option<Self> {
182 if *r == 0.0 || r.is_nan() || self.is_nan() {
183 None
184 } else {
185 let result = *self % *r;
186 if result.is_finite() {
187 Some(result)
188 } else {
189 None
190 }
191 }
192 }
193
194 fn saturating_rem(&self, r: &Self) -> Self {
195 if *r == 0.0 || r.is_nan() || self.is_nan() {
196 0.0
197 } else {
198 let result = *self % *r;
199 if result.is_finite() {
200 result
201 } else {
202 0.0
203 }
204 }
205 }
206
207 fn wrapping_rem(&self, r: &Self) -> Self {
208 if *r == 0.0 {
209 0.0
210 } else {
211 let result = *self % *r;
212 if result.is_infinite() || result.is_nan() {
213 0.0
214 } else {
215 result
216 }
217 }
218 }
219
220 fn is_zero(&self) -> bool {
221 *self == 0.0
222 }
223}
224
225impl SafeRemainder for f64 {
226 fn checked_rem(&self, r: &Self) -> Option<Self> {
227 if *r == 0.0 || r.is_nan() || self.is_nan() {
228 None
229 } else {
230 let result = *self % *r;
231 if result.is_finite() {
232 Some(result)
233 } else {
234 None
235 }
236 }
237 }
238
239 fn saturating_rem(&self, r: &Self) -> Self {
240 if *r == 0.0 || r.is_nan() || self.is_nan() {
241 0.0
242 } else {
243 let result = *self % *r;
244 if result.is_finite() {
245 result
246 } else {
247 0.0
248 }
249 }
250 }
251
252 fn wrapping_rem(&self, r: &Self) -> Self {
253 if *r == 0.0 {
254 0.0
255 } else {
256 let result = *self % *r;
257 if result.is_infinite() || result.is_nan() {
258 0.0
259 } else {
260 result
261 }
262 }
263 }
264
265 fn is_zero(&self) -> bool {
266 *self == 0.0
267 }
268}
269
270#[cfg(test)]
271pub mod tests {
272 macro_rules! signed_unsigned {
273 ($($t:ty => $mod:ident),*) => {
274 $(
275 mod $mod {
276 use super::super::SafeRemainder;
277
278 #[test]
279 fn checked_rem_happy() {
280 let x: $t = 10;
281 let y: $t = 3;
282 assert_eq!(SafeRemainder::checked_rem(&x, &y), Some(1));
283 }
284
285 #[test]
286 fn checked_rem_zero() {
287 let x: $t = 10;
288 let y: $t = 0;
289 assert_eq!(SafeRemainder::checked_rem(&x, &y), None);
290 }
291
292 #[test]
293 fn saturating_rem_happy() {
294 let x: $t = 10;
295 let y: $t = 3;
296 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 1);
297 }
298
299 #[test]
300 fn saturating_rem_zero() {
301 let x: $t = 10;
302 let y: $t = 0;
303 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 0);
304 }
305
306 #[test]
307 fn wrapping_rem_happy() {
308 let x: $t = 10;
309 let y: $t = 3;
310 assert_eq!(SafeRemainder::wrapping_rem(&x, &y), 1);
311 }
312
313 #[test]
314 fn wrapping_rem_zero() {
315 let x: $t = 10;
316 let y: $t = 0;
317 assert_eq!(SafeRemainder::wrapping_rem(&x, &y), 0);
318 }
319 }
320 )*
321 };
322 }
323
324 signed_unsigned!(
325 i8 => i8,
326 i16 => i16,
327 i32 => i32,
328 i64 => i64,
329 i128 => i128,
330 u8 => u8,
331 u16 => u16,
332 u32 => u32,
333 u64 => u64,
334 u128 => u128
335 );
336
337 mod signed_overflow {
338 use crate::value::number::safe::remainder::SafeRemainder;
339
340 #[test]
341 fn checked_rem_min_negative_one() {
342 assert_eq!(SafeRemainder::checked_rem(&i8::MIN, &-1), None);
343 assert_eq!(SafeRemainder::checked_rem(&i16::MIN, &-1), None);
344 assert_eq!(SafeRemainder::checked_rem(&i32::MIN, &-1), None);
345 assert_eq!(SafeRemainder::checked_rem(&i64::MIN, &-1), None);
346 assert_eq!(SafeRemainder::checked_rem(&i128::MIN, &-1), None);
347 }
348
349 #[test]
350 fn saturating_rem_min_negative_one() {
351 assert_eq!(SafeRemainder::saturating_rem(&i8::MIN, &-1), 0);
352 assert_eq!(SafeRemainder::saturating_rem(&i16::MIN, &-1), 0);
353 assert_eq!(SafeRemainder::saturating_rem(&i32::MIN, &-1), 0);
354 assert_eq!(SafeRemainder::saturating_rem(&i64::MIN, &-1), 0);
355 assert_eq!(SafeRemainder::saturating_rem(&i128::MIN, &-1), 0);
356 }
357
358 #[test]
359 fn wrapping_rem_min_negative_one() {
360 assert_eq!(SafeRemainder::wrapping_rem(&i8::MIN, &-1), 0);
361 assert_eq!(SafeRemainder::wrapping_rem(&i16::MIN, &-1), 0);
362 assert_eq!(SafeRemainder::wrapping_rem(&i32::MIN, &-1), 0);
363 assert_eq!(SafeRemainder::wrapping_rem(&i64::MIN, &-1), 0);
364 assert_eq!(SafeRemainder::wrapping_rem(&i128::MIN, &-1), 0);
365 }
366 }
367
368 mod f32 {
369 use crate::value::number::safe::remainder::SafeRemainder;
370
371 #[test]
372 fn checked_rem_happy() {
373 let x: f32 = 10.5;
374 let y: f32 = 3.0;
375 assert_eq!(SafeRemainder::checked_rem(&x, &y), Some(1.5));
376 }
377
378 #[test]
379 fn checked_rem_zero() {
380 let x: f32 = 10.0;
381 let y: f32 = 0.0;
382 assert_eq!(SafeRemainder::checked_rem(&x, &y), None);
383 }
384
385 #[test]
386 fn checked_rem_nan() {
387 let x: f32 = f32::NAN;
388 let y: f32 = 3.0;
389 assert_eq!(SafeRemainder::checked_rem(&x, &y), None);
390
391 let x: f32 = 10.0;
392 let y: f32 = f32::NAN;
393 assert_eq!(SafeRemainder::checked_rem(&x, &y), None);
394 }
395
396 #[test]
397 fn saturating_rem_happy() {
398 let x: f32 = 10.5;
399 let y: f32 = 3.0;
400 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 1.5);
401 }
402
403 #[test]
404 fn saturating_rem_zero() {
405 let x: f32 = 10.0;
406 let y: f32 = 0.0;
407 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 0.0);
408 }
409
410 #[test]
411 fn saturating_rem_nan() {
412 let x: f32 = f32::NAN;
413 let y: f32 = 3.0;
414 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 0.0);
415 }
416
417 #[test]
418 fn wrapping_rem_happy() {
419 let x: f32 = 10.5;
420 let y: f32 = 3.0;
421 assert_eq!(SafeRemainder::wrapping_rem(&x, &y), 1.5);
422 }
423
424 #[test]
425 fn wrapping_rem_zero() {
426 let x: f32 = 10.0;
427 let y: f32 = 0.0;
428 assert_eq!(SafeRemainder::wrapping_rem(&x, &y), 0.0);
429 }
430
431 #[test]
432 fn wrapping_rem_infinity() {
433 let x: f32 = f32::INFINITY;
434 let y: f32 = 3.0;
435 let result = SafeRemainder::wrapping_rem(&x, &y);
436 assert_eq!(result, 0.0);
437 }
438 }
439
440 mod f64 {
441 use crate::value::number::safe::remainder::SafeRemainder;
442
443 #[test]
444 fn checked_rem_happy() {
445 let x: f64 = 10.5;
446 let y: f64 = 3.0;
447 assert_eq!(SafeRemainder::checked_rem(&x, &y), Some(1.5));
448 }
449
450 #[test]
451 fn checked_rem_zero() {
452 let x: f64 = 10.0;
453 let y: f64 = 0.0;
454 assert_eq!(SafeRemainder::checked_rem(&x, &y), None);
455 }
456
457 #[test]
458 fn checked_rem_nan() {
459 let x: f64 = f64::NAN;
460 let y: f64 = 3.0;
461 assert_eq!(SafeRemainder::checked_rem(&x, &y), None);
462
463 let x: f64 = 10.0;
464 let y: f64 = f64::NAN;
465 assert_eq!(SafeRemainder::checked_rem(&x, &y), None);
466 }
467
468 #[test]
469 fn saturating_rem_happy() {
470 let x: f64 = 10.5;
471 let y: f64 = 3.0;
472 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 1.5);
473 }
474
475 #[test]
476 fn saturating_rem_zero() {
477 let x: f64 = 10.0;
478 let y: f64 = 0.0;
479 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 0.0);
480 }
481
482 #[test]
483 fn saturating_rem_nan() {
484 let x: f64 = f64::NAN;
485 let y: f64 = 3.0;
486 assert_eq!(SafeRemainder::saturating_rem(&x, &y), 0.0);
487 }
488
489 #[test]
490 fn wrapping_rem_happy() {
491 let x: f64 = 10.5;
492 let y: f64 = 3.0;
493 assert_eq!(SafeRemainder::wrapping_rem(&x, &y), 1.5);
494 }
495
496 #[test]
497 fn wrapping_rem_zero() {
498 let x: f64 = 10.0;
499 let y: f64 = 0.0;
500 assert_eq!(SafeRemainder::wrapping_rem(&x, &y), 0.0);
501 }
502
503 #[test]
504 fn wrapping_rem_infinity() {
505 let x: f64 = f64::INFINITY;
506 let y: f64 = 3.0;
507 let result = SafeRemainder::wrapping_rem(&x, &y);
508 assert_eq!(result, 0.0);
509 }
510 }
511}