icydb_schema/decimal/
wire.rs1use crate::{TypeParseError, decimal::Decimal};
2use candid::CandidType;
3use serde::{Deserialize, Serialize};
4use serde_bytes::ByteBuf;
5
6impl CandidType for Decimal {
7 fn _ty() -> candid::types::Type {
8 candid::types::TypeInner::Text.into()
9 }
10
11 fn idl_serialize<S>(&self, serializer: S) -> Result<(), S::Error>
12 where
13 S: candid::types::Serializer,
14 {
15 serializer.serialize_text(&self.to_string())
16 }
17}
18
19impl<'de> Deserialize<'de> for Decimal {
20 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
21 where
22 D: serde::Deserializer<'de>,
23 {
24 #[derive(Deserialize)]
25 #[serde(untagged)]
26 enum DecimalPayload {
27 Binary((ByteBuf, u32)),
28 Text(String),
29 }
30
31 if deserializer.is_human_readable() {
32 let s = String::deserialize(deserializer)?;
33 return s
34 .parse::<Self>()
35 .map_err(|_| serde::de::Error::custom(TypeParseError::InvalidDecimal));
36 }
37
38 let payload: DecimalPayload = Deserialize::deserialize(deserializer)?;
42 let (mantissa_bytes, scale) = match payload {
43 DecimalPayload::Binary(parts) => parts,
44 DecimalPayload::Text(s) => {
45 return s
46 .parse::<Self>()
47 .map_err(|_| serde::de::Error::custom(TypeParseError::InvalidDecimal));
48 }
49 };
50
51 if mantissa_bytes.len() != 16 {
52 return Err(serde::de::Error::custom(TypeParseError::InvalidDecimal));
53 }
54
55 let mut mantissa_buf = [0u8; 16];
56 mantissa_buf.copy_from_slice(mantissa_bytes.as_ref());
57 let mantissa = i128::from_be_bytes(mantissa_buf);
58
59 Self::checked_from_mantissa_scale(mantissa, scale)
60 .ok_or_else(|| serde::de::Error::custom(TypeParseError::InvalidDecimal))
61 }
62}
63
64impl Serialize for Decimal {
65 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
66 where
67 S: serde::Serializer,
68 {
69 serializer.serialize_str(&self.to_string())
70 }
71}
72
73impl From<f32> for Decimal {
75 fn from(n: f32) -> Self {
76 Self::from_f32_lossy(n).unwrap_or(Self::ZERO)
77 }
78}
79
80impl From<f64> for Decimal {
81 fn from(n: f64) -> Self {
82 Self::from_f64_lossy(n).unwrap_or(Self::ZERO)
83 }
84}
85
86macro_rules! impl_decimal_from_signed_int {
87 ( $( $type:ty ),* ) => {
88 $(
89 impl From<$type> for Decimal {
90 fn from(n: $type) -> Self {
91 Self {
92 mantissa: i128::from(n),
93 scale: 0,
94 }
95 }
96 }
97 )*
98 };
99}
100
101macro_rules! impl_decimal_from_unsigned_int {
102 ( $( $type:ty ),* ) => {
103 $(
104 impl From<$type> for Decimal {
105 fn from(n: $type) -> Self {
106 Self {
107 mantissa: i128::from(n),
108 scale: 0,
109 }
110 }
111 }
112 )*
113 };
114}
115
116impl_decimal_from_unsigned_int!(u8, u16, u32, u64);
117impl_decimal_from_signed_int!(i8, i16, i32, i64, i128);
118
119impl From<u128> for Decimal {
120 fn from(n: u128) -> Self {
121 let mantissa = i128::try_from(n).unwrap_or(i128::MAX);
122 Self { mantissa, scale: 0 }
123 }
124}