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 crate::value::decimal::Decimal;
69
70impl SafeDiv for Decimal {
71 fn checked_div(&self, r: &Self) -> Option<Self> {
72 Decimal::checked_div(self, r)
73 }
74
75 fn saturating_div(&self, r: &Self) -> Self {
76 Decimal::saturating_div(self, r)
77 }
78
79 fn wrapping_div(&self, r: &Self) -> Self {
80 if r.is_zero() {
81 return Decimal::zero();
82 }
83 Decimal::saturating_div(self, r)
84 }
85
86 fn is_zero(&self) -> bool {
87 Decimal::is_zero(self)
88 }
89}
90
91impl SafeDiv for f32 {
92 fn checked_div(&self, r: &Self) -> Option<Self> {
93 let result = *self / *r;
94 if result.is_infinite() && self.is_finite() && r.is_finite() {
95 None
96 } else {
97 Some(result)
98 }
99 }
100
101 fn saturating_div(&self, r: &Self) -> Self {
102 let result = *self / *r;
103 if result.is_infinite() {
104 if result.is_sign_positive() {
105 f32::MAX
106 } else {
107 f32::MIN
108 }
109 } else {
110 result
111 }
112 }
113
114 fn wrapping_div(&self, r: &Self) -> Self {
115 let result = *self / *r;
116 if result.is_finite() {
117 result
118 } else {
119 0.0
120 }
121 }
122
123 fn is_zero(&self) -> bool {
124 *self == 0.0
125 }
126}
127
128impl SafeDiv for f64 {
129 fn checked_div(&self, r: &Self) -> Option<Self> {
130 let result = *self / *r;
131 if result.is_infinite() && self.is_finite() && r.is_finite() {
132 None
133 } else {
134 Some(result)
135 }
136 }
137
138 fn saturating_div(&self, r: &Self) -> Self {
139 let result = *self / *r;
140 if result.is_infinite() {
141 if result.is_sign_positive() {
142 f64::MAX
143 } else {
144 f64::MIN
145 }
146 } else {
147 result
148 }
149 }
150
151 fn wrapping_div(&self, r: &Self) -> Self {
152 let result = *self / *r;
153 if result.is_finite() {
154 result
155 } else {
156 0.0
157 }
158 }
159
160 fn is_zero(&self) -> bool {
161 *self == 0.0
162 }
163}
164
165#[cfg(test)]
166pub mod tests {
167 macro_rules! signed {
168 ($($t:ty => $mod:ident),*) => {
169 $(
170 mod $mod {
171 use super::super::SafeDiv;
172
173 #[test]
174 fn checked_div_happy() {
175 let x: $t = 20;
176 let y: $t = 2;
177 assert_eq!(SafeDiv::checked_div(&x, &y), Some(10));
178 }
179
180 #[test]
181 fn checked_div_unhappy() {
182 let x: $t = 10;
183 let y: $t = 0;
184 assert_eq!(SafeDiv::checked_div(&x, &y), None);
185 }
186
187 #[test]
188 fn saturating_div_happy() {
189 let x: $t = 20;
190 let y: $t = 2;
191 assert_eq!(SafeDiv::saturating_div(&x, &y), 10);
192 }
193
194 #[test]
195 fn saturating_div_unhappy() {
196 let x: $t = 10;
197 let y: $t = 0;
198 let result = SafeDiv::saturating_div(&x, &y);
200 assert_eq!(result, 0);
201 }
202
203 #[test]
204 fn saturating_div_negative() {
205 let x: $t = -10;
206 let y: $t = 0;
207 let result = SafeDiv::saturating_div(&x, &y);
209 assert_eq!(result, 0);
210 }
211
212 #[test]
213 fn wrapping_div_happy() {
214 let x: $t = 20;
215 let y: $t = 2;
216 assert_eq!(SafeDiv::wrapping_div(&x, &y), 10);
217 }
218
219 #[test]
220 fn wrapping_div_unhappy() {
221 let x: $t = <$t>::MIN;
222 let y: $t = -1;
223 let result = SafeDiv::wrapping_div(&x, &y);
225 assert_eq!(result, <$t>::MIN);
226 }
227
228 #[test]
229 fn div_small_by_large() {
230 let x: $t = 5;
231 let y: $t = <$t>::MAX;
232
233 assert_eq!(SafeDiv::checked_div(&x, &y), Some(0));
234 assert_eq!(SafeDiv::saturating_div(&x, &y), 0);
235 assert_eq!(SafeDiv::wrapping_div(&x, &y), 0);
236 }
237 }
238 )*
239 };
240 }
241
242 macro_rules! unsigned {
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 wrapping_div_happy() {
280 let x: $t = 20;
281 let y: $t = 2;
282 assert_eq!(SafeDiv::wrapping_div(&x, &y), 10);
283 }
284
285 #[test]
286 fn wrapping_div_unhappy() {
287 let x: $t = 10;
288 let y: $t = 0;
289 let result = SafeDiv::wrapping_div(&x, &y);
290 assert_eq!(result, 0);
291 }
292
293 #[test]
294 fn div_small_by_large() {
295 let x: $t = 5;
296 let y: $t = <$t>::MAX;
297
298 assert_eq!(SafeDiv::checked_div(&x, &y), Some(0));
299 assert_eq!(SafeDiv::saturating_div(&x, &y), 0);
300 assert_eq!(SafeDiv::wrapping_div(&x, &y), 0);
301 }
302 }
303 )*
304 };
305 }
306
307 signed!(
308 i8 => i8,
309 i16 => i16,
310 i32 => i32,
311 i64 => i64,
312 i128 => i128
313 );
314
315 unsigned!(
316 u8 => u8,
317 u16 => u16,
318 u32 => u32,
319 u64 => u64,
320 u128 => u128
321 );
322
323 mod f32 {
324 use super::super::SafeDiv;
325
326 #[test]
327 fn checked_div_happy() {
328 let x: f32 = 20.0;
329 let y: f32 = 2.0;
330 assert_eq!(SafeDiv::checked_div(&x, &y), Some(10.0));
331 }
332
333 #[test]
334 fn checked_div_unhappy() {
335 let x: f32 = f32::MAX;
336 let y: f32 = 0.1;
337 assert_eq!(SafeDiv::checked_div(&x, &y), None);
338 }
339
340 #[test]
341 fn saturating_div_happy() {
342 let x: f32 = 20.0;
343 let y: f32 = 2.0;
344 assert_eq!(SafeDiv::saturating_div(&x, &y), 10.0);
345 }
346
347 #[test]
348 fn saturating_div_unhappy() {
349 let x: f32 = f32::MAX;
350 let y: f32 = 0.1;
351 assert_eq!(SafeDiv::saturating_div(&x, &y), f32::MAX);
352 }
353
354 #[test]
355 fn wrapping_div_happy() {
356 let x: f32 = 20.0;
357 let y: f32 = 2.0;
358 assert_eq!(SafeDiv::wrapping_div(&x, &y), 10.0);
359 }
360
361 #[test]
362 fn wrapping_div_unhappy() {
363 let x: f32 = f32::MAX;
364 let y: f32 = 0.1;
365 let result = SafeDiv::wrapping_div(&x, &y);
366 assert!(result.is_finite());
367 assert_eq!(result, 0.0);
368 }
369
370 #[test]
371 fn wrapping_div_negative() {
372 let x: f32 = f32::MAX;
373 let y: f32 = -0.1;
374 let result = SafeDiv::wrapping_div(&x, &y);
375 assert!(result.is_finite());
376 assert_eq!(result, 0.0);
377 }
378 }
379
380 mod f64 {
381 use super::super::SafeDiv;
382
383 #[test]
384 fn checked_div_happy() {
385 let x: f64 = 20.0;
386 let y: f64 = 2.0;
387 assert_eq!(SafeDiv::checked_div(&x, &y), Some(10.0));
388 }
389
390 #[test]
391 fn checked_div_unhappy() {
392 let x: f64 = f64::MAX;
393 let y: f64 = 0.1;
394 assert_eq!(SafeDiv::checked_div(&x, &y), None);
395 }
396
397 #[test]
398 fn saturating_div_happy() {
399 let x: f64 = 20.0;
400 let y: f64 = 2.0;
401 assert_eq!(SafeDiv::saturating_div(&x, &y), 10.0);
402 }
403
404 #[test]
405 fn saturating_div_unhappy() {
406 let x: f64 = f64::MAX;
407 let y: f64 = 0.1;
408 assert_eq!(SafeDiv::saturating_div(&x, &y), f64::MAX);
409 }
410
411 #[test]
412 fn wrapping_div_happy() {
413 let x: f64 = 20.0;
414 let y: f64 = 2.0;
415 assert_eq!(SafeDiv::wrapping_div(&x, &y), 10.0);
416 }
417
418 #[test]
419 fn wrapping_div_unhappy() {
420 let x: f64 = f64::MAX;
421 let y: f64 = 0.1;
422 let result = SafeDiv::wrapping_div(&x, &y);
423 assert!(result.is_finite());
424 assert_eq!(result, 0.0);
425 }
426
427 #[test]
428 fn wrapping_div_negative() {
429 let x: f64 = f64::MAX;
430 let y: f64 = -0.1;
431 let result = SafeDiv::wrapping_div(&x, &y);
432 assert!(result.is_finite());
433 assert_eq!(result, 0.0);
434 }
435 }
436}