Skip to main content

icydb_schema/decimal/
wire.rs

1use crate::{TypeParseError, decimal::Decimal};
2use candid::CandidType;
3use serde::{Deserialize, Serialize};
4
5impl CandidType for Decimal {
6    fn ty() -> candid::types::Type {
7        <String as CandidType>::ty()
8    }
9
10    fn _ty() -> candid::types::Type {
11        candid::types::TypeInner::Text.into()
12    }
13
14    fn idl_serialize<S>(&self, serializer: S) -> Result<(), S::Error>
15    where
16        S: candid::types::Serializer,
17    {
18        serializer.serialize_text(&self.to_string())
19    }
20}
21
22impl<'de> Deserialize<'de> for Decimal {
23    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
24    where
25        D: serde::Deserializer<'de>,
26    {
27        // Candid and Serde both emit text, including non-human-readable formats.
28        let text = String::deserialize(deserializer)?;
29        text.parse::<Self>()
30            .map_err(|_| serde::de::Error::custom(TypeParseError::InvalidDecimal))
31    }
32}
33
34impl Serialize for Decimal {
35    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
36    where
37        S: serde::Serializer,
38    {
39        serializer.serialize_str(&self.to_string())
40    }
41}
42
43// lossy f32 done on purpose as these ORM floats aren't designed for NaN etc.
44impl From<f32> for Decimal {
45    fn from(n: f32) -> Self {
46        Self::from_f32_lossy(n).unwrap_or(Self::ZERO)
47    }
48}
49
50impl From<f64> for Decimal {
51    fn from(n: f64) -> Self {
52        Self::from_f64_lossy(n).unwrap_or(Self::ZERO)
53    }
54}
55
56macro_rules! impl_decimal_from_signed_int {
57    ( $( $type:ty ),* ) => {
58        $(
59            impl From<$type> for Decimal {
60                fn from(n: $type) -> Self {
61                    Self {
62                        mantissa: i128::from(n),
63                        scale: 0,
64                    }
65                }
66            }
67        )*
68    };
69}
70
71macro_rules! impl_decimal_from_unsigned_int {
72    ( $( $type:ty ),* ) => {
73        $(
74            impl From<$type> for Decimal {
75                fn from(n: $type) -> Self {
76                    Self {
77                        mantissa: i128::from(n),
78                        scale: 0,
79                    }
80                }
81            }
82        )*
83    };
84}
85
86impl_decimal_from_unsigned_int!(u8, u16, u32, u64);
87impl_decimal_from_signed_int!(i8, i16, i32, i64, i128);
88
89impl From<u128> for Decimal {
90    fn from(n: u128) -> Self {
91        let mantissa = i128::try_from(n).unwrap_or(i128::MAX);
92        Self { mantissa, scale: 0 }
93    }
94}