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