mybatis_drive/types/
decimal.rs

1use std::any::type_name;
2use std::fmt::Formatter;
3use std::ops::{Deref, DerefMut};
4use std::str::FromStr;
5use bigdecimal_::{BigDecimal, ParseBigDecimalError};
6use rbson::Bson;
7use rbson::spec::BinarySubtype;
8use serde::{Deserializer, Serialize, Serializer};
9use serde::de::{Error, Visitor};
10
11/// Rbatis Decimal
12#[derive(Clone, Eq, Hash, Ord, PartialEq, PartialOrd)]
13pub struct Decimal {
14    pub inner: BigDecimal,
15}
16
17impl From<BigDecimal> for Decimal {
18    fn from(arg: BigDecimal) -> Self {
19        Self {
20            inner: arg
21        }
22    }
23}
24
25impl From<&BigDecimal> for Decimal {
26    fn from(arg: &BigDecimal) -> Self {
27        Self {
28            inner: arg.clone()
29        }
30    }
31}
32
33impl serde::Serialize for Decimal {
34    #[inline]
35    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> where S: Serializer {
36        use serde::ser::Error;
37        if type_name::<S::Error>().eq("rbson::ser::error::Error") {
38            return serializer.serialize_str(&format!("Decimal({})", self.inner));
39        }else{
40            return self.inner.serialize(serializer);
41        }
42    }
43}
44
45/// Decimal allow deserialize by an String or Binary
46impl<'de> serde::Deserialize<'de> for Decimal {
47    #[inline]
48    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> where D: Deserializer<'de> {
49        let bson = rbson::Bson::deserialize(deserializer)?;
50        return match bson {
51            Bson::String(s) => {
52                if s.starts_with("Decimal(") && s.ends_with(")") {
53                    let inner_data = &s["Decimal(".len()..(s.len() - 1)];
54                    return Ok(Self {
55                        inner: BigDecimal::from_str(inner_data).or_else(|e| Err(D::Error::custom(e.to_string())))?,
56                    });
57                } else {
58                    Ok(Self {
59                        inner: BigDecimal::from_str(s.as_str()).unwrap_or_default(),
60                    })
61                }
62            }
63            Bson::Int32(s) => {
64                Ok(Self {
65                    inner: BigDecimal::from(s),
66                })
67            }
68            Bson::Int64(s) => {
69                Ok(Self {
70                    inner: BigDecimal::from(s),
71                })
72            }
73            Bson::Decimal128(s) => {
74                Ok(Self {
75                    inner: BigDecimal::from_str(&s.to_string()).unwrap_or_default(),
76                })
77            }
78            _ => {
79                Err(D::Error::custom("deserialize unsupported bson type!"))
80            }
81        };
82    }
83}
84
85impl std::fmt::Display for Decimal {
86    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
87        self.inner.fmt(f)
88    }
89}
90
91impl std::fmt::Debug for Decimal {
92    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93        self.inner.fmt(f)
94    }
95}
96
97impl Deref for Decimal {
98    type Target = BigDecimal;
99
100    fn deref(&self) -> &Self::Target {
101        &self.inner
102    }
103}
104
105impl DerefMut for Decimal {
106    fn deref_mut(&mut self) -> &mut Self::Target {
107        &mut self.inner
108    }
109}
110
111
112impl Decimal {
113    pub fn from(s: &str) -> Self {
114        let b = BigDecimal::from_str(s).unwrap_or_default();
115        Self {
116            inner: b
117        }
118    }
119
120    /// create from str
121    pub fn from_str(arg: &str) -> Result<Self, crate::error::Error> {
122        let b = BigDecimal::from_str(arg)?;
123        Ok(Self {
124            inner: b
125        })
126    }
127}
128
129#[cfg(test)]
130mod test {
131    use rbson::Bson;
132    use crate::types::Decimal;
133
134    #[test]
135    fn test_ser_de() {
136        let b = Decimal::from("1");
137        let bsons = rbson::to_bson(&b).unwrap();
138        match &bsons{
139            rbson::Bson::String(s)=>{
140                assert_eq!(s,"Decimal(1)");
141            }
142            _ => {
143                panic!("not str");
144            }
145        }
146        let b_de: Decimal = rbson::from_bson(bsons).unwrap();
147        assert_eq!(b, b_de);
148    }
149}