evtc\content/
serde_guid.rs

1use crate::content::{GuidExt, GUID};
2use serde::{
3    de::{Error, Visitor},
4    Deserializer, Serializer,
5};
6use std::fmt;
7
8#[inline]
9pub fn serialize<S>(guid: &GUID, serializer: S) -> Result<S::Ok, S::Error>
10where
11    S: Serializer,
12{
13    serializer.serialize_str(&guid.format_hyphenated())
14}
15
16#[inline]
17pub fn deserialize<'de, D>(deserializer: D) -> Result<GUID, D::Error>
18where
19    D: Deserializer<'de>,
20{
21    deserializer.deserialize_str(GuidVisitor)
22}
23
24struct GuidVisitor;
25
26impl GuidVisitor {
27    fn parse(string: &str) -> Option<GUID> {
28        GUID::try_from(string)
29            .ok()
30            .or_else(|| u128::from_str_radix(string, 16).ok().map(GUID::from_u128))
31    }
32
33    fn deserialize_parse<E>(string: &str) -> Result<GUID, E>
34    where
35        E: Error,
36    {
37        Self::parse(string).ok_or_else(|| E::custom("invalid guid"))
38    }
39
40    fn deserialize_convert<T, E>(value: T) -> Result<GUID, E>
41    where
42        T: Into<u128>,
43    {
44        Ok(GUID::from_u128(value.into()))
45    }
46}
47
48impl Visitor<'_> for GuidVisitor {
49    type Value = GUID;
50
51    #[inline]
52    fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
53        formatter.write_str("a number or a hexadecimal string")
54    }
55
56    #[inline]
57    fn visit_u8<E>(self, v: u8) -> Result<Self::Value, E>
58    where
59        E: Error,
60    {
61        Self::deserialize_convert(v)
62    }
63
64    #[inline]
65    fn visit_u16<E>(self, v: u16) -> Result<Self::Value, E>
66    where
67        E: Error,
68    {
69        Self::deserialize_convert(v)
70    }
71
72    #[inline]
73    fn visit_u32<E>(self, v: u32) -> Result<Self::Value, E>
74    where
75        E: Error,
76    {
77        Self::deserialize_convert(v)
78    }
79
80    #[inline]
81    fn visit_u64<E>(self, v: u64) -> Result<Self::Value, E>
82    where
83        E: Error,
84    {
85        Self::deserialize_convert(v)
86    }
87
88    #[inline]
89    fn visit_u128<E>(self, v: u128) -> Result<Self::Value, E>
90    where
91        E: Error,
92    {
93        Self::deserialize_convert(v)
94    }
95
96    #[inline]
97    fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
98    where
99        E: Error,
100    {
101        Self::deserialize_parse(v)
102    }
103
104    #[inline]
105    fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
106    where
107        E: Error,
108    {
109        Self::deserialize_parse(&v)
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116
117    const TEST_GUID: GUID = GUID::from_u128(0x1B56F702912BE7428182CA57036AEE99);
118
119    #[test]
120    fn parse() {
121        assert_eq!(
122            GuidVisitor::parse("1B56F702912BE7428182CA57036AEE99"),
123            Some(TEST_GUID)
124        );
125        assert_eq!(
126            GuidVisitor::parse("1B56F702-912B-E742-8182-CA57036AEE99"),
127            Some(TEST_GUID)
128        );
129    }
130
131    #[test]
132    fn roundtrip() {
133        let string = TEST_GUID.format_hyphenated();
134        assert_eq!(GuidVisitor::parse(&string), Some(TEST_GUID));
135    }
136}