1use alloc::format;
5use core::{
6 any,
7 fmt::{Formatter, Result as FmtResult},
8 marker::PhantomData,
9};
10
11use serde::{
12 de::{Error as SerdeError, MapAccess, Unexpected, Visitor},
13 ser::SerializeMap,
14 Deserialize, Deserializer, Serialize,
15};
16
17use crate::{Domain, DomainMap};
18
19struct DomainMapVisitor<T>(PhantomData<T>);
20
21impl<'de, T: Deserialize<'de>> Visitor<'de> for DomainMapVisitor<T> {
22 type Value = DomainMap<T>;
23
24 fn expecting(&self, f: &mut Formatter) -> FmtResult {
25 f.write_fmt(format_args!(
26 "a map with domain name keys and {} values",
27 any::type_name::<T>()
28 ))
29 }
30
31 fn visit_map<A>(self, mut map: A) -> Result<Self::Value, A::Error>
32 where
33 A: MapAccess<'de>,
34 {
35 let mut domainmap = map
36 .size_hint()
37 .map_or_else(DomainMap::default, |cap| DomainMap::with_capacity(cap));
38
39 while let Some((k, v)) = map.next_entry()? {
40 domainmap.set(k, v);
41 }
42
43 Ok(domainmap)
44 }
45}
46
47struct DomainVisitor;
48
49impl<'de> Visitor<'de> for DomainVisitor {
50 type Value = Domain;
51
52 fn expecting(&self, f: &mut Formatter) -> FmtResult {
53 f.write_str("a valid domain name")
54 }
55
56 fn visit_borrowed_str<E>(self, v: &'de str) -> Result<Self::Value, E>
57 where
58 E: SerdeError,
59 {
60 Domain::presented(v)
61 .or_else(|_| Domain::reference(v))
62 .map_err(|_| SerdeError::invalid_value(Unexpected::Str(v), &self))
63 }
64}
65
66impl<T: Serialize> Serialize for DomainMap<T> {
67 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
68 where
69 S: serde::Serializer,
70 {
71 let mut map = serializer.serialize_map(Some(self.len()))?;
72
73 for (k, v) in self {
74 map.serialize_entry(k, v)?;
75 }
76
77 map.end()
78 }
79}
80
81impl<'de, T: Deserialize<'de>> Deserialize<'de> for DomainMap<T> {
82 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
83 where
84 D: Deserializer<'de>,
85 {
86 deserializer.deserialize_map(DomainMapVisitor::<T>(PhantomData))
87 }
88}
89
90impl Serialize for Domain {
91 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
92 where
93 S: serde::Serializer,
94 {
95 serializer.serialize_str(&format!("{self:#}"))
96 }
97}
98
99impl<'de> Deserialize<'de> for Domain {
100 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
101 where
102 D: Deserializer<'de>,
103 {
104 deserializer.deserialize_str(DomainVisitor)
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use alloc::string::ToString;
111 use core::f32::consts::PI;
112
113 use super::*;
114 use crate::tests::*;
115
116 #[test]
117 fn domain_serde() {
118 for &(input, _) in DOMAIN_REFERENCE {
119 if let Ok(domain) = Domain::reference(input) {
120 let res = serde_json::from_str(
121 &serde_json::to_string(&domain).expect("couldn't serialize domain"),
122 )
123 .expect("couldn't deserialize domain");
124
125 assert_eq!(domain, res);
126 }
127 }
128
129 for &(input, _) in DOMAIN_PRESENTED {
130 if let Ok(domain) = Domain::presented(input) {
131 let res = serde_json::from_str(
132 &serde_json::to_string(&domain).expect("couldn't serialize domain"),
133 )
134 .expect("couldn't deserialize domain");
135
136 assert_eq!(domain, res);
137 }
138 }
139
140 assert!(serde_json::from_str::<Domain>(r"[1, 2, 3]")
141 .unwrap_err()
142 .to_string()
143 .contains("a valid domain name"));
144 }
145
146 #[test]
147 fn domainmap_serde() {
148 let mut map = DomainMap::<usize>::new();
149 let empty = DomainMap::<i8>::new();
150 let mut example = DomainMap::<f32>::new();
151
152 for (i, &(input, _)) in DOMAIN_PRESENTED.iter().enumerate() {
153 if let Ok(domain) = Domain::presented(input) {
154 map.set(domain, i);
155 }
156 }
157
158 example.set(Domain::presented("example.com").unwrap(), PI);
159
160 let ser = serde_json::to_string(&map).unwrap();
161 let ser_empty = serde_json::to_string(&empty).unwrap();
162 let ser_example = serde_json::to_string(&example).unwrap();
163 let serde = serde_json::from_str::<DomainMap<usize>>(&ser).unwrap();
164
165 for &(input, _) in DOMAIN_PRESENTED {
166 if let Ok(domain) = Domain::presented(input) {
167 assert_eq!(serde.get(&domain), map.get(&domain));
168 }
169 }
170
171 assert_eq!(ser_empty, "{}");
172 assert!(serde_json::from_str::<DomainMap<i8>>(&ser_empty)
173 .unwrap()
174 .is_empty());
175
176 assert_eq!(ser_example, r#"{"example.com":3.1415927}"#);
177 assert_eq!(
178 serde_json::from_str::<DomainMap<f32>>(&ser_example)
179 .unwrap()
180 .get(&Domain::reference("example.com").unwrap()),
181 Some(&PI)
182 );
183
184 assert!(serde_json::from_str::<DomainMap<u16>>(r#""string""#)
185 .unwrap_err()
186 .to_string()
187 .contains("a map with domain name keys and u16 values"));
188 }
189}