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);
274 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);
283 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);
302 }
303
304 #[test]
305 fn div_small_by_large() {
306 let x: $t = 5;
307 let y: $t = <$t>::MAX;
308
309 assert_eq!(SafeDiv::checked_div(&x, &y), Some(0));
310 assert_eq!(SafeDiv::saturating_div(&x, &y), 0);
311 assert_eq!(SafeDiv::wrapping_div(&x, &y), 0);
312 }
313 }
314 )*
315 };
316 }
317
318 macro_rules! unsigned {
319 ($($t:ty => $mod:ident),*) => {
320 $(
321 mod $mod {
322 use super::super::SafeDiv;
323
324 #[test]
325 fn checked_div_happy() {
326 let x: $t = 20;
327 let y: $t = 2;
328 assert_eq!(SafeDiv::checked_div(&x, &y), Some(10));
329 }
330
331 #[test]
332 fn checked_div_unhappy() {
333 let x: $t = 10;
334 let y: $t = 0;
335 assert_eq!(SafeDiv::checked_div(&x, &y), None);
336 }
337
338 #[test]
339 fn saturating_div_happy() {
340 let x: $t = 20;
341 let y: $t = 2;
342 assert_eq!(SafeDiv::saturating_div(&x, &y), 10);
343 }
344
345 #[test]
346 fn saturating_div_unhappy() {
347 let x: $t = 10;
348 let y: $t = 0;
349 let result = SafeDiv::saturating_div(&x, &y);
350 assert_eq!(result, 0);
352 }
353
354 #[test]
355 fn wrapping_div_happy() {
356 let x: $t = 20;
357 let y: $t = 2;
358 assert_eq!(SafeDiv::wrapping_div(&x, &y), 10);
359 }
360
361 #[test]
362 fn wrapping_div_unhappy() {
363 let x: $t = 10;
364 let y: $t = 0;
365 let result = SafeDiv::wrapping_div(&x, &y);
366 assert_eq!(result, 0);
367 }
368
369 #[test]
370 fn div_small_by_large() {
371 let x: $t = 5;
372 let y: $t = <$t>::MAX;
373
374 assert_eq!(SafeDiv::checked_div(&x, &y), Some(0));
375 assert_eq!(SafeDiv::saturating_div(&x, &y), 0);
376 assert_eq!(SafeDiv::wrapping_div(&x, &y), 0);
377 }
378 }
379 )*
380 };
381 }
382
383 signed!(
384 i8 => i8,
385 i16 => i16,
386 i32 => i32,
387 i64 => i64,
388 i128 => i128
389 );
390
391 unsigned!(
392 u8 => u8,
393 u16 => u16,
394 u32 => u32,
395 u64 => u64,
396 u128 => u128
397 );
398
399 mod f32 {
400 use super::super::SafeDiv;
401
402 #[test]
403 fn checked_div_happy() {
404 let x: f32 = 20.0;
405 let y: f32 = 2.0;
406 assert_eq!(SafeDiv::checked_div(&x, &y), Some(10.0));
407 }
408
409 #[test]
410 fn checked_div_unhappy() {
411 let x: f32 = f32::MAX;
412 let y: f32 = 0.1;
413 assert_eq!(SafeDiv::checked_div(&x, &y), None);
414 }
415
416 #[test]
417 fn saturating_div_happy() {
418 let x: f32 = 20.0;
419 let y: f32 = 2.0;
420 assert_eq!(SafeDiv::saturating_div(&x, &y), 10.0);
421 }
422
423 #[test]
424 fn saturating_div_unhappy() {
425 let x: f32 = f32::MAX;
426 let y: f32 = 0.1;
427 assert_eq!(SafeDiv::saturating_div(&x, &y), f32::MAX);
428 }
429
430 #[test]
431 fn wrapping_div_happy() {
432 let x: f32 = 20.0;
433 let y: f32 = 2.0;
434 assert_eq!(SafeDiv::wrapping_div(&x, &y), 10.0);
435 }
436
437 #[test]
438 fn wrapping_div_unhappy() {
439 let x: f32 = f32::MAX;
440 let y: f32 = 0.1;
441 let result = SafeDiv::wrapping_div(&x, &y);
442 assert!(result.is_finite());
443 assert_eq!(result, 0.0);
444 }
445
446 #[test]
447 fn wrapping_div_negative() {
448 let x: f32 = f32::MAX;
449 let y: f32 = -0.1;
450 let result = SafeDiv::wrapping_div(&x, &y);
451 assert!(result.is_finite());
452 assert_eq!(result, 0.0);
453 }
454 }
455
456 mod f64 {
457 use super::super::SafeDiv;
458
459 #[test]
460 fn checked_div_happy() {
461 let x: f64 = 20.0;
462 let y: f64 = 2.0;
463 assert_eq!(SafeDiv::checked_div(&x, &y), Some(10.0));
464 }
465
466 #[test]
467 fn checked_div_unhappy() {
468 let x: f64 = f64::MAX;
469 let y: f64 = 0.1;
470 assert_eq!(SafeDiv::checked_div(&x, &y), None);
471 }
472
473 #[test]
474 fn saturating_div_happy() {
475 let x: f64 = 20.0;
476 let y: f64 = 2.0;
477 assert_eq!(SafeDiv::saturating_div(&x, &y), 10.0);
478 }
479
480 #[test]
481 fn saturating_div_unhappy() {
482 let x: f64 = f64::MAX;
483 let y: f64 = 0.1;
484 assert_eq!(SafeDiv::saturating_div(&x, &y), f64::MAX);
485 }
486
487 #[test]
488 fn wrapping_div_happy() {
489 let x: f64 = 20.0;
490 let y: f64 = 2.0;
491 assert_eq!(SafeDiv::wrapping_div(&x, &y), 10.0);
492 }
493
494 #[test]
495 fn wrapping_div_unhappy() {
496 let x: f64 = f64::MAX;
497 let y: f64 = 0.1;
498 let result = SafeDiv::wrapping_div(&x, &y);
499 assert!(result.is_finite());
500 assert_eq!(result, 0.0);
501 }
502
503 #[test]
504 fn wrapping_div_negative() {
505 let x: f64 = f64::MAX;
506 let y: f64 = -0.1;
507 let result = SafeDiv::wrapping_div(&x, &y);
508 assert!(result.is_finite());
509 assert_eq!(result, 0.0);
510 }
511 }
512}