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