1use serde::{
27 de::{self, DeserializeSeed, Deserializer, IntoDeserializer, MapAccess, SeqAccess, Visitor},
28 forward_to_deserialize_any,
29};
30use serde_json::{Map, Value};
31
32use crate::normalize::canonical;
33
34pub struct Forgiving(pub Value);
37
38fn rekey(
44 map: Map<String, Value>,
45 fields: &[&str],
46) -> Result<Map<String, Value>, serde_json::Error> {
47 let mut out = Map::new();
48
49 for (key, value) in map {
50 let key = match canonical(&key, fields) {
51 Some(field) => field.to_string(),
52 None => key,
53 };
54
55 if out.contains_key(&key) {
56 return Err(de::Error::custom(format!(
57 "`{key}` was given more than once, under more than one spelling"
58 )));
59 }
60
61 out.insert(key, value);
62 }
63
64 Ok(out)
65}
66
67impl<'de> Deserializer<'de> for Forgiving {
68 type Error = serde_json::Error;
69
70 fn deserialize_struct<V: Visitor<'de>>(
71 self,
72 name: &'static str,
73 fields: &'static [&'static str],
74 visitor: V,
75 ) -> Result<V::Value, Self::Error> {
76 match self.0 {
77 Value::Object(map) => visitor.visit_map(ForgivingMap::new(rekey(map, fields)?)),
78 other => other.deserialize_struct(name, fields, visitor),
79 }
80 }
81
82 fn deserialize_map<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
86 match self.0 {
87 Value::Object(map) => visitor.visit_map(ForgivingMap::new(map)),
88 other => other.deserialize_map(visitor),
89 }
90 }
91
92 fn deserialize_enum<V: Visitor<'de>>(
95 self,
96 name: &'static str,
97 variants: &'static [&'static str],
98 visitor: V,
99 ) -> Result<V::Value, Self::Error> {
100 let value = match self.0 {
101 Value::String(tag) => match canonical(&tag, variants) {
102 Some(variant) => Value::String(variant.to_string()),
103 None => Value::String(tag),
104 },
105 other => other,
106 };
107
108 value.deserialize_enum(name, variants, visitor)
109 }
110
111 fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
112 match self.0 {
113 Value::Array(items) => visitor.visit_seq(ForgivingSeq(items.into_iter())),
114 other => other.deserialize_seq(visitor),
115 }
116 }
117
118 fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
119 match self.0 {
120 Value::Null => visitor.visit_none(),
121 value => visitor.visit_some(Forgiving(value)),
122 }
123 }
124
125 fn deserialize_newtype_struct<V: Visitor<'de>>(
126 self,
127 _name: &'static str,
128 visitor: V,
129 ) -> Result<V::Value, Self::Error> {
130 visitor.visit_newtype_struct(Forgiving(self.0))
131 }
132
133 fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Self::Error> {
134 self.0.deserialize_any(visitor)
135 }
136
137 forward_to_deserialize_any! {
138 bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
139 bytes byte_buf unit unit_struct tuple tuple_struct identifier ignored_any
140 }
141}
142
143struct ForgivingMap {
144 entries: serde_json::map::IntoIter,
145 value: Option<Value>,
146}
147
148impl ForgivingMap {
149 fn new(map: Map<String, Value>) -> Self {
150 Self {
151 entries: map.into_iter(),
152 value: None,
153 }
154 }
155}
156
157impl<'de> MapAccess<'de> for ForgivingMap {
158 type Error = serde_json::Error;
159
160 fn next_key_seed<K: DeserializeSeed<'de>>(
161 &mut self,
162 seed: K,
163 ) -> Result<Option<K::Value>, Self::Error> {
164 let Some((key, value)) = self.entries.next() else {
165 return Ok(None);
166 };
167
168 self.value = Some(value);
169 seed.deserialize(key.into_deserializer()).map(Some)
170 }
171
172 fn next_value_seed<V: DeserializeSeed<'de>>(
173 &mut self,
174 seed: V,
175 ) -> Result<V::Value, Self::Error> {
176 let value = self.value.take().unwrap_or(Value::Null);
177 seed.deserialize(Forgiving(value))
178 }
179
180 fn size_hint(&self) -> Option<usize> {
181 Some(self.entries.len())
182 }
183}
184
185struct ForgivingSeq(std::vec::IntoIter<Value>);
186
187impl<'de> SeqAccess<'de> for ForgivingSeq {
188 type Error = serde_json::Error;
189
190 fn next_element_seed<T: DeserializeSeed<'de>>(
191 &mut self,
192 seed: T,
193 ) -> Result<Option<T::Value>, Self::Error> {
194 match self.0.next() {
195 Some(value) => seed.deserialize(Forgiving(value)).map(Some),
196 None => Ok(None),
197 }
198 }
199
200 fn size_hint(&self) -> Option<usize> {
201 Some(self.0.len())
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use serde::Deserialize;
208 use serde_json::json;
209
210 use super::*;
211
212 #[derive(Debug, Deserialize, PartialEq)]
213 #[serde(rename_all = "kebab-case")]
214 enum Format {
215 Hex,
216 #[serde(alias = "raw")]
217 RawBinary,
218 }
219
220 #[derive(Debug, Deserialize, PartialEq)]
221 #[serde(rename_all = "kebab-case", deny_unknown_fields)]
222 struct Config {
223 format: Format,
224 #[serde(default)]
225 max_connections: Option<u32>,
226 #[serde(default)]
227 label: Option<String>,
228 }
229
230 fn parse(value: Value) -> Result<Config, serde_json::Error> {
231 Config::deserialize(Forgiving(value))
232 }
233
234 #[test]
235 fn keys_and_values_tolerate_any_spelling() {
236 let config = parse(json!({"Format": "Raw_Binary", "max_connections": 4})).unwrap();
237
238 assert_eq!(config.format, Format::RawBinary);
239 assert_eq!(config.max_connections, Some(4));
240 }
241
242 #[test]
243 fn declared_aliases_still_reach_serde() {
244 assert_eq!(
245 parse(json!({"format": "raw"})).unwrap().format,
246 Format::RawBinary
247 );
248 }
249
250 #[test]
251 fn values_are_not_touched() {
252 let config = parse(json!({"format": "hex", "label": "Wire_Tap"})).unwrap();
253
254 assert_eq!(config.label.as_deref(), Some("Wire_Tap"));
255 }
256
257 #[test]
258 fn unknown_options_are_still_rejected() {
259 assert!(parse(json!({"format": "hex", "nonsense": 1})).is_err());
260 }
261
262 #[test]
263 fn one_option_under_two_spellings_is_an_error() {
264 assert!(
265 parse(json!({"format": "hex", "max-connections": 1, "maxconnections": 2})).is_err()
266 );
267 }
268}