1use std::{
41 collections::BTreeMap,
42 error,
43 fmt::{self, Display},
44 marker::PhantomData,
45 num,
46 str,
47 str::{FromStr, ParseBoolError},
48};
49
50use serde::{
51 Deserialize,
52 de::{self, DeserializeOwned, IntoDeserializer, Visitor, value::SeqDeserializer},
53 forward_to_deserialize_any,
54};
55use winnow::Parser;
56
57use super::parser::{Item, ini_file};
58
59#[derive(Clone, Debug)]
60pub enum Error {
61 Parse(String),
65
66 Custom(String),
70
71 UnexpectedEof,
75
76 InvalidState,
80}
81
82impl From<num::ParseIntError> for Error {
83 fn from(e: num::ParseIntError) -> Self {
84 Error::Custom(e.to_string())
85 }
86}
87
88impl From<num::ParseFloatError> for Error {
89 fn from(e: num::ParseFloatError) -> Self {
90 Error::Custom(e.to_string())
91 }
92}
93
94impl From<ParseBoolError> for Error {
95 fn from(e: ParseBoolError) -> Self {
96 Error::Custom(e.to_string())
97 }
98}
99
100impl Display for Error {
101 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102 match self {
103 Error::Custom(msg) => write!(f, "{msg}"),
104 Error::Parse(msg) => write!(f, "{msg}"),
105 Error::UnexpectedEof => write!(f, "internal consistency error: unexpected EOF"),
106 Error::InvalidState => write!(f, "internal consistency error"),
107 }
108 }
109}
110
111impl error::Error for Error {
112 fn description(&self) -> &str {
113 "deserialization error"
114 }
115}
116
117impl de::Error for Error {
118 fn custom<T: Display>(msg: T) -> Self {
119 Error::Custom(msg.to_string())
120 }
121}
122
123pub type Result<T> = std::result::Result<T, Error>;
124
125impl IntoDeserializer<'_, Error> for Item {
126 type Deserializer = ItemDeserializer<Error>;
127
128 fn into_deserializer(self) -> Self::Deserializer {
129 ItemDeserializer::new(self)
130 }
131}
132
133struct Deserializer {
135 input: BTreeMap<String, Item>,
136}
137
138impl<'a> TryFrom<&'a str> for Deserializer {
145 type Error = Error;
146
147 fn try_from(contents: &'a str) -> Result<Self> {
148 let input = ini_file
149 .parse(contents)
150 .map_err(|err| Error::Custom(format!("{err}")))?;
151
152 Ok(Deserializer { input })
153 }
154}
155
156impl<'de> de::Deserializer<'de> for &mut Deserializer {
157 type Error = Error;
158
159 fn is_human_readable(&self) -> bool {
160 true
161 }
162
163 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
164 where
165 V: serde::de::Visitor<'de>,
166 {
167 visitor.visit_map(self.input.clone().into_deserializer())
168 }
169
170 forward_to_deserialize_any! {
171 bool i8 i16 i32 i64 i128 u8 u16 u32 u64 u128 f32 f64 char str string bytes
172 byte_buf unit unit_struct newtype_struct tuple_struct
173 struct identifier ignored_any enum option map tuple seq
174 }
175}
176
177pub struct ItemDeserializer<E> {
178 item: Item,
179 marker: PhantomData<E>,
180}
181
182impl<E> ItemDeserializer<E> {
183 pub fn new(item: Item) -> Self {
184 ItemDeserializer {
185 item,
186 marker: PhantomData,
187 }
188 }
189}
190
191impl<'de> de::Deserializer<'de> for ItemDeserializer<Error> {
192 type Error = Error;
193
194 fn is_human_readable(&self) -> bool {
195 true
196 }
197
198 fn deserialize_any<V>(self, visitor: V) -> Result<V::Value>
199 where
200 V: serde::de::Visitor<'de>,
201 {
202 match &self.item {
203 Item::Value(value) => visitor.visit_str(value),
204 Item::List(vec) => visitor.visit_seq(vec.clone().into_deserializer()),
205 }
206 }
207
208 fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
209 where
210 V: serde::de::Visitor<'de>,
211 {
212 let de = match self.item {
214 Item::Value(value) => {
216 SeqDeserializer::new(vec![SeqItemDeserializer(value.clone())].into_iter())
217 }
218 Item::List(values) => {
220 let mut items = Vec::new();
221 for value in values.clone() {
222 items.push(SeqItemDeserializer(value.clone()));
223 }
224 SeqDeserializer::new(items.into_iter())
225 }
226 };
227 visitor
228 .visit_seq(de)
229 .map_err(|e| Error::Custom(e.to_string()))
230 }
231
232 fn deserialize_bool<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
233 visitor.visit_bool(FromStr::from_str(self.item.value_or_error()?)?)
234 }
235
236 fn deserialize_i8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
237 visitor.visit_i8(FromStr::from_str(self.item.value_or_error()?)?)
238 }
239
240 fn deserialize_i16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
241 visitor.visit_i16(FromStr::from_str(self.item.value_or_error()?)?)
242 }
243
244 fn deserialize_i32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
245 visitor.visit_i32(FromStr::from_str(self.item.value_or_error()?)?)
246 }
247
248 fn deserialize_i64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
249 visitor.visit_i64(FromStr::from_str(self.item.value_or_error()?)?)
250 }
251
252 fn deserialize_i128<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
253 visitor.visit_i128(FromStr::from_str(self.item.value_or_error()?)?)
254 }
255
256 fn deserialize_u8<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
257 visitor.visit_u8(FromStr::from_str(self.item.value_or_error()?)?)
258 }
259
260 fn deserialize_u16<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
261 visitor.visit_u16(FromStr::from_str(self.item.value_or_error()?)?)
262 }
263
264 fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
265 visitor.visit_u32(FromStr::from_str(self.item.value_or_error()?)?)
266 }
267
268 fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
269 visitor.visit_u64(FromStr::from_str(self.item.value_or_error()?)?)
270 }
271
272 fn deserialize_u128<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
273 visitor.visit_u128(FromStr::from_str(self.item.value_or_error()?)?)
274 }
275
276 fn deserialize_f32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
277 visitor.visit_f32(FromStr::from_str(self.item.value_or_error()?)?)
278 }
279
280 fn deserialize_f64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
281 visitor.visit_f64(FromStr::from_str(self.item.value_or_error()?)?)
282 }
283
284 forward_to_deserialize_any! {
285 char str string bytes
286 byte_buf unit unit_struct newtype_struct tuple tuple_struct
287 struct identifier ignored_any enum option map
288 }
289}
290
291struct SeqItemDeserializer(String);
293
294impl<'de> de::Deserializer<'de> for SeqItemDeserializer {
295 type Error = serde::de::value::Error;
296
297 fn deserialize_any<V>(self, visitor: V) -> std::result::Result<V::Value, Self::Error>
298 where
299 V: Visitor<'de>,
300 {
301 visitor.visit_str(&self.0)
302 }
303
304 fn deserialize_u64<V>(self, visitor: V) -> std::result::Result<V::Value, Self::Error>
305 where
306 V: Visitor<'de>,
307 {
308 visitor.visit_u64(self.0.parse().unwrap())
309 }
310
311 forward_to_deserialize_any! {
312 bool i8 i16 i32 i64 u8 u16 u32 f32 f64 char str string bytes
313 byte_buf unit unit_struct newtype_struct tuple tuple_struct
314 map struct identifier ignored_any enum option seq
315 }
316}
317
318impl IntoDeserializer<'_> for SeqItemDeserializer {
319 type Deserializer = SeqItemDeserializer;
320 fn into_deserializer(self) -> Self::Deserializer {
321 SeqItemDeserializer(self.0)
322 }
323}
324
325pub fn from_str<T: DeserializeOwned>(s: &str) -> Result<T> {
326 let mut de = Deserializer::try_from(s)?;
327 let value = Deserialize::deserialize(&mut de)?;
328 Ok(value)
329}
330
331#[cfg(test)]
332mod tests {
333 use serde::Deserialize;
334
335 use super::*;
336
337 #[derive(Clone, Debug, Default, Deserialize, PartialEq)]
338 struct TestModel {
339 builddate: i64,
340 builddir: String,
341 buildenv: Vec<String>,
342 format: String,
343 installed: Vec<String>,
344 options: Vec<String>,
345 packager: String,
346 pkgarch: String,
347 pkgbase: String,
348 pkgbuild_sha256sum: String,
349 pkgname: String,
350 pkgver: String,
351 }
352
353 const TEST_INPUT: &str = "
354 builddate = 1
355 builddir = /build
356 buildenv = ccache
357 buildenv = color
358 format = 1
359 installed = bar-1.2.3-1-any
360 installed = beh-2.2.3-4-any
361 options = lto
362 options = !strip
363 packager = Foobar McFooface <foobar@mcfooface.org>
364 pkgarch = any
365 pkgbase = foo
366 pkgbuild_sha256sum = b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c
367 pkgname = foo
368 pkgver = 1:1.0.0-1";
369
370 fn expected() -> TestModel {
371 TestModel {
372 builddate: 1,
373 builddir: "/build".into(),
374 buildenv: vec!["ccache".into(), "color".into()],
375 format: "1".into(),
376 installed: vec!["bar-1.2.3-1-any".into(), "beh-2.2.3-4-any".into()],
377 options: vec!["lto".into(), "!strip".into()],
378 packager: "Foobar McFooface <foobar@mcfooface.org>".into(),
379 pkgarch: "any".into(),
380 pkgbase: "foo".into(),
381 pkgbuild_sha256sum: "b5bb9d8014a0f9b1d61e21e796d78dccdf1352f23cd32812f4850b878ae4944c"
382 .into(),
383 pkgname: "foo".into(),
384 pkgver: "1:1.0.0-1".into(),
385 }
386 }
387
388 #[test]
389 fn deserialize() {
390 let v = from_str::<TestModel>(TEST_INPUT).unwrap();
391 assert_eq!(expected(), v);
392 }
393
394 #[derive(Clone, Debug, Default, Deserialize, PartialEq)]
395 struct TypeTestModel {
396 i64: i64,
397 i32: i32,
398 u64: u64,
399 u32: u32,
400 list: Vec<String>,
401 u64_list: Vec<u64>,
402 bool: bool,
403 }
404
405 const TYPE_TEST_INPUT: &str = "
406 i64 = -64
407 i32 = -32
408 u64 = 64
409 u32 = 32
410 list = a
411 list = b
412 list = c
413 u64_list = 1
414 u64_list = 2
415 u64_list = 3
416 bool = true";
417 #[test]
418 fn deserialize_types() {
419 let value = from_str::<TypeTestModel>(TYPE_TEST_INPUT).unwrap();
420 assert_eq!(
421 TypeTestModel {
422 i64: -64,
423 i32: -32,
424 u64: 64,
425 u32: 32,
426 list: vec!["a".to_string(), "b".to_string(), "c".to_string()],
427 u64_list: vec![1, 2, 3],
428 bool: true
429 },
430 value
431 );
432 }
433
434 #[derive(Clone, Debug, Default, Deserialize, PartialEq)]
435 struct FlattenTestModelInner {
436 u64_list: Vec<u64>,
437 u64: u64,
438 }
439
440 #[derive(Clone, Debug, Default, Deserialize, PartialEq)]
441 struct FlattenTestModel {
442 #[serde(flatten)]
443 flattened: FlattenTestModelInner,
444 }
445
446 const FLATTEN_TEST_INPUT: &str = "
447 u64 = 42
448 u64_list = 1";
449
450 #[test]
461 fn deserialize_with_flatten() {
462 let expected = FlattenTestModelInner {
463 u64: 42,
464 u64_list: vec![1],
465 };
466
467 let value = from_str::<FlattenTestModelInner>(FLATTEN_TEST_INPUT).unwrap();
468 assert_eq!(expected, value);
469
470 let value = from_str::<FlattenTestModel>(FLATTEN_TEST_INPUT);
471 assert!(value.is_err());
472 }
473}