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