reifydb_value/value/number/safe/convert/
mod.rs1pub trait SafeConvert<T>: Sized {
5 fn checked_convert(self) -> Option<T>;
6 fn saturating_convert(self) -> T;
7 fn wrapping_convert(self) -> T;
8}
9
10macro_rules! impl_safe_convert {
11 ($src:ty => $($dst:ty),*) => {
12 $(
13 impl SafeConvert<$dst> for $src {
14 fn checked_convert(self) -> Option<$dst> {
15 <$dst>::try_from(self).ok()
16 }
17
18 fn saturating_convert(self) -> $dst {
19 if let Ok(v) = <$dst>::try_from(self) {
20 v
21 } else if self < 0 {
22 0
23 } else {
24 <$dst>::MAX
25 }
26 }
27
28 fn wrapping_convert(self) -> $dst {
29 self as $dst
30 }
31 }
32 )*
33 };
34}
35
36macro_rules! impl_safe_unsigned_convert {
37 ($src:ty => $($dst:ty),*) => {
38 $(
39 impl SafeConvert<$dst> for $src {
40 fn checked_convert(self) -> Option<$dst> {
41 <$dst>::try_from(self).ok()
42 }
43
44 fn saturating_convert(self) -> $dst {
45 if self > <$dst>::MAX as $src {
46 <$dst>::MAX
47 }else{
48 self as $dst
49 }
50 }
51
52 fn wrapping_convert(self) -> $dst {
53 self as $dst
54 }
55 }
56 )*
57 };
58}
59
60macro_rules! impl_safe_convert_signed_to_float {
61 ($mantissa_bits:expr; $src:ty => $($float:ty),* $(,)?) => {
62 $(
63 impl SafeConvert<$float> for $src {
64 fn checked_convert(self) -> Option<$float> {
65 let val = self as i128;
66 let max_exact = 1i128 << $mantissa_bits;
67 if val >= -max_exact && val <= max_exact {
68 Some(self as $float)
69 } else {
70 None
71 }
72 }
73
74 fn saturating_convert(self) -> $float {
75 let max_exact = 1i128 << $mantissa_bits;
76 let min = -max_exact;
77 let max = max_exact;
78 let val = self as i128;
79 if val < min {
80 min as $float
81 } else if val > max {
82 max as $float
83 } else {
84 self as $float
85 }
86 }
87
88 fn wrapping_convert(self) -> $float {
89 self as $float
90 }
91 }
92 )*
93 };
94}
95
96macro_rules! impl_safe_convert_unsigned_to_float {
97 ($mantissa_bits:expr; $src:ty => $($float:ty),* $(,)?) => {
98 $(
99 impl SafeConvert<$float> for $src {
100 fn checked_convert(self) -> Option<$float> {
101 if self as u64 <= (1u64 << $mantissa_bits) {
102 Some(self as $float)
103 } else {
104 None
105 }
106 }
107
108 fn saturating_convert(self) -> $float {
109 let max_exact = 1u64 << $mantissa_bits;
110 let max = max_exact as u128;
111 let val = self as u128;
112 if val > max {
113 max as $float
114 } else {
115 self as $float
116 }
117 }
118
119 fn wrapping_convert(self) -> $float {
120 self as $float
121 }
122 }
123 )*
124 };
125}
126
127macro_rules! impl_safe_convert_float_to_signed {
128 ($src:ty => $($dst:ty),* $(,)?) => {
129 $(
130 impl SafeConvert<$dst> for $src {
131 fn checked_convert(self) -> Option<$dst> {
132 if self.is_nan() || self.is_infinite() {
133 return None;
134 }
135
136 let min_val = <$dst>::MIN as $src;
137 let max_val = <$dst>::MAX as $src;
138
139 if self < min_val || self > max_val {
140 None
141 } else {
142 Some(self as $dst)
143 }
144 }
145
146 fn saturating_convert(self) -> $dst {
147 if self.is_nan() {
148 return 0;
149 }
150
151 if self.is_infinite() {
152 return if self.is_sign_positive() { <$dst>::MAX } else { <$dst>::MIN };
153 }
154
155 let min_val = <$dst>::MIN as $src;
156 let max_val = <$dst>::MAX as $src;
157
158 if self < min_val {
159 <$dst>::MIN
160 } else if self > max_val {
161 <$dst>::MAX
162 } else {
163 self as $dst
164 }
165 }
166
167 fn wrapping_convert(self) -> $dst {
168 if self.is_nan() {
169 return 0;
170 }
171
172 if self.is_infinite() {
173 return if self.is_sign_positive() { <$dst>::MAX } else { <$dst>::MIN };
174 }
175
176 self as $dst
177 }
178 }
179 )*
180 };
181}
182
183macro_rules! impl_safe_convert_float_to_unsigned {
184 ($src:ty => $($dst:ty),* $(,)?) => {
185 $(
186 impl SafeConvert<$dst> for $src {
187 fn checked_convert(self) -> Option<$dst> {
188 if self.is_nan() || self.is_infinite() || self < 0.0 {
189 return None;
190 }
191
192 let max_val = <$dst>::MAX as $src;
193
194 if self > max_val {
195 None
196 } else {
197 Some(self as $dst)
198 }
199 }
200
201 fn saturating_convert(self) -> $dst {
202 if self.is_nan() || self < 0.0 {
203 return 0;
204 }
205
206 if self.is_infinite() {
207 return <$dst>::MAX;
208 }
209
210 let max_val = <$dst>::MAX as $src;
211
212 if self > max_val {
213 <$dst>::MAX
214 } else {
215 self as $dst
216 }
217 }
218
219 fn wrapping_convert(self) -> $dst {
220 if self.is_nan() || self < 0.0 {
221 return 0;
222 }
223
224 if self.is_infinite() {
225 return <$dst>::MAX;
226 }
227
228 self as $dst
229 }
230 }
231 )*
232 };
233}
234
235use num_bigint::{BigInt, ToBigInt};
236use num_traits::{Signed, ToPrimitive};
237
238use crate::value::{decimal::Decimal, int::Int, uint::Uint};
239
240macro_rules! impl_safe_convert_to_int {
241 ($($from:ty),*) => {
242 $(
243 impl SafeConvert<Int> for $from {
244 fn checked_convert(self) -> Option<Int> {
245 Some(Int(BigInt::from(self)))
246 }
247
248 fn saturating_convert(self) -> Int {
249 Int(BigInt::from(self))
250 }
251
252 fn wrapping_convert(self) -> Int {
253 Int(BigInt::from(self))
254 }
255 }
256 )*
257 };
258}
259
260macro_rules! impl_safe_convert_unsigned_to_uint {
261 ($($from:ty),*) => {
262 $(
263 impl SafeConvert<Uint> for $from {
264 fn checked_convert(self) -> Option<Uint> {
265 Some(Uint(BigInt::from(self)))
266 }
267
268 fn saturating_convert(self) -> Uint {
269 Uint(BigInt::from(self))
270 }
271
272 fn wrapping_convert(self) -> Uint {
273 Uint(BigInt::from(self))
274 }
275 }
276 )*
277 };
278}
279
280macro_rules! impl_safe_convert_float_to_int {
281 ($($from:ty),*) => {
282 $(
283 impl SafeConvert<Int> for $from {
284 fn checked_convert(self) -> Option<Int> {
285 if self.is_finite() {
286 let truncated = self.trunc();
287
288 truncated.to_bigint().map(Int)
289 } else {
290 None
291 }
292 }
293
294 fn saturating_convert(self) -> Int {
295 if self.is_nan() {
296 Int::zero()
297 } else if self.is_infinite() {
298 if self.is_sign_positive() {
299 Int(BigInt::from(i64::MAX))
300 } else {
301 Int(BigInt::from(i64::MIN))
302 }
303 } else {
304 let truncated = self.trunc() as i64;
305 Int(BigInt::from(truncated))
306 }
307 }
308
309 fn wrapping_convert(self) -> Int {
310 if self.is_finite() {
311 Int(BigInt::from(self.trunc() as i64))
312 } else {
313 Int::zero()
314 }
315 }
316 }
317 )*
318 };
319}
320
321macro_rules! impl_safe_convert_float_to_uint {
322 ($($from:ty),*) => {
323 $(
324 impl SafeConvert<Uint> for $from {
325 fn checked_convert(self) -> Option<Uint> {
326 if self.is_finite() && self >= 0.0 {
327 let truncated = self.trunc();
328
329 truncated.to_bigint().and_then(|big_int| {
330 if big_int >= BigInt::from(0) {
331 Some(Uint(big_int))
332 } else {
333 None
334 }
335 })
336 } else {
337 None
338 }
339 }
340
341 fn saturating_convert(self) -> Uint {
342 if self.is_nan() || self < 0.0 {
343 Uint::zero()
344 } else if self.is_infinite() {
345 Uint(BigInt::from(u64::MAX))
346 } else {
347 let truncated = self.trunc() as u64;
348 Uint(BigInt::from(truncated))
349 }
350 }
351
352 fn wrapping_convert(self) -> Uint {
353 if self.is_finite() && self >= 0.0 {
354 Uint(BigInt::from(self.trunc() as u64))
355 } else if self.is_finite() && self < 0.0 {
356
357 Uint(BigInt::from(self.trunc() as i64 as u64))
358 } else {
359 Uint::zero()
360 }
361 }
362 }
363 )*
364 };
365}
366
367macro_rules! impl_safe_convert_promote {
368 ($src:ty => $($dst:ty),* $(,)?) => {
369 $(
370 impl SafeConvert<$dst> for $src {
371 fn checked_convert(self) -> Option<$dst> {
372 Some(self as $dst)
373 }
374
375 fn saturating_convert(self) -> $dst {
376 self as $dst
377 }
378
379 fn wrapping_convert(self) -> $dst {
380 self as $dst
381 }
382 }
383 )*
384 };
385}
386
387macro_rules! impl_safe_convert_demote {
388 ($src:ty => $($dst:ty),* $(,)?) => {
389 $(
390 impl SafeConvert<$dst> for $src {
391 fn checked_convert(self) -> Option<$dst> {
392 <$dst>::try_from(self).ok()
393 }
394
395 fn saturating_convert(self) -> $dst {
396 match <$dst>::try_from(self) {
397 Ok(v) => v,
398 Err(_) => {
399 if self < <$dst>::MIN as $src {
400 <$dst>::MIN
401 } else {
402 <$dst>::MAX
403 }
404 }
405 }
406 }
407
408 fn wrapping_convert(self) -> $dst {
409 self as $dst
410 }
411 }
412 )*
413 };
414}
415
416macro_rules! impl_safe_convert_unsigned_demote {
417 ($src:ty => $($dst:ty),* $(,)?) => {
418 $(
419 impl SafeConvert<$dst> for $src {
420 fn checked_convert(self) -> Option<$dst> {
421 <$dst>::try_from(self).ok()
422 }
423
424 fn saturating_convert(self) -> $dst {
425 if self > <$dst>::MAX as $src {
426 <$dst>::MAX
427 } else {
428 self as $dst
429 }
430 }
431
432 fn wrapping_convert(self) -> $dst {
433 self as $dst
434 }
435 }
436 )*
437 };
438}
439
440macro_rules! impl_safe_convert_float_demote {
441 ($src:ty => $dst:ty) => {
442 impl SafeConvert<$dst> for $src {
443 fn checked_convert(self) -> Option<$dst> {
444 let demoted = self as $dst;
445 if self.is_finite() && self >= <$dst>::MIN as $src && self <= <$dst>::MAX as $src {
446 Some(demoted)
447 } else {
448 None
449 }
450 }
451
452 fn saturating_convert(self) -> $dst {
453 if self.is_nan() {
454 <$dst>::NAN
455 } else if self <= <$dst>::MIN as $src {
456 <$dst>::MIN
457 } else if self >= <$dst>::MAX as $src {
458 <$dst>::MAX
459 } else {
460 self as $dst
461 }
462 }
463
464 fn wrapping_convert(self) -> $dst {
465 self as $dst
466 }
467 }
468 };
469}
470
471macro_rules! impl_safe_convert_self {
472 ($($ty:ty),* $(,)?) => {
473 $(
474 impl SafeConvert<$ty> for $ty {
475 fn checked_convert(self) -> Option<$ty> {
476 Some(self)
477 }
478
479 fn saturating_convert(self) -> $ty {
480 self
481 }
482
483 fn wrapping_convert(self) -> $ty {
484 self
485 }
486 }
487 )*
488 };
489}
490
491macro_rules! impl_safe_convert_to_decimal_from_int {
492 ($($src:ty),* $(,)?) => {
493 $(
494 impl SafeConvert<Decimal> for $src {
495 fn checked_convert(self) -> Option<Decimal> {
496 Some(Decimal::from(self))
497 }
498
499 fn saturating_convert(self) -> Decimal {
500 Decimal::from(self)
501 }
502
503 fn wrapping_convert(self) -> Decimal {
504 Decimal::from(self)
505 }
506 }
507 )*
508 };
509}
510
511macro_rules! impl_safe_convert_to_decimal_from_large_int {
512 ($($src:ty),* $(,)?) => {
513 $(
514 impl SafeConvert<Decimal> for $src {
515 fn checked_convert(self) -> Option<Decimal> {
516 Some(Decimal::from(self))
517 }
518
519 fn saturating_convert(self) -> Decimal {
520 Decimal::from(self)
521 }
522
523 fn wrapping_convert(self) -> Decimal {
524 Decimal::from(self)
525 }
526 }
527 )*
528 };
529}
530
531macro_rules! impl_safe_convert_to_decimal_from_uint {
532 ($($src:ty),* $(,)?) => {
533 $(
534 impl SafeConvert<Decimal> for $src {
535 fn checked_convert(self) -> Option<Decimal> {
536 Some(Decimal::from(self))
537 }
538
539 fn saturating_convert(self) -> Decimal {
540 Decimal::from(self)
541 }
542
543 fn wrapping_convert(self) -> Decimal {
544 Decimal::from(self)
545 }
546 }
547 )*
548 };
549}
550
551macro_rules! impl_safe_convert_to_decimal_from_float {
552 ($($src:ty),* $(,)?) => {
553 $(
554 impl SafeConvert<Decimal> for $src {
555 fn checked_convert(self) -> Option<Decimal> {
556 if !self.is_finite() {
557 return None;
558 }
559 Some(Decimal::from(self))
560 }
561
562 fn saturating_convert(self) -> Decimal {
563 self.checked_convert()
564 .unwrap_or_else(|| Decimal::default())
565 }
566
567 fn wrapping_convert(self) -> Decimal {
568 self.saturating_convert()
569 }
570 }
571 )*
572 };
573}
574
575impl_safe_convert_self!(i8, i16, i32, i64, i128, u8, u16, u32, u64, u128, f32, f64);
576impl_safe_convert_self!(Int, Uint, Decimal);
577
578pub mod decimal;
579pub mod f32;
580pub mod f64;
581pub mod i128;
582pub mod i16;
583pub mod i32;
584pub mod i64;
585pub mod i8;
586pub mod int;
587pub mod u128;
588pub mod u16;
589pub mod u32;
590pub mod u64;
591pub mod u8;
592pub mod uint;