engineering_repr/
serde_support.rs

1//! Serde support
2
3use std::{marker::PhantomData, str::FromStr};
4
5use serde::{de, Deserialize, Serialize};
6
7use crate::{EQSupported, EngineeringQuantity};
8
9/// <div class="warning">
10/// Available on feature <b>serde</b> only.
11/// </div>
12impl<T: EQSupported<T>> Serialize for EngineeringQuantity<T> {
13    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
14    where
15        S: serde::Serializer,
16    {
17        let s = self.with_precision(0).to_string();
18        serializer.serialize_str(&s)
19    }
20}
21
22struct EQVisitor<U: EQSupported<U>>(PhantomData<U>);
23impl<U: EQSupported<U>> EQVisitor<U> {
24    fn new() -> Self {
25        Self(PhantomData)
26    }
27}
28impl<U: EQSupported<U> + FromStr + std::convert::TryFrom<u128> + std::convert::TryFrom<i128>>
29    de::Visitor<'_> for EQVisitor<U>
30{
31    type Value = EngineeringQuantity<U>;
32
33    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
34    where
35        E: de::Error,
36    {
37        let res = EngineeringQuantity::from_str(v);
38        res.map_err(|_| de::Error::invalid_value(de::Unexpected::Str(v), &self))
39    }
40
41    fn visit_u128<E>(self, value: u128) -> Result<Self::Value, E>
42    where
43        E: de::Error,
44    {
45        let u = U::try_from(value).map_err(|_| de::Error::custom("failed to convert integer"))?;
46        Ok(Self::Value::from(u))
47    }
48    fn visit_i128<E>(self, value: i128) -> Result<Self::Value, E>
49    where
50        E: de::Error,
51    {
52        let u = U::try_from(value).map_err(|_| de::Error::custom("failed to convert integer"))?;
53        Ok(Self::Value::from(u))
54    }
55    fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
56    where
57        E: de::Error,
58    {
59        self.visit_u128(value.into())
60    }
61    fn visit_i64<E>(self, value: i64) -> Result<Self::Value, E>
62    where
63        E: de::Error,
64    {
65        self.visit_i128(value.into())
66    }
67
68    fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
69        formatter.write_str("an engineering quantity (1M, 4.5k, etc) or an integer")
70    }
71}
72
73/// <div class="warning">
74/// Available on feature <b>serde</b> only.
75/// </div>
76impl<
77        'de,
78        T: EQSupported<T> + FromStr + std::convert::TryFrom<u128> + std::convert::TryFrom<i128>,
79    > Deserialize<'de> for EngineeringQuantity<T>
80{
81    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
82    where
83        D: serde::Deserializer<'de>,
84    {
85        deserializer.deserialize_any(EQVisitor::<T>::new())
86    }
87}
88
89#[cfg(test)]
90mod test {
91    use crate::EngineeringQuantity as EQ;
92
93    #[test]
94    fn pairwise_precision() {
95        let e1 = EQ::from_raw(1_234, 2).unwrap();
96        let json = serde_json::to_string(&e1).unwrap();
97        println!("{json}");
98        let e2 = serde_json::from_str(&json).unwrap();
99        assert_eq!(e1, e2);
100    }
101
102    #[test]
103    fn type_mismatch() {
104        let _ = serde_json::from_str::<EQ<i32>>("false").expect_err("type mismatch");
105    }
106
107    #[test]
108    fn deserialize_int() {
109        let eq = serde_json::from_str::<EQ<u128>>("42768").unwrap();
110        assert_eq!(eq.to_raw(), (42768, 0));
111        let eq = serde_json::from_str::<EQ<i128>>("-42768").unwrap();
112        assert_eq!(eq.to_raw(), (-42768, 0));
113        let eq = serde_json::from_str::<EQ<u32>>("12345").unwrap();
114        assert_eq!(eq.to_raw(), (12345, 0));
115        let eq = serde_json::from_str::<EQ<i16>>("-9876").unwrap();
116        assert_eq!(eq.to_raw(), (-9876, 0));
117
118        // overflow (raw integer that won't fit)
119        let _ = serde_json::from_str::<EQ<u16>>("65537").unwrap_err();
120    }
121}