reifydb_value/value/number/safe/
div.rs1pub trait SafeDiv: Sized {
5 fn checked_div(&self, r: &Self) -> Option<Self>;
6 fn saturating_div(&self, r: &Self) -> Self;
7 fn wrapping_div(&self, r: &Self) -> Self;
8 fn is_zero(&self) -> bool;
9}
10
11macro_rules! impl_safe_div_signed {
12 ($($t:ty),*) => {
13 $(
14 impl SafeDiv for $t {
15 fn checked_div(&self, r: &Self) -> Option<Self> {
16 <$t>::checked_div(*self, *r)
17 }
18 fn saturating_div(&self, r: &Self) -> Self {
19 match <$t>::checked_div(*self, *r) {
20 Some(result) => result,
21 None => {
22 if *r == 0 {
23 0
24 } else {
25 <$t>::MAX
26 }
27 }
28 }
29 }
30 fn wrapping_div(&self, r: &Self) -> Self {
31 if *r == 0 { 0 } else { <$t>::wrapping_div(*self, *r) }
32 }
33 fn is_zero(&self) -> bool {
34 *self == 0
35 }
36 }
37 )*
38 };
39}
40
41macro_rules! impl_safe_div_unsigned {
42 ($($t:ty),*) => {
43 $(
44 impl SafeDiv for $t {
45 fn checked_div(&self, r: &Self) -> Option<Self> {
46 <$t>::checked_div(*self, *r)
47 }
48 fn saturating_div(&self, r: &Self) -> Self {
49 match <$t>::checked_div(*self, *r) {
50 Some(result) => result,
51 None => 0
52 }
53 }
54 fn wrapping_div(&self, r: &Self) -> Self {
55 if *r == 0 { 0 } else { <$t>::wrapping_div(*self, *r) }
56 }
57 fn is_zero(&self) -> bool {
58 *self == 0
59 }
60 }
61 )*
62 };
63}
64
65impl_safe_div_signed!(i8, i16, i32, i64, i128);
66impl_safe_div_unsigned!(u8, u16, u32, u64, u128);
67
68use bigdecimal::{BigDecimal, Zero};
69use num_bigint::BigInt;
70
71use crate::value::{decimal::Decimal, int::Int, uint::Uint};
72
73impl SafeDiv for Int {
74 fn checked_div(&self, r: &Self) -> Option<Self> {
75 if r.0 == BigInt::from(0) {
76 None
77 } else {
78 Some(Int::from(&self.0 / &r.0))
79 }
80 }
81
82 fn saturating_div(&self, r: &Self) -> Self {
83 if r.0 == BigInt::from(0) {
84 self.clone()
85 } else {
86 Int::from(&self.0 / &r.0)
87 }
88 }
89
90 fn wrapping_div(&self, r: &Self) -> Self {
91 if r.0 == BigInt::from(0) {
92 Int::from(0)
93 } else {
94 Int::from(&self.0 / &r.0)
95 }
96 }
97
98 fn is_zero(&self) -> bool {
99 self.0 == BigInt::from(0)
100 }
101}
102
103impl SafeDiv for Uint {
104 fn checked_div(&self, r: &Self) -> Option<Self> {
105 if r.0 == BigInt::from(0) {
106 None
107 } else {
108 Some(Uint::from(&self.0 / &r.0))
109 }
110 }
111
112 fn saturating_div(&self, r: &Self) -> Self {
113 if r.0 == BigInt::from(0) {
114 self.clone()
115 } else {
116 Uint::from(&self.0 / &r.0)
117 }
118 }
119
120 fn wrapping_div(&self, r: &Self) -> Self {
121 if r.0 == BigInt::from(0) {
122 Uint::from(0u64)
123 } else {
124 Uint::from(&self.0 / &r.0)
125 }
126 }
127
128 fn is_zero(&self) -> bool {
129 self.0 == BigInt::from(0)
130 }
131}
132
133impl SafeDiv for Decimal {
134 fn checked_div(&self, r: &Self) -> Option<Self> {
135 if r.inner().is_zero() {
136 None
137 } else {
138 let result = self.inner() / r.inner();
139 Some(Decimal::from(result))
140 }
141 }
142
143 fn saturating_div(&self, r: &Self) -> Self {
144 if r.inner().is_zero() {
145 self.clone()
146 } else {
147 let result = self.inner() / r.inner();
148 Decimal::from(result)
149 }
150 }
151
152 fn wrapping_div(&self, r: &Self) -> Self {
153 if r.inner().is_zero() {
154 Decimal::from(BigDecimal::from(0))
155 } else {
156 let result = self.inner() / r.inner();
157 Decimal::from(result)
158 }
159 }
160
161 fn is_zero(&self) -> bool {
162 self.inner().is_zero()
163 }
164}
165
166impl SafeDiv for f32 {
167 fn checked_div(&self, r: &Self) -> Option<Self> {
168 let result = *self / *r;
169 if result.is_finite() {
170 Some(result)
171 } else {
172 None
173 }
174 }
175
176 fn saturating_div(&self, r: &Self) -> Self {
177 let result = *self / *r;
178 if result.is_infinite() {
179 if result.is_sign_positive() {
180 f32::MAX
181 } else {
182 f32::MIN
183 }
184 } else {
185 result
186 }
187 }
188
189 fn wrapping_div(&self, r: &Self) -> Self {
190 let result = *self / *r;
191 if result.is_finite() {
192 result
193 } else {
194 0.0
195 }
196 }
197
198 fn is_zero(&self) -> bool {
199 *self == 0.0
200 }
201}
202
203impl SafeDiv for f64 {
204 fn checked_div(&self, r: &Self) -> Option<Self> {
205 let result = *self / *r;
206 if result.is_finite() {
207 Some(result)
208 } else {
209 None
210 }
211 }
212
213 fn saturating_div(&self, r: &Self) -> Self {
214 let result = *self / *r;
215 if result.is_infinite() {
216 if result.is_sign_positive() {
217 f64::MAX
218 } else {
219 f64::MIN
220 }
221 } else {
222 result
223 }
224 }
225
226 fn wrapping_div(&self, r: &Self) -> Self {
227 let result = *self / *r;
228 if result.is_finite() {
229 result
230 } else {
231 0.0
232 }
233 }
234
235 fn is_zero(&self) -> bool {
236 *self == 0.0
237 }
238}
239
240#[cfg(test)]
241pub mod tests {
242 macro_rules! signed {
243 ($($t:ty => $mod:ident),*) => {
244 $(
245 mod $mod {
246 use super::super::SafeDiv;
247
248 #[test]
249 fn checked_div_happy() {
250 let x: $t = 20;
251 let y: $t = 2;
252 assert_eq!(SafeDiv::checked_div(&x, &y), Some(10));
253 }
254
255 #[test]
256 fn checked_div_unhappy() {
257 let x: $t = 10;
258 let y: $t = 0;
259 assert_eq!(SafeDiv::checked_div(&x, &y), None);
260 }
261
262 #[test]
263 fn saturating_div_happy() {
264 let x: $t = 20;
265 let y: $t = 2;
266 assert_eq!(SafeDiv::saturating_div(&x, &y), 10);
267 }
268
269 #[test]
270 fn saturating_div_unhappy() {
271 let x: $t = 10;
272 let y: $t = 0;
273 let result = SafeDiv::saturating_div(&x, &y);
275 assert_eq!(result, 0);
276 }
277
278 #[test]
279 fn saturating_div_negative() {
280 let x: $t = -10;
281 let y: $t = 0;
282 let result = SafeDiv::saturating_div(&x, &y);
284 assert_eq!(result, 0);
285 }
286
287 #[test]
288 fn wrapping_div_happy() {
289 let x: $t = 20;
290 let y: $t = 2;
291 assert_eq!(SafeDiv::wrapping_div(&x, &y), 10);
292 }
293
294 #[test]
295 fn wrapping_div_unhappy() {
296 let x: $t = <$t>::MIN;
297 let y: $t = -1;
298 let result = SafeDiv::wrapping_div(&x, &y);
300 assert_eq!(result, <$t>::MIN);
301 }
302
303 #[test]
304 fn div_small_by_large() {
305 let x: $t = 5;
306 let y: $t = <$t>::MAX;
307
308 assert_eq!(SafeDiv::checked_div(&x, &y), Some(0));
309 assert_eq!(SafeDiv::saturating_div(&x, &y), 0);
310 assert_eq!(SafeDiv::wrapping_div(&x, &y), 0);
311 }
312 }
313 )*
314 };
315 }
316
317 macro_rules! unsigned {
318 ($($t:ty => $mod:ident),*) => {
319 $(
320 mod $mod {
321 use super::super::SafeDiv;
322
323 #[test]
324 fn checked_div_happy() {
325 let x: $t = 20;
326 let y: $t = 2;
327 assert_eq!(SafeDiv::checked_div(&x, &y), Some(10));
328 }
329
330 #[test]
331 fn checked_div_unhappy() {
332 let x: $t = 10;
333 let y: $t = 0;
334 assert_eq!(SafeDiv::checked_div(&x, &y), None);
335 }
336
337 #[test]
338 fn saturating_div_happy() {
339 let x: $t = 20;
340 let y: $t = 2;
341 assert_eq!(SafeDiv::saturating_div(&x, &y), 10);
342 }
343
344 #[test]
345 fn saturating_div_unhappy() {
346 let x: $t = 10;
347 let y: $t = 0;
348 let result = SafeDiv::saturating_div(&x, &y);
350 assert_eq!(result, 0);
351 }
352
353 #[test]
354 fn wrapping_div_happy() {
355 let x: $t = 20;
356 let y: $t = 2;
357 assert_eq!(SafeDiv::wrapping_div(&x, &y), 10);
358 }
359
360 #[test]
361 fn wrapping_div_unhappy() {
362 let x: $t = 10;
363 let y: $t = 0;
364 let result = SafeDiv::wrapping_div(&x, &y);
365 assert_eq!(result, 0);
366 }
367
368 #[test]
369 fn div_small_by_large() {
370 let x: $t = 5;
371 let y: $t = <$t>::MAX;
372
373 assert_eq!(SafeDiv::checked_div(&x, &y), Some(0));
374 assert_eq!(SafeDiv::saturating_div(&x, &y), 0);
375 assert_eq!(SafeDiv::wrapping_div(&x, &y), 0);
376 }
377 }
378 )*
379 };
380 }
381
382 signed!(
383 i8 => i8,
384 i16 => i16,
385 i32 => i32,
386 i64 => i64,
387 i128 => i128
388 );
389
390 unsigned!(
391 u8 => u8,
392 u16 => u16,
393 u32 => u32,
394 u64 => u64,
395 u128 => u128
396 );
397
398 mod f32 {
399 use super::super::SafeDiv;
400
401 #[test]
402 fn checked_div_happy() {
403 let x: f32 = 20.0;
404 let y: f32 = 2.0;
405 assert_eq!(SafeDiv::checked_div(&x, &y), Some(10.0));
406 }
407
408 #[test]
409 fn checked_div_unhappy() {
410 let x: f32 = f32::MAX;
411 let y: f32 = 0.1;
412 assert_eq!(SafeDiv::checked_div(&x, &y), None);
413 }
414
415 #[test]
416 fn saturating_div_happy() {
417 let x: f32 = 20.0;
418 let y: f32 = 2.0;
419 assert_eq!(SafeDiv::saturating_div(&x, &y), 10.0);
420 }
421
422 #[test]
423 fn saturating_div_unhappy() {
424 let x: f32 = f32::MAX;
425 let y: f32 = 0.1;
426 assert_eq!(SafeDiv::saturating_div(&x, &y), f32::MAX);
427 }
428
429 #[test]
430 fn wrapping_div_happy() {
431 let x: f32 = 20.0;
432 let y: f32 = 2.0;
433 assert_eq!(SafeDiv::wrapping_div(&x, &y), 10.0);
434 }
435
436 #[test]
437 fn wrapping_div_unhappy() {
438 let x: f32 = f32::MAX;
439 let y: f32 = 0.1;
440 let result = SafeDiv::wrapping_div(&x, &y);
441 assert!(result.is_finite());
442 assert_eq!(result, 0.0);
443 }
444
445 #[test]
446 fn wrapping_div_negative() {
447 let x: f32 = f32::MAX;
448 let y: f32 = -0.1;
449 let result = SafeDiv::wrapping_div(&x, &y);
450 assert!(result.is_finite());
451 assert_eq!(result, 0.0);
452 }
453 }
454
455 mod f64 {
456 use super::super::SafeDiv;
457
458 #[test]
459 fn checked_div_happy() {
460 let x: f64 = 20.0;
461 let y: f64 = 2.0;
462 assert_eq!(SafeDiv::checked_div(&x, &y), Some(10.0));
463 }
464
465 #[test]
466 fn checked_div_unhappy() {
467 let x: f64 = f64::MAX;
468 let y: f64 = 0.1;
469 assert_eq!(SafeDiv::checked_div(&x, &y), None);
470 }
471
472 #[test]
473 fn saturating_div_happy() {
474 let x: f64 = 20.0;
475 let y: f64 = 2.0;
476 assert_eq!(SafeDiv::saturating_div(&x, &y), 10.0);
477 }
478
479 #[test]
480 fn saturating_div_unhappy() {
481 let x: f64 = f64::MAX;
482 let y: f64 = 0.1;
483 assert_eq!(SafeDiv::saturating_div(&x, &y), f64::MAX);
484 }
485
486 #[test]
487 fn wrapping_div_happy() {
488 let x: f64 = 20.0;
489 let y: f64 = 2.0;
490 assert_eq!(SafeDiv::wrapping_div(&x, &y), 10.0);
491 }
492
493 #[test]
494 fn wrapping_div_unhappy() {
495 let x: f64 = f64::MAX;
496 let y: f64 = 0.1;
497 let result = SafeDiv::wrapping_div(&x, &y);
498 assert!(result.is_finite());
499 assert_eq!(result, 0.0);
500 }
501
502 #[test]
503 fn wrapping_div_negative() {
504 let x: f64 = f64::MAX;
505 let y: f64 = -0.1;
506 let result = SafeDiv::wrapping_div(&x, &y);
507 assert!(result.is_finite());
508 assert_eq!(result, 0.0);
509 }
510 }
511}