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}