links_domainmap/
serde.rs

1//! Serialization and deserialization implementations using `serde` for
2//! [`DomainMap`] and [`Domain`]
3
4use 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}