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