deb822/
de.rs

1use serde::{
2    de::{self, Deserialize, DeserializeSeed, SeqAccess, Visitor},
3    forward_to_deserialize_any,
4};
5
6use crate::{
7    DeserializerStanza,
8    error::{Error, Result},
9};
10
11pub struct Deserializer<'de> {
12    input: &'de str,
13    tuple_rest: usize,
14    inside_seq: bool,
15}
16
17#[expect(clippy::should_implement_trait)]
18impl<'de> Deserializer<'de> {
19    pub fn from_str(input: &'de str) -> Self {
20        Deserializer {
21            input,
22            tuple_rest: 0,
23            inside_seq: false,
24        }
25    }
26}
27
28pub fn from_str<'a, T: Deserialize<'a>>(s: &'a str) -> Result<T> {
29    let mut deserializer = Deserializer::from_str(s);
30    let t = T::deserialize(&mut deserializer)?;
31    if deserializer.is_ended() {
32        Ok(t)
33    } else {
34        Err(Error::TrailingCharacters)
35    }
36}
37
38impl<'de> Deserializer<'de> {
39    fn is_ended(&self) -> bool {
40        self.input
41            .lines()
42            .all(|s| s.starts_with('#') || s.trim().is_empty())
43    }
44}
45
46impl<'de> de::Deserializer<'de> for &mut Deserializer<'de> {
47    type Error = Error;
48
49    fn deserialize_any<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value> {
50        Err(Error::FileCannotBeScalar)
51    }
52
53    forward_to_deserialize_any! {
54        bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string
55        bytes byte_buf option unit unit_struct newtype_struct
56        enum identifier ignored_any
57    }
58
59    fn deserialize_seq<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
60        if self.inside_seq || self.tuple_rest > 1 {
61            return Err(Error::FileCannotBeMultiLevelSequence);
62        }
63        visitor.visit_seq(self)
64    }
65
66    fn deserialize_tuple<V: Visitor<'de>>(self, len: usize, visitor: V) -> Result<V::Value> {
67        if self.inside_seq || self.tuple_rest > 1 {
68            return Err(Error::FileCannotBeMultiLevelSequence);
69        }
70        self.tuple_rest = len;
71        visitor.visit_seq(self)
72    }
73
74    fn deserialize_tuple_struct<V: Visitor<'de>>(
75        self,
76        _name: &'static str,
77        len: usize,
78        visitor: V,
79    ) -> Result<V::Value> {
80        self.deserialize_tuple(len, visitor)
81    }
82
83    fn deserialize_map<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
84        let mut deser = DeserializerStanza::from_str(self.input);
85        let v = deser.deserialize_map(visitor);
86        self.input = deser.into_inner();
87        v
88    }
89
90    fn deserialize_struct<V: Visitor<'de>>(
91        self,
92        _name: &'static str,
93        _fields: &'static [&'static str],
94        visitor: V,
95    ) -> Result<V::Value> {
96        self.deserialize_map(visitor)
97    }
98}
99impl<'de> SeqAccess<'de> for &mut Deserializer<'de> {
100    type Error = Error;
101
102    fn next_element_seed<T: DeserializeSeed<'de>>(&mut self, seed: T) -> Result<Option<T::Value>> {
103        if self.tuple_rest > 0 {
104            self.tuple_rest -= 1;
105        }
106        if self.is_ended() {
107            self.tuple_rest = 0;
108            Ok(None)
109        } else {
110            seed.deserialize(&mut **self).map(Some)
111        }
112    }
113}
114
115#[cfg(test)]
116mod tests {
117    use std::collections::HashMap;
118
119    use serde_derive::Deserialize;
120
121    use super::*;
122
123    #[derive(Deserialize, PartialEq, Debug)]
124    struct Point {
125        x: String,
126        y: String,
127    }
128
129    #[test]
130    fn test_simple_struct() {
131        let deb822 = "x: my-x\ny: MY YYYYY";
132        let pt_deb822: Point = from_str(deb822).unwrap();
133        let expected = Point {
134            x: "my-x".into(),
135            y: "MY YYYYY".into(),
136        };
137        assert_eq!(expected, pt_deb822);
138    }
139
140    #[test]
141    fn test_vec_struct() {
142        let deb822 = "x: my-x\ny: MY YYYYY\n\ny: zyx\n#adf\n 123\nx: abc\n\n";
143        let pt_deb822: Vec<Point> = from_str(deb822).unwrap();
144        let expected1 = Point {
145            x: "my-x".into(),
146            y: "MY YYYYY".into(),
147        };
148        let expected2 = Point {
149            x: "abc".into(),
150            y: "zyx\n123".into(),
151        };
152        assert_eq!(vec![expected1, expected2], pt_deb822);
153    }
154
155    #[test]
156    fn test_simple_map() {
157        let deb822 = "x: my-x\ny: MY YYYYY";
158        let pt_deb822: HashMap<String, String> = from_str(deb822).unwrap();
159        let expected: HashMap<String, String> =
160            [("x".into(), "my-x".into()), ("y".into(), "MY YYYYY".into())]
161                .into_iter()
162                .collect();
163        assert_eq!(expected, pt_deb822);
164
165        let pt_deb822: HashMap<&str, String> = from_str(deb822).unwrap();
166        let expected: HashMap<&str, String> = [("x", "my-x".into()), ("y", "MY YYYYY".into())]
167            .into_iter()
168            .collect();
169        assert_eq!(expected, pt_deb822);
170    }
171
172    #[test]
173    fn test_simple_enum() {
174        #[derive(Deserialize, PartialEq, Debug)]
175        enum Val {
176            A,
177            B,
178            C,
179        }
180
181        let deb822 = "x: A";
182        let pt_deb822: HashMap<String, Val> = from_str(deb822).unwrap();
183        let expected: HashMap<String, Val> = [("x".into(), Val::A)].into_iter().collect();
184        assert_eq!(expected, pt_deb822);
185    }
186
187    #[test]
188    fn test_ignore_supplement_field() {
189        let deb822 = "x: my-x\ny: MY YYYYY\nz: New Field";
190        let pt_deb822: Point = from_str(deb822).unwrap();
191        let expected = Point {
192            x: "my-x".into(),
193            y: "MY YYYYY".into(),
194        };
195        assert_eq!(expected, pt_deb822);
196    }
197}