1use crate::{Error, LocatedValue, Value};
10use serde::de::{
11 Deserialize, DeserializeSeed, Deserializer, EnumAccess, MapAccess, SeqAccess, VariantAccess,
12 Visitor,
13};
14use serde::forward_to_deserialize_any;
15use std::fmt::Display;
16
17fn custom(message: impl Display) -> Error {
19 Error::Deserialize {
20 message: message.to_string(),
21 location: None,
22 }
23}
24
25impl serde::de::Error for Error {
26 fn custom<T: Display>(message: T) -> Self {
27 custom(message)
28 }
29}
30
31impl Value {
34 pub fn try_deserialize<'de, T: Deserialize<'de>>(&'de self) -> Result<T, Error> {
37 T::deserialize(self)
38 }
39}
40
41impl LocatedValue {
42 pub fn try_deserialize<'de, T: Deserialize<'de>>(&'de self) -> Result<T, Error> {
45 T::deserialize(self)
46 }
47}
48
49impl<'de> Deserializer<'de> for &'de Value {
52 type Error = Error;
53
54 fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
55 match self {
56 Value::Bool(value) => visitor.visit_bool(*value),
57 Value::Int(value) => visitor.visit_i64(*value as i64),
58 Value::Float(value) => visitor.visit_f64(*value),
59 Value::String(value) => visitor.visit_borrowed_str(value),
60 Value::List(items) => visitor.visit_seq(SeqDeserializer::new(items)),
61 Value::Map(map) => visitor.visit_map(MapDeserializer::new(map.entries())),
62 Value::Null => visitor.visit_unit(),
63 }
64 }
65
66 fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
67 match self {
68 Value::Null => visitor.visit_none(),
69 _ => visitor.visit_some(self),
70 }
71 }
72
73 fn deserialize_newtype_struct<V: Visitor<'de>>(
74 self,
75 _name: &'static str,
76 visitor: V,
77 ) -> Result<V::Value, Error> {
78 visitor.visit_newtype_struct(self)
79 }
80
81 fn deserialize_enum<V: Visitor<'de>>(
82 self,
83 _name: &'static str,
84 _variants: &'static [&'static str],
85 visitor: V,
86 ) -> Result<V::Value, Error> {
87 visitor.visit_enum(EnumDeserializer::new(self)?)
88 }
89
90 forward_to_deserialize_any! {
91 bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
92 bytes byte_buf unit unit_struct seq tuple tuple_struct map struct
93 identifier ignored_any
94 }
95}
96
97impl<'de> Deserializer<'de> for &'de LocatedValue {
100 type Error = Error;
101
102 fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
103 self.value()
104 .deserialize_any(visitor)
105 .map_err(|error| error.or_location(self.location()))
106 }
107
108 fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
109 self.value()
110 .deserialize_option(visitor)
111 .map_err(|error| error.or_location(self.location()))
112 }
113
114 fn deserialize_newtype_struct<V: Visitor<'de>>(
115 self,
116 name: &'static str,
117 visitor: V,
118 ) -> Result<V::Value, Error> {
119 self.value()
120 .deserialize_newtype_struct(name, visitor)
121 .map_err(|error| error.or_location(self.location()))
122 }
123
124 fn deserialize_enum<V: Visitor<'de>>(
125 self,
126 name: &'static str,
127 variants: &'static [&'static str],
128 visitor: V,
129 ) -> Result<V::Value, Error> {
130 self.value()
131 .deserialize_enum(name, variants, visitor)
132 .map_err(|error| error.or_location(self.location()))
133 }
134
135 forward_to_deserialize_any! {
136 bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
137 bytes byte_buf unit unit_struct seq tuple tuple_struct map struct
138 identifier ignored_any
139 }
140}
141
142struct SeqDeserializer<'de> {
145 iter: std::slice::Iter<'de, LocatedValue>,
146}
147
148impl<'de> SeqDeserializer<'de> {
149 fn new(items: &'de [LocatedValue]) -> Self {
150 Self { iter: items.iter() }
151 }
152}
153
154impl<'de> SeqAccess<'de> for SeqDeserializer<'de> {
155 type Error = Error;
156
157 fn next_element_seed<T: DeserializeSeed<'de>>(
158 &mut self,
159 seed: T,
160 ) -> Result<Option<T::Value>, Error> {
161 match self.iter.next() {
162 Some(element) => seed.deserialize(element).map(Some),
163 None => Ok(None),
164 }
165 }
166
167 fn size_hint(&self) -> Option<usize> {
168 Some(self.iter.len())
169 }
170}
171
172struct MapDeserializer<'de> {
173 iter: std::slice::Iter<'de, (String, LocatedValue)>,
174 value: Option<&'de LocatedValue>,
175}
176
177impl<'de> MapDeserializer<'de> {
178 fn new(entries: &'de [(String, LocatedValue)]) -> Self {
179 Self {
180 iter: entries.iter(),
181 value: None,
182 }
183 }
184}
185
186impl<'de> MapAccess<'de> for MapDeserializer<'de> {
187 type Error = Error;
188
189 fn next_key_seed<K: DeserializeSeed<'de>>(
190 &mut self,
191 seed: K,
192 ) -> Result<Option<K::Value>, Error> {
193 match self.iter.next() {
194 Some((key, value)) => {
195 self.value = Some(value);
196 seed.deserialize(MapKeyDeserializer { key }).map(Some)
197 }
198 None => Ok(None),
199 }
200 }
201
202 fn next_value_seed<V: DeserializeSeed<'de>>(&mut self, seed: V) -> Result<V::Value, Error> {
203 let value = self
204 .value
205 .take()
206 .expect("next_value_seed called before next_key_seed");
207 seed.deserialize(value)
208 }
209
210 fn size_hint(&self) -> Option<usize> {
211 Some(self.iter.len())
212 }
213}
214
215struct MapKeyDeserializer<'de> {
217 key: &'de str,
218}
219
220impl<'de> Deserializer<'de> for MapKeyDeserializer<'de> {
221 type Error = Error;
222
223 fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value, Error> {
224 visitor.visit_borrowed_str(self.key)
225 }
226
227 forward_to_deserialize_any! {
228 bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
229 bytes byte_buf option unit unit_struct newtype_struct seq tuple
230 tuple_struct map struct enum identifier ignored_any
231 }
232}
233
234struct EnumDeserializer<'de> {
237 variant: &'de str,
238 value: Option<&'de LocatedValue>,
239}
240
241impl<'de> EnumDeserializer<'de> {
242 fn new(value: &'de Value) -> Result<Self, Error> {
243 match value {
244 Value::String(variant) => Ok(Self {
245 variant,
246 value: None,
247 }),
248 Value::Map(map) if map.len() == 1 => {
249 let (variant, value) = &map.entries()[0];
250 Ok(Self {
251 variant,
252 value: Some(value),
253 })
254 }
255 other => Err(custom(format!(
256 "cannot deserialize enum from {}",
257 other.type_name()
258 ))),
259 }
260 }
261}
262
263impl<'de> EnumAccess<'de> for EnumDeserializer<'de> {
264 type Error = Error;
265 type Variant = VariantDeserializer<'de>;
266
267 fn variant_seed<V: DeserializeSeed<'de>>(
268 self,
269 seed: V,
270 ) -> Result<(V::Value, Self::Variant), Error> {
271 let variant = seed.deserialize(MapKeyDeserializer { key: self.variant })?;
272 Ok((variant, VariantDeserializer { value: self.value }))
273 }
274}
275
276struct VariantDeserializer<'de> {
277 value: Option<&'de LocatedValue>,
278}
279
280impl<'de> VariantAccess<'de> for VariantDeserializer<'de> {
281 type Error = Error;
282
283 fn unit_variant(self) -> Result<(), Error> {
284 match self.value {
285 None => Ok(()),
286 Some(_) => Err(custom("expected a unit variant, found a payload")),
287 }
288 }
289
290 fn newtype_variant_seed<T: DeserializeSeed<'de>>(self, seed: T) -> Result<T::Value, Error> {
291 match self.value {
292 Some(value) => seed.deserialize(value),
293 None => Err(custom("expected a newtype variant payload")),
294 }
295 }
296
297 fn tuple_variant<V: Visitor<'de>>(self, _len: usize, visitor: V) -> Result<V::Value, Error> {
298 match self.value {
299 Some(value) => value.deserialize_any(visitor),
300 None => Err(custom("expected a tuple variant payload")),
301 }
302 }
303
304 fn struct_variant<V: Visitor<'de>>(
305 self,
306 _fields: &'static [&'static str],
307 visitor: V,
308 ) -> Result<V::Value, Error> {
309 match self.value {
310 Some(value) => value.deserialize_any(visitor),
311 None => Err(custom("expected a struct variant payload")),
312 }
313 }
314}
315
316#[cfg(test)]
317mod tests {
318 use crate::{LocatedValue, Location, Map, Value};
319 use serde::Deserialize;
320
321 fn location() -> Location {
322 Location::at("test", "cfg", Some(1), Some(1), None)
323 }
324
325 fn located(value: Value) -> LocatedValue {
326 LocatedValue::new(value, location())
327 }
328
329 #[derive(Deserialize, Debug, PartialEq)]
330 struct Config {
331 name: String,
332 port: u16,
333 ratio: f64,
334 enabled: bool,
335 tags: Vec<String>,
336 nickname: Option<String>,
337 level: Level,
338 }
339
340 #[derive(Deserialize, Debug, PartialEq)]
341 #[serde(rename_all = "lowercase")]
342 enum Level {
343 Debug,
344 Info,
345 Warn,
346 }
347
348 fn sample_tree() -> LocatedValue {
349 let mut map = Map::new();
350 map.insert("name".into(), located(Value::String("app".into())));
351 map.insert("port".into(), located(Value::Int(8080)));
352 map.insert("ratio".into(), located(Value::Float(0.5)));
353 map.insert("enabled".into(), located(Value::Bool(true)));
354 map.insert(
355 "tags".into(),
356 located(Value::List(vec![
357 located(Value::String("a".into())),
358 located(Value::String("b".into())),
359 ])),
360 );
361 map.insert("nickname".into(), located(Value::Null));
362 map.insert("level".into(), located(Value::String("info".into())));
363 located(Value::Map(map))
364 }
365
366 #[test]
367 fn deserializes_nested_struct() {
368 let tree = sample_tree();
369 let config: Config = tree.try_deserialize().unwrap();
370 assert_eq!(
371 config,
372 Config {
373 name: "app".into(),
374 port: 8080,
375 ratio: 0.5,
376 enabled: true,
377 tags: vec!["a".into(), "b".into()],
378 nickname: None,
379 level: Level::Info,
380 }
381 );
382 }
383
384 #[test]
385 fn type_mismatch_error_carries_location() {
386 #[derive(Deserialize, Debug)]
387 struct Port {
388 #[allow(dead_code)]
389 port: u16,
390 }
391
392 let mut map = Map::new();
393 map.insert(
394 "port".into(),
395 LocatedValue::new(
396 Value::String("nope".into()),
397 Location::at("file", "config.toml", Some(4), Some(9), None),
398 ),
399 );
400 let tree = located(Value::Map(map));
401
402 let error = tree.try_deserialize::<Port>().unwrap_err();
403 assert!(
404 matches!(
405 error,
406 crate::Error::Deserialize {
407 location: Some(_),
408 ..
409 }
410 ),
411 "expected a located deserialize error, got {error:?}"
412 );
413 let message = error.to_string();
414 assert!(
415 message.contains("file:config.toml:4:9"),
416 "message should point at the offending node: {message}"
417 );
418 }
419
420 #[test]
421 fn deserializes_borrowed_str_zero_copy() {
422 #[derive(Deserialize)]
423 struct Borrowed<'a> {
424 name: &'a str,
425 }
426
427 let mut map = Map::new();
428 map.insert("name".into(), located(Value::String("app".into())));
429 let tree = located(Value::Map(map));
430
431 let borrowed: Borrowed = tree.try_deserialize().unwrap();
432 assert_eq!(borrowed.name, "app");
433 }
434
435 #[test]
436 fn deserializes_from_json_produced_tree_shape() {
437 let mut inner = Map::new();
439 inner.insert("port".into(), located(Value::Int(1)));
440 let mut map = Map::new();
441 map.insert("name".into(), located(Value::String("x".into())));
442 map.insert("port".into(), located(Value::Int(2)));
443 map.insert("ratio".into(), located(Value::Float(1.0)));
444 map.insert("enabled".into(), located(Value::Bool(false)));
445 map.insert("tags".into(), located(Value::List(vec![])));
446 map.insert("nickname".into(), located(Value::String("n".into())));
447 map.insert("level".into(), located(Value::String("warn".into())));
448 let tree = located(Value::Map(map));
449 let config: Config = tree.try_deserialize().unwrap();
450 assert_eq!(config.nickname, Some("n".into()));
451 assert_eq!(config.level, Level::Warn);
452 let _ = inner;
453 }
454}