Skip to main content

serde_structprop/
de.rs

1//! Serde [`Deserializer`](serde::Deserializer) for the structprop format.
2//!
3//! The public entry point is [`from_str`].  Internally the input is first
4//! parsed into a [`Value`] tree by [`parse()`], then the tree is walked
5//! by a `ValueDeserializer` which implements [`serde::Deserializer`].
6//!
7//! # Type mapping
8//!
9//! | Structprop | Rust / serde |
10//! |---|---|
11//! | scalar `"true"` / `"false"` | `bool` |
12//! | scalar integer string | `i8`–`i64`, `u8`–`u64` |
13//! | scalar float string | `f32`, `f64` |
14//! | scalar `"null"` | `None` / `()` |
15//! | any other scalar | `String` / `&str` |
16//! | `key = { … }` | `Vec<T>` / tuple |
17//! | `key { … }` | struct / map |
18
19use crate::error::{Error, Result};
20use crate::parse::{parse, Value};
21use indexmap::IndexMap;
22use serde::de::{
23    self, DeserializeOwned, DeserializeSeed, EnumAccess, IntoDeserializer, MapAccess, SeqAccess,
24    VariantAccess, Visitor,
25};
26
27// ---------------------------------------------------------------------------
28// Public entry point
29// ---------------------------------------------------------------------------
30
31/// Deserialize an instance of `T` from a structprop-formatted string.
32///
33/// The entire `input` is parsed into a [`Value`] tree first, then the tree is
34/// driven through serde's visitor protocol to produce a `T`.
35///
36/// # Errors
37///
38/// Returns [`Error::Parse`] if the input is not valid structprop, or a
39/// [`Error::Message`] variant if the deserialized data does not match the
40/// expected shape of `T`.
41///
42/// # Examples
43///
44/// ```
45/// use serde::Deserialize;
46/// use serde_structprop::from_str;
47///
48/// #[derive(Deserialize, PartialEq, Debug)]
49/// struct Config { host: String, port: u16 }
50///
51/// let cfg: Config = from_str("host = localhost\nport = 9000\n").unwrap();
52/// assert_eq!(cfg.host, "localhost");
53/// assert_eq!(cfg.port, 9000);
54/// ```
55pub fn from_str<T: DeserializeOwned>(input: &str) -> Result<T> {
56    let value = parse(input)?;
57    T::deserialize(ValueDeserializer(value))
58}
59
60// ---------------------------------------------------------------------------
61// ValueDeserializer
62// ---------------------------------------------------------------------------
63
64/// A [`serde::Deserializer`] that walks a [`Value`] tree.
65///
66/// Created internally by [`from_str`]; not typically constructed directly.
67struct ValueDeserializer(Value);
68
69impl<'de> de::Deserializer<'de> for ValueDeserializer {
70    type Error = Error;
71
72    fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
73        match self.0 {
74            Value::Scalar(s) => {
75                // Mirror the Python implementation: try JSON-like coercions.
76                if s == "null" {
77                    return visitor.visit_unit();
78                }
79                if s == "true" {
80                    return visitor.visit_bool(true);
81                }
82                if s == "false" {
83                    return visitor.visit_bool(false);
84                }
85                if let Ok(n) = s.parse::<i64>() {
86                    return visitor.visit_i64(n);
87                }
88                if let Ok(n) = s.parse::<f64>() {
89                    return visitor.visit_f64(n);
90                }
91                visitor.visit_string(s)
92            }
93            Value::Array(items) => visitor.visit_seq(SeqDe::new(items)),
94            Value::Object(map) => visitor.visit_map(MapDe::new(map)),
95        }
96    }
97
98    fn deserialize_bool<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
99        match &self.0 {
100            Value::Scalar(s) => match s.as_str() {
101                "true" => visitor.visit_bool(true),
102                "false" => visitor.visit_bool(false),
103                other => Err(Error::Parse(format!("expected bool, got '{other}'"))),
104            },
105            _ => Err(Error::Parse("expected scalar for bool".into())),
106        }
107    }
108
109    fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
110        let n = parse_int(&self.0)?;
111        visitor.visit_i8(
112            i8::try_from(n).map_err(|_| Error::Parse(format!("value {n} out of range for i8")))?,
113        )
114    }
115
116    fn deserialize_i16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
117        let n = parse_int(&self.0)?;
118        visitor.visit_i16(
119            i16::try_from(n)
120                .map_err(|_| Error::Parse(format!("value {n} out of range for i16")))?,
121        )
122    }
123
124    fn deserialize_i32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
125        let n = parse_int(&self.0)?;
126        visitor.visit_i32(
127            i32::try_from(n)
128                .map_err(|_| Error::Parse(format!("value {n} out of range for i32")))?,
129        )
130    }
131
132    fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
133        visitor.visit_i64(parse_int(&self.0)?)
134    }
135
136    fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
137        let n = parse_uint(&self.0)?;
138        visitor.visit_u8(
139            u8::try_from(n).map_err(|_| Error::Parse(format!("value {n} out of range for u8")))?,
140        )
141    }
142
143    fn deserialize_u16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
144        let n = parse_uint(&self.0)?;
145        visitor.visit_u16(
146            u16::try_from(n)
147                .map_err(|_| Error::Parse(format!("value {n} out of range for u16")))?,
148        )
149    }
150
151    fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
152        let n = parse_uint(&self.0)?;
153        visitor.visit_u32(
154            u32::try_from(n)
155                .map_err(|_| Error::Parse(format!("value {n} out of range for u32")))?,
156        )
157    }
158
159    fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
160        visitor.visit_u64(parse_uint(&self.0)?)
161    }
162
163    fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
164        // f64 → f32 truncation is intentional and unavoidable here.
165        #[allow(clippy::cast_possible_truncation)]
166        visitor.visit_f32(parse_float(&self.0)? as f32)
167    }
168
169    fn deserialize_f64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
170        visitor.visit_f64(parse_float(&self.0)?)
171    }
172
173    fn deserialize_char<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
174        if let Value::Scalar(s) = &self.0 {
175            let mut chars = s.chars();
176            if let Some(c) = chars.next() {
177                if chars.next().is_none() {
178                    return visitor.visit_char(c);
179                }
180            }
181        }
182        Err(Error::Parse("expected single-character scalar".into()))
183    }
184
185    fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
186        if let Value::Scalar(s) = self.0 {
187            visitor.visit_string(s)
188        } else {
189            Err(Error::Parse("expected scalar string".into()))
190        }
191    }
192
193    fn deserialize_string<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
194        self.deserialize_str(visitor)
195    }
196
197    fn deserialize_bytes<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value> {
198        Err(Error::UnsupportedType("bytes"))
199    }
200
201    fn deserialize_byte_buf<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value> {
202        Err(Error::UnsupportedType("byte_buf"))
203    }
204
205    fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
206        if self.0.is_null() {
207            visitor.visit_none()
208        } else {
209            visitor.visit_some(self)
210        }
211    }
212
213    fn deserialize_unit<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
214        if self.0.is_null() {
215            visitor.visit_unit()
216        } else {
217            Err(Error::Parse(format!(
218                "expected null, found {}",
219                self.0.type_name()
220            )))
221        }
222    }
223
224    fn deserialize_unit_struct<V: Visitor<'de>>(
225        self,
226        _name: &'static str,
227        visitor: V,
228    ) -> Result<V::Value> {
229        self.deserialize_unit(visitor)
230    }
231
232    fn deserialize_newtype_struct<V: Visitor<'de>>(
233        self,
234        _name: &'static str,
235        visitor: V,
236    ) -> Result<V::Value> {
237        visitor.visit_newtype_struct(self)
238    }
239
240    fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
241        match self.0 {
242            Value::Array(items) => visitor.visit_seq(SeqDe::new(items)),
243            _ => Err(Error::Parse("expected array value".into())),
244        }
245    }
246
247    fn deserialize_tuple<V: Visitor<'de>>(self, _len: usize, visitor: V) -> Result<V::Value> {
248        self.deserialize_seq(visitor)
249    }
250
251    fn deserialize_tuple_struct<V: Visitor<'de>>(
252        self,
253        _name: &'static str,
254        _len: usize,
255        visitor: V,
256    ) -> Result<V::Value> {
257        self.deserialize_seq(visitor)
258    }
259
260    fn deserialize_map<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
261        match self.0 {
262            Value::Object(map) => visitor.visit_map(MapDe::new(map)),
263            _ => Err(Error::Parse("expected object value".into())),
264        }
265    }
266
267    fn deserialize_struct<V: Visitor<'de>>(
268        self,
269        _name: &'static str,
270        _fields: &'static [&'static str],
271        visitor: V,
272    ) -> Result<V::Value> {
273        self.deserialize_map(visitor)
274    }
275
276    fn deserialize_enum<V: Visitor<'de>>(
277        self,
278        _name: &'static str,
279        _variants: &'static [&'static str],
280        visitor: V,
281    ) -> Result<V::Value> {
282        match self.0 {
283            Value::Scalar(s) => {
284                // Unit variant: just the variant name as a string.
285                visitor.visit_enum(s.into_deserializer())
286            }
287            Value::Object(map) => {
288                // Newtype / tuple / struct variant: a single-entry object whose
289                // key is the variant name and whose value is the payload.
290                if map.len() != 1 {
291                    return Err(Error::Parse("enum object must have exactly one key".into()));
292                }
293                let (variant, payload) = map.into_iter().next().unwrap();
294                visitor.visit_enum(EnumDe { variant, payload })
295            }
296            Value::Array(_) => Err(Error::Parse("expected scalar or object for enum".into())),
297        }
298    }
299
300    fn deserialize_identifier<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
301        self.deserialize_str(visitor)
302    }
303
304    fn deserialize_ignored_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
305        self.deserialize_any(visitor)
306    }
307}
308
309// ---------------------------------------------------------------------------
310// SeqDe – drives sequence deserialization
311// ---------------------------------------------------------------------------
312
313/// [`SeqAccess`] impl that iterates over a [`Value::Array`]'s items.
314struct SeqDe {
315    iter: std::vec::IntoIter<Value>,
316}
317
318impl SeqDe {
319    fn new(items: Vec<Value>) -> Self {
320        SeqDe {
321            iter: items.into_iter(),
322        }
323    }
324}
325
326impl<'de> SeqAccess<'de> for SeqDe {
327    type Error = Error;
328
329    fn next_element_seed<T: DeserializeSeed<'de>>(&mut self, seed: T) -> Result<Option<T::Value>> {
330        match self.iter.next() {
331            None => Ok(None),
332            Some(v) => seed.deserialize(ValueDeserializer(v)).map(Some),
333        }
334    }
335}
336
337// ---------------------------------------------------------------------------
338// MapDe – drives map / struct deserialization
339// ---------------------------------------------------------------------------
340
341/// [`MapAccess`] impl that iterates over a [`Value::Object`]'s key-value pairs.
342struct MapDe {
343    iter: indexmap::map::IntoIter<String, Value>,
344    /// The value of the most recently yielded key, waiting for `next_value_seed`.
345    current_value: Option<Value>,
346}
347
348impl MapDe {
349    fn new(map: IndexMap<String, Value>) -> Self {
350        MapDe {
351            iter: map.into_iter(),
352            current_value: None,
353        }
354    }
355}
356
357impl<'de> MapAccess<'de> for MapDe {
358    type Error = Error;
359
360    fn next_key_seed<K: DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>> {
361        match self.iter.next() {
362            None => Ok(None),
363            Some((k, v)) => {
364                self.current_value = Some(v);
365                seed.deserialize(ValueDeserializer(Value::Scalar(k)))
366                    .map(Some)
367            }
368        }
369    }
370
371    fn next_value_seed<V2: DeserializeSeed<'de>>(&mut self, seed: V2) -> Result<V2::Value> {
372        match self.current_value.take() {
373            None => Err(Error::Parse("value missing".into())),
374            Some(v) => seed.deserialize(ValueDeserializer(v)),
375        }
376    }
377}
378
379// ---------------------------------------------------------------------------
380// EnumDe – drives enum deserialization for object-encoded variants
381// ---------------------------------------------------------------------------
382
383/// [`EnumAccess`] impl for enum variants encoded as single-key objects.
384struct EnumDe {
385    /// The variant name (the object's sole key).
386    variant: String,
387    /// The variant payload (the object's sole value).
388    payload: Value,
389}
390
391impl<'de> EnumAccess<'de> for EnumDe {
392    type Error = Error;
393    type Variant = VariantDe;
394
395    fn variant_seed<V: DeserializeSeed<'de>>(self, seed: V) -> Result<(V::Value, Self::Variant)> {
396        let variant_val = seed.deserialize(ValueDeserializer(Value::Scalar(self.variant)))?;
397        Ok((variant_val, VariantDe(self.payload)))
398    }
399}
400
401/// [`VariantAccess`] impl for the payload of an object-encoded enum variant.
402struct VariantDe(Value);
403
404impl<'de> VariantAccess<'de> for VariantDe {
405    type Error = Error;
406
407    fn unit_variant(self) -> Result<()> {
408        Ok(())
409    }
410
411    fn newtype_variant_seed<T: DeserializeSeed<'de>>(self, seed: T) -> Result<T::Value> {
412        seed.deserialize(ValueDeserializer(self.0))
413    }
414
415    fn tuple_variant<V: Visitor<'de>>(self, _len: usize, visitor: V) -> Result<V::Value> {
416        de::Deserializer::deserialize_seq(ValueDeserializer(self.0), visitor)
417    }
418
419    fn struct_variant<V: Visitor<'de>>(
420        self,
421        _fields: &'static [&'static str],
422        visitor: V,
423    ) -> Result<V::Value> {
424        de::Deserializer::deserialize_map(ValueDeserializer(self.0), visitor)
425    }
426}
427
428// ---------------------------------------------------------------------------
429// Scalar coercion helpers
430// ---------------------------------------------------------------------------
431
432/// Parse a [`Value::Scalar`] as a signed 64-bit integer.
433///
434/// # Errors
435///
436/// Returns [`Error::Parse`] if `v` is not a scalar or not a valid `i64`.
437fn parse_int(v: &Value) -> Result<i64> {
438    if let Value::Scalar(s) = v {
439        s.parse::<i64>()
440            .map_err(|_| Error::Parse(format!("expected integer, got '{s}'")))
441    } else {
442        Err(Error::Parse("expected scalar for integer".into()))
443    }
444}
445
446/// Parse a [`Value::Scalar`] as an unsigned 64-bit integer.
447///
448/// # Errors
449///
450/// Returns [`Error::Parse`] if `v` is not a scalar or not a valid `u64`.
451fn parse_uint(v: &Value) -> Result<u64> {
452    if let Value::Scalar(s) = v {
453        s.parse::<u64>()
454            .map_err(|_| Error::Parse(format!("expected unsigned integer, got '{s}'")))
455    } else {
456        Err(Error::Parse("expected scalar for unsigned integer".into()))
457    }
458}
459
460/// Parse a [`Value::Scalar`] as a 64-bit float.
461///
462/// # Errors
463///
464/// Returns [`Error::Parse`] if `v` is not a scalar or not a valid `f64`.
465fn parse_float(v: &Value) -> Result<f64> {
466    if let Value::Scalar(s) = v {
467        s.parse::<f64>()
468            .map_err(|_| Error::Parse(format!("expected float, got '{s}'")))
469    } else {
470        Err(Error::Parse("expected scalar for float".into()))
471    }
472}