Skip to main content

icydb_core/traits/
numeric_value.rs

1use crate::types::Decimal;
2
3///
4/// NumericValue
5///
6/// Fallible numeric round-trip contract used by generic validators and sanitizers.
7/// Implementors convert through `Decimal` so numeric policy stays explicit and local.
8///
9
10pub trait NumericValue: Sized {
11    /// Convert this value into Decimal for generic numeric handling.
12    fn try_to_decimal(&self) -> Option<Decimal>;
13
14    /// Rebuild the value from Decimal after generic numeric handling.
15    fn try_from_decimal(value: Decimal) -> Option<Self>;
16}
17
18macro_rules! impl_numeric_value_signed {
19    ($($ty:ty),* $(,)?) => {
20        $(
21            impl NumericValue for $ty {
22                fn try_to_decimal(&self) -> Option<Decimal> {
23                    Decimal::from_i128(i128::from(*self))
24                }
25
26                fn try_from_decimal(value: Decimal) -> Option<Self> {
27                    value.to_i128().and_then(|inner| Self::try_from(inner).ok())
28                }
29            }
30        )*
31    };
32}
33
34macro_rules! impl_numeric_value_unsigned {
35    ($($ty:ty),* $(,)?) => {
36        $(
37            impl NumericValue for $ty {
38                fn try_to_decimal(&self) -> Option<Decimal> {
39                    Decimal::from_u128(u128::from(*self))
40                }
41
42                fn try_from_decimal(value: Decimal) -> Option<Self> {
43                    value.to_u128().and_then(|inner| Self::try_from(inner).ok())
44                }
45            }
46        )*
47    };
48}
49
50impl_numeric_value_signed!(i8, i16, i32, i64, i128);
51impl_numeric_value_unsigned!(u8, u16, u32, u64, u128);
52
53impl NumericValue for isize {
54    fn try_to_decimal(&self) -> Option<Decimal> {
55        Decimal::from_i128(i128::try_from(*self).ok()?)
56    }
57
58    fn try_from_decimal(value: Decimal) -> Option<Self> {
59        value.to_i128().and_then(|inner| Self::try_from(inner).ok())
60    }
61}
62
63impl NumericValue for usize {
64    fn try_to_decimal(&self) -> Option<Decimal> {
65        Decimal::from_u128(u128::try_from(*self).ok()?)
66    }
67
68    fn try_from_decimal(value: Decimal) -> Option<Self> {
69        value.to_u128().and_then(|inner| Self::try_from(inner).ok())
70    }
71}
72
73impl NumericValue for f32 {
74    fn try_to_decimal(&self) -> Option<Decimal> {
75        Decimal::from_f32_lossy(*self)
76    }
77
78    fn try_from_decimal(value: Decimal) -> Option<Self> {
79        value.to_f32()
80    }
81}
82
83impl NumericValue for f64 {
84    fn try_to_decimal(&self) -> Option<Decimal> {
85        Decimal::from_f64_lossy(*self)
86    }
87
88    fn try_from_decimal(value: Decimal) -> Option<Self> {
89        value.to_f64()
90    }
91}