etopay_api_types/api/
decimal.rs1#[derive(Debug, Copy, Clone, PartialEq)]
4#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
5#[cfg_attr(feature = "utoipa", schema(value_type = String))]
6pub struct Decimal(pub rust_decimal::Decimal);
7
8impl From<rust_decimal::Decimal> for Decimal {
9 fn from(value: rust_decimal::Decimal) -> Self {
10 Self(value)
11 }
12}
13
14mod serde {
17 use super::Decimal;
18
19 impl serde::Serialize for Decimal {
20 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
21 where
22 S: serde::Serializer,
23 {
24 serializer.serialize_str(&self.0.to_string())
25 }
26 }
27
28 struct DecimalVisitor;
29
30 impl serde::de::Visitor<'_> for DecimalVisitor {
31 type Value = Decimal;
32
33 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
34 formatter.write_str("String containing a decimal number")
35 }
36
37 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
38 where
39 E: serde::de::Error,
40 {
41 rust_decimal::Decimal::from_str_exact(v)
48 .map(Decimal)
49 .map_err(|e| E::custom(format!("Could not parse {v}: {e}")))
50 }
51 }
52
53 impl<'de> serde::Deserialize<'de> for Decimal {
54 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
55 where
56 D: serde::Deserializer<'de>,
57 {
58 deserializer.deserialize_string(DecimalVisitor)
59 }
60 }
61}
62
63#[cfg(test)]
64mod test {
65 use super::Decimal;
66 use rust_decimal_macros::dec;
67
68 #[rstest::rstest]
69 #[case("\"0.000000000000000001\"", Ok(Decimal::from(dec!(0.000000000000000001))))]
70 #[case("\"1.000000000000000001\"", Ok(Decimal::from(dec!(1.000000000000000001))))]
71 #[case("\"10000000000.000000000000000001\"", Ok(Decimal::from(dec!(10000000000.000000000000000001))))]
72 #[case("\"100000000000.000000000000000001\"", Err(serde_json::error::Category::Data))]
73 #[case("\"10000000000000000000000000001\"", Ok(Decimal::from(dec!(10000000000000000000000000001))))]
74 fn test_deserialization(#[case] input: &str, #[case] expected: Result<Decimal, serde_json::error::Category>) {
75 let result = serde_json::from_str::<Decimal>(input);
76
77 match (result, expected) {
78 (Ok(d), Ok(d2)) => assert_eq!(d, d2),
79 (Err(e), Err(e2)) => assert_eq!(e.classify(), e2),
80 (other, other2) => panic!("Expected: {:?} but got {:?}", other2, other),
81 }
82 }
83}