serde_aco/
de.rs

1// Copyright 2024 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::collections::HashMap;
16
17use serde::de::{self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, VariantAccess, Visitor};
18use serde::Deserialize;
19
20use crate::error::{Error, Result};
21
22#[derive(Debug)]
23pub struct Deserializer<'s, 'o> {
24    input: &'s str,
25    objects: Option<&'o HashMap<&'s str, &'s str>>,
26    top_level: bool,
27    key: &'s str,
28}
29
30impl<'s, 'o, 'a> de::Deserializer<'s> for &'a mut Deserializer<'s, 'o> {
31    type Error = Error;
32
33    fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>
34    where
35        V: Visitor<'s>,
36    {
37        Err(Error::UnknownType)
38    }
39
40    fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>
41    where
42        V: Visitor<'s>,
43    {
44        let s = self.consume_input();
45        match s {
46            "on" | "true" => visitor.visit_bool(true),
47            "off" | "false" => visitor.visit_bool(false),
48            _ => Err(Error::ExpectedBool),
49        }
50    }
51
52    fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>
53    where
54        V: Visitor<'s>,
55    {
56        visitor.visit_i8(self.parse_signed()?)
57    }
58
59    fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>
60    where
61        V: Visitor<'s>,
62    {
63        visitor.visit_i16(self.parse_signed()?)
64    }
65
66    fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>
67    where
68        V: Visitor<'s>,
69    {
70        visitor.visit_i32(self.parse_signed()?)
71    }
72
73    fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>
74    where
75        V: Visitor<'s>,
76    {
77        visitor.visit_i64(self.parse_signed()?)
78    }
79
80    fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>
81    where
82        V: Visitor<'s>,
83    {
84        visitor.visit_u8(self.parse_unsigned()?)
85    }
86
87    fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>
88    where
89        V: Visitor<'s>,
90    {
91        visitor.visit_u16(self.parse_unsigned()?)
92    }
93
94    fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>
95    where
96        V: Visitor<'s>,
97    {
98        visitor.visit_u32(self.parse_unsigned()?)
99    }
100
101    fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>
102    where
103        V: Visitor<'s>,
104    {
105        visitor.visit_u64(self.parse_unsigned()?)
106    }
107
108    fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>
109    where
110        V: Visitor<'s>,
111    {
112        let s = self.consume_input();
113        visitor.visit_f32(s.parse().map_err(|_| Error::ExpectedFloat)?)
114    }
115
116    fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>
117    where
118        V: Visitor<'s>,
119    {
120        let s = self.consume_input();
121        visitor.visit_f64(s.parse().map_err(|_| Error::ExpectedFloat)?)
122    }
123
124    fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>
125    where
126        V: Visitor<'s>,
127    {
128        self.deserialize_str(visitor)
129    }
130
131    fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>
132    where
133        V: Visitor<'s>,
134    {
135        if self.top_level {
136            visitor.visit_borrowed_str(self.consume_all())
137        } else {
138            let id = self.consume_input();
139            visitor.visit_borrowed_str(self.deref_id(id)?)
140        }
141    }
142
143    fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>
144    where
145        V: Visitor<'s>,
146    {
147        self.deserialize_str(visitor)
148    }
149
150    fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>
151    where
152        V: Visitor<'s>,
153    {
154        self.deserialize_seq(visitor)
155    }
156
157    fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>
158    where
159        V: Visitor<'s>,
160    {
161        self.deserialize_bytes(visitor)
162    }
163
164    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
165    where
166        V: Visitor<'s>,
167    {
168        let id = self.consume_input();
169        let s = self.deref_id(id)?;
170        if id.starts_with("id_") && s.is_empty() {
171            visitor.visit_none()
172        } else {
173            let mut sub_de = Deserializer { input: s, ..*self };
174            visitor.visit_some(&mut sub_de)
175        }
176    }
177
178    fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>
179    where
180        V: Visitor<'s>,
181    {
182        let s = self.consume_input();
183        if s.is_empty() {
184            visitor.visit_unit()
185        } else {
186            Err(Error::ExpectedUnit)
187        }
188    }
189
190    fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
191    where
192        V: Visitor<'s>,
193    {
194        self.deserialize_unit(visitor)
195    }
196
197    fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>
198    where
199        V: Visitor<'s>,
200    {
201        visitor.visit_newtype_struct(self)
202    }
203
204    fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>
205    where
206        V: Visitor<'s>,
207    {
208        self.deserialize_nested(|de| visitor.visit_seq(CommaSeparated::new(de)))
209    }
210
211    fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>
212    where
213        V: Visitor<'s>,
214    {
215        self.deserialize_seq(visitor)
216    }
217
218    fn deserialize_tuple_struct<V>(
219        self,
220        _name: &'static str,
221        _len: usize,
222        visitor: V,
223    ) -> Result<V::Value>
224    where
225        V: Visitor<'s>,
226    {
227        self.deserialize_seq(visitor)
228    }
229
230    fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>
231    where
232        V: Visitor<'s>,
233    {
234        self.deserialize_nested(|de| visitor.visit_map(CommaSeparated::new(de)))
235    }
236
237    fn deserialize_struct<V>(
238        self,
239        _name: &'static str,
240        _fields: &'static [&'static str],
241        visitor: V,
242    ) -> Result<V::Value>
243    where
244        V: Visitor<'s>,
245    {
246        self.deserialize_map(visitor)
247    }
248
249    fn deserialize_enum<V>(
250        self,
251        _name: &'static str,
252        _variants: &'static [&'static str],
253        visitor: V,
254    ) -> Result<V::Value>
255    where
256        V: Visitor<'s>,
257    {
258        self.deserialize_nested(|de| visitor.visit_enum(Enum::new(de)))
259    }
260
261    fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>
262    where
263        V: Visitor<'s>,
264    {
265        visitor.visit_borrowed_str(self.consume_input())
266    }
267
268    fn deserialize_ignored_any<V>(self, _visitor: V) -> Result<V::Value>
269    where
270        V: Visitor<'s>,
271    {
272        Err(Error::Ignored(self.key.to_owned()))
273    }
274}
275
276impl<'s, 'o> Deserializer<'s, 'o> {
277    pub fn from_args(input: &'s str, objects: &'o HashMap<&'s str, &'s str>) -> Self {
278        Deserializer {
279            input,
280            objects: Some(objects),
281            top_level: true,
282            key: "",
283        }
284    }
285
286    pub fn from_arg(input: &'s str) -> Self {
287        Deserializer {
288            input,
289            objects: None,
290            top_level: true,
291            key: "",
292        }
293    }
294
295    fn end(&self) -> Result<()> {
296        if self.input.is_empty() {
297            Ok(())
298        } else {
299            Err(Error::Trailing(self.input.to_owned()))
300        }
301    }
302
303    fn deserialize_nested<F, V>(&mut self, f: F) -> Result<V>
304    where
305        F: FnOnce(&mut Self) -> Result<V>,
306    {
307        let mut sub_de;
308        let de = if !self.top_level {
309            let id = self.consume_input();
310            let sub_input = self.deref_id(id)?;
311            sub_de = Deserializer {
312                input: sub_input,
313                ..*self
314            };
315            &mut sub_de
316        } else {
317            self.top_level = false;
318            self
319        };
320        let val = f(de)?;
321        de.end()?;
322        Ok(val)
323    }
324
325    fn consume_input_until(&mut self, end: char) -> Option<&'s str> {
326        let len = self.input.find(end)?;
327        let s = &self.input[..len];
328        self.input = &self.input[len + end.len_utf8()..];
329        Some(s)
330    }
331
332    fn consume_all(&mut self) -> &'s str {
333        let s = self.input;
334        self.input = "";
335        s
336    }
337
338    fn consume_input(&mut self) -> &'s str {
339        match self.consume_input_until(',') {
340            Some(s) => s,
341            None => self.consume_all(),
342        }
343    }
344
345    fn deref_id(&self, id: &'s str) -> Result<&'s str> {
346        if id.starts_with("id_") {
347            if let Some(s) = self.objects.and_then(|objects| objects.get(id)) {
348                Ok(s)
349            } else {
350                Err(Error::IdNotFound(id.to_owned()))
351            }
352        } else {
353            Ok(id)
354        }
355    }
356
357    fn parse_unsigned<T>(&mut self) -> Result<T>
358    where
359        T: TryFrom<u64>,
360    {
361        let s = self.consume_input();
362        let (num, shift) = if let Some((num, "")) = s.split_once(['k', 'K']) {
363            (num, 10)
364        } else if let Some((num, "")) = s.split_once(['m', 'M']) {
365            (num, 20)
366        } else if let Some((num, "")) = s.split_once(['g', 'G']) {
367            (num, 30)
368        } else if let Some((num, "")) = s.split_once(['t', 'T']) {
369            (num, 40)
370        } else {
371            (s, 0)
372        };
373        let n = if let Some(num_h) = num.strip_prefix("0x") {
374            u64::from_str_radix(num_h, 16)
375        } else if let Some(num_o) = num.strip_prefix("0o") {
376            u64::from_str_radix(num_o, 8)
377        } else if let Some(num_b) = num.strip_prefix("0b") {
378            u64::from_str_radix(num_b, 2)
379        } else {
380            num.parse::<u64>()
381        }
382        .map_err(|_| Error::ExpectedInteger)?;
383
384        let shifted_n = n.checked_shl(shift).ok_or(Error::Overflow)?;
385
386        T::try_from(shifted_n).map_err(|_| Error::Overflow)
387    }
388
389    fn parse_signed<T>(&mut self) -> Result<T>
390    where
391        T: TryFrom<i64>,
392    {
393        let i = if self.input.starts_with('-') {
394            let s = self.consume_input();
395            s.parse().map_err(|_| Error::ExpectedInteger)
396        } else {
397            let n = self.parse_unsigned::<u64>()?;
398            i64::try_from(n).map_err(|_| Error::Overflow)
399        }?;
400        T::try_from(i).map_err(|_| Error::Overflow)
401    }
402}
403
404pub fn from_args<'s, 'o, T>(s: &'s str, objects: &'o HashMap<&'s str, &'s str>) -> Result<T>
405where
406    T: Deserialize<'s>,
407{
408    let mut deserializer = Deserializer::from_args(s, objects);
409    let value = T::deserialize(&mut deserializer)?;
410    deserializer.end()?;
411    Ok(value)
412}
413
414pub fn from_arg<'s, T>(s: &'s str) -> Result<T>
415where
416    T: Deserialize<'s>,
417{
418    let mut deserializer = Deserializer::from_arg(s);
419    let value = T::deserialize(&mut deserializer)?;
420    deserializer.end()?;
421    Ok(value)
422}
423
424struct CommaSeparated<'a, 's: 'a, 'o: 'a> {
425    de: &'a mut Deserializer<'s, 'o>,
426}
427
428impl<'a, 's, 'o> CommaSeparated<'a, 's, 'o> {
429    fn new(de: &'a mut Deserializer<'s, 'o>) -> Self {
430        CommaSeparated { de }
431    }
432}
433
434impl<'a, 's, 'o> SeqAccess<'s> for CommaSeparated<'a, 's, 'o> {
435    type Error = Error;
436    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>
437    where
438        T: DeserializeSeed<'s>,
439    {
440        if self.de.input.is_empty() {
441            return Ok(None);
442        }
443        seed.deserialize(&mut *self.de).map(Some)
444    }
445}
446
447impl<'a, 's, 'o> MapAccess<'s> for CommaSeparated<'a, 's, 'o> {
448    type Error = Error;
449
450    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>
451    where
452        K: DeserializeSeed<'s>,
453    {
454        if self.de.input.is_empty() {
455            return Ok(None);
456        }
457        let Some(key) = self.de.consume_input_until('=') else {
458            return Err(Error::ExpectedMapEq);
459        };
460        if key.contains(',') {
461            return Err(Error::ExpectedMapEq);
462        }
463        self.de.key = key;
464        let mut sub_de = Deserializer {
465            input: key,
466            key: "",
467            ..*self.de
468        };
469        seed.deserialize(&mut sub_de).map(Some)
470    }
471
472    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>
473    where
474        V: DeserializeSeed<'s>,
475    {
476        seed.deserialize(&mut *self.de)
477    }
478}
479
480struct Enum<'a, 's: 'a, 'o: 'a> {
481    de: &'a mut Deserializer<'s, 'o>,
482}
483
484impl<'a, 's, 'o> Enum<'a, 's, 'o> {
485    fn new(de: &'a mut Deserializer<'s, 'o>) -> Self {
486        Enum { de }
487    }
488}
489
490impl<'a, 's, 'o> EnumAccess<'s> for Enum<'a, 's, 'o> {
491    type Error = Error;
492    type Variant = Self;
493
494    fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>
495    where
496        V: DeserializeSeed<'s>,
497    {
498        let val = seed.deserialize(&mut *self.de)?;
499        Ok((val, self))
500    }
501}
502
503impl<'a, 's, 'o> VariantAccess<'s> for Enum<'a, 's, 'o> {
504    type Error = Error;
505
506    fn unit_variant(self) -> Result<()> {
507        Ok(())
508    }
509
510    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>
511    where
512        T: DeserializeSeed<'s>,
513    {
514        self.de.top_level = true;
515        seed.deserialize(self.de)
516    }
517
518    fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>
519    where
520        V: Visitor<'s>,
521    {
522        visitor.visit_seq(CommaSeparated::new(self.de))
523    }
524
525    fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>
526    where
527        V: Visitor<'s>,
528    {
529        visitor.visit_map(CommaSeparated::new(self.de))
530    }
531}
532
533#[cfg(test)]
534mod test {
535    use std::collections::HashMap;
536    use std::marker::PhantomData;
537
538    use assert_matches::assert_matches;
539    use serde::Deserialize;
540    use serde_bytes::{ByteArray, ByteBuf};
541
542    use crate::{from_arg, from_args, Error};
543
544    #[test]
545    fn test_option() {
546        assert_matches!(from_arg::<Option<u32>>(""), Err(Error::ExpectedInteger));
547        assert_eq!(from_arg::<Option<u32>>("12").unwrap(), Some(12));
548
549        assert_eq!(from_arg::<Option<&'static str>>("").unwrap(), Some(""));
550        assert_eq!(
551            from_args::<Option<&'static str>>("id_1", &HashMap::from([("id_1", "")])).unwrap(),
552            None
553        );
554        assert_eq!(from_arg::<Option<&'static str>>("12").unwrap(), Some("12"));
555        assert_matches!(
556            from_arg::<Option<&'static str>>("id_1"),
557            Err(Error::IdNotFound(id)) if id == "id_1"
558        );
559        assert_eq!(
560            from_args::<Option<&'static str>>("id_1", &HashMap::from([("id_1", "id_2")])).unwrap(),
561            Some("id_2")
562        );
563
564        let map_none = HashMap::from([("id_none", "")]);
565        assert_eq!(from_arg::<Vec<Option<u32>>>("").unwrap(), vec![]);
566        assert_eq!(
567            from_args::<Vec<Option<u32>>>("id_none,", &map_none).unwrap(),
568            vec![None]
569        );
570        assert_eq!(from_arg::<Vec<Option<u32>>>("1,").unwrap(), vec![Some(1)]);
571        assert_eq!(
572            from_arg::<Vec<Option<u32>>>("1,2,").unwrap(),
573            vec![Some(1), Some(2)]
574        );
575        assert_eq!(
576            from_args::<Vec<Option<u32>>>("1,2,id_none,", &map_none).unwrap(),
577            vec![Some(1), Some(2), None]
578        );
579        assert_eq!(
580            from_args::<Vec<Option<u32>>>("id_none,2", &map_none).unwrap(),
581            vec![None, Some(2)]
582        );
583    }
584
585    #[test]
586    fn test_unit() {
587        assert!(from_arg::<()>("").is_ok());
588        assert_matches!(from_arg::<()>("unit"), Err(Error::ExpectedUnit));
589
590        assert!(from_arg::<PhantomData<u8>>("").is_ok());
591        assert_matches!(from_arg::<PhantomData<u8>>("12"), Err(Error::ExpectedUnit));
592
593        #[derive(Debug, Deserialize, PartialEq, Eq)]
594        struct Param {
595            p: PhantomData<u8>,
596        }
597        assert_eq!(from_arg::<Param>("p=").unwrap(), Param { p: PhantomData });
598        assert_matches!(from_arg::<Param>("p=1,"), Err(Error::ExpectedUnit));
599    }
600
601    #[test]
602    fn test_numbers() {
603        assert_eq!(from_arg::<i8>("0").unwrap(), 0);
604        assert_eq!(from_arg::<i8>("1").unwrap(), 1);
605        assert_eq!(from_arg::<i8>("127").unwrap(), 127);
606        assert_matches!(from_arg::<i8>("128"), Err(Error::Overflow));
607        assert_eq!(from_arg::<i8>("-1").unwrap(), -1);
608        assert_eq!(from_arg::<i8>("-128").unwrap(), -128);
609        assert_matches!(from_arg::<i8>("-129"), Err(Error::Overflow));
610
611        assert_eq!(from_arg::<i16>("1k").unwrap(), 1 << 10);
612
613        assert_eq!(from_arg::<i32>("1g").unwrap(), 1 << 30);
614        assert_matches!(from_arg::<i32>("2g"), Err(Error::Overflow));
615        assert_matches!(from_arg::<i32>("0xffffffff"), Err(Error::Overflow));
616
617        assert_eq!(from_arg::<i64>("0xffffffff").unwrap(), 0xffffffff);
618
619        assert_matches!(from_arg::<i64>("gg"), Err(Error::ExpectedInteger));
620
621        assert_matches!(from_arg::<f32>("0.125").unwrap(), 0.125);
622
623        assert_matches!(from_arg::<f64>("-0.5").unwrap(), -0.5);
624    }
625
626    #[test]
627    fn test_char() {
628        assert_eq!(from_arg::<char>("=").unwrap(), '=');
629        assert_eq!(from_arg::<char>("a").unwrap(), 'a');
630        assert_matches!(from_arg::<char>("an"), Err(Error::Message(_)));
631
632        assert_eq!(
633            from_args::<HashMap<char, char>>(
634                "id_1=a,b=id_2,id_2=id_1",
635                &HashMap::from([("id_1", ","), ("id_2", "="),])
636            )
637            .unwrap(),
638            HashMap::from([(',', 'a'), ('b', '='), ('=', ',')])
639        );
640    }
641
642    #[test]
643    fn test_bytes() {
644        assert!(from_arg::<ByteArray<6>>("0xea,0xd7,0xa8,0xe8,0xc6,0x2f").is_ok());
645        assert_matches!(
646            from_arg::<ByteArray<5>>("0xea,0xd7,0xa8,0xe8,0xc6,0x2f"),
647            Err(Error::Trailing(t)) if t == "0x2f"
648        );
649        assert_eq!(
650            from_arg::<ByteBuf>("0xea,0xd7,0xa8,0xe8,0xc6,0x2f").unwrap(),
651            vec![0xea, 0xd7, 0xa8, 0xe8, 0xc6, 0x2f]
652        );
653
654        #[derive(Debug, Deserialize, Eq, PartialEq)]
655        struct MacAddr {
656            addr: ByteArray<6>,
657        }
658        assert_eq!(
659            from_args::<MacAddr>(
660                "addr=id_addr",
661                &HashMap::from([("id_addr", "0xea,0xd7,0xa8,0xe8,0xc6,0x2f")])
662            )
663            .unwrap(),
664            MacAddr {
665                addr: ByteArray::new([0xea, 0xd7, 0xa8, 0xe8, 0xc6, 0x2f])
666            }
667        )
668    }
669
670    #[test]
671    fn test_string() {
672        assert_eq!(
673            from_arg::<String>("test,s=1,c").unwrap(),
674            "test,s=1,c".to_owned()
675        );
676        assert_eq!(
677            from_args::<HashMap<String, String>>(
678                "cmd=id_1",
679                &HashMap::from([("id_1", "console=ttyS0")])
680            )
681            .unwrap(),
682            HashMap::from([("cmd".to_owned(), "console=ttyS0".to_owned())])
683        )
684    }
685
686    #[test]
687    fn test_seq() {
688        assert_eq!(from_arg::<Vec<u32>>("").unwrap(), vec![]);
689
690        assert_eq!(from_arg::<Vec<u32>>("1").unwrap(), vec![1]);
691
692        assert_eq!(from_arg::<Vec<u32>>("1,2,3,4").unwrap(), vec![1, 2, 3, 4]);
693
694        assert_eq!(from_arg::<(u16, bool)>("12,true").unwrap(), (12, true));
695        assert_matches!(
696            from_arg::<(u16, bool)>("12,true,false"),
697            Err(Error::Trailing(t)) if t == "false"
698        );
699
700        #[derive(Debug, Deserialize, PartialEq, Eq)]
701        struct TestStruct {
702            a: (u16, bool),
703        }
704        assert_eq!(
705            from_args::<TestStruct>("a=id_a", &HashMap::from([("id_a", "12,true")])).unwrap(),
706            TestStruct { a: (12, true) }
707        );
708        assert_matches!(
709            from_args::<TestStruct>("a=id_a", &HashMap::from([("id_a", "12,true,true")])),
710            Err(Error::Trailing(t)) if t == "true"
711        );
712
713        #[derive(Debug, Deserialize, PartialEq, Eq)]
714        struct Node {
715            #[serde(default)]
716            name: String,
717            #[serde(default)]
718            start: u64,
719            size: u64,
720        }
721        #[derive(Debug, Deserialize, PartialEq, Eq)]
722        struct Numa {
723            nodes: Vec<Node>,
724        }
725
726        assert_eq!(
727            from_args::<Numa>(
728                "nodes=id_nodes",
729                &HashMap::from([
730                    ("id_nodes", "id_node1,id_node2"),
731                    ("id_node1", "name=a,start=0,size=2g"),
732                    ("id_node2", "name=b,start=4g,size=2g"),
733                ])
734            )
735            .unwrap(),
736            Numa {
737                nodes: vec![
738                    Node {
739                        name: "a".to_owned(),
740                        start: 0,
741                        size: 2 << 30
742                    },
743                    Node {
744                        name: "b".to_owned(),
745                        start: 4 << 30,
746                        size: 2 << 30
747                    }
748                ]
749            }
750        );
751
752        assert_eq!(
753            from_arg::<Numa>("nodes=size=2g,").unwrap(),
754            Numa {
755                nodes: vec![Node {
756                    name: "".to_owned(),
757                    start: 0,
758                    size: 2 << 30
759                }]
760            }
761        );
762
763        #[derive(Debug, Deserialize, PartialEq, Eq)]
764        struct Info(bool, u32);
765
766        assert_eq!(from_arg::<Info>("true,32").unwrap(), Info(true, 32));
767    }
768
769    #[test]
770    fn test_map() {
771        #[derive(Debug, Deserialize, PartialEq, Eq, Hash)]
772        struct MapKey {
773            name: String,
774            id: u32,
775        }
776        #[derive(Debug, Deserialize, PartialEq, Eq)]
777        struct MapVal {
778            addr: String,
779            info: HashMap<String, String>,
780        }
781
782        assert_matches!(
783            from_arg::<MapKey>("name=a,id=1,addr=b"),
784            Err(Error::Ignored(k)) if k == "addr"
785        );
786        assert_matches!(
787            from_arg::<MapKey>("name=a,addr=b,id=1"),
788            Err(Error::Ignored(k)) if k == "addr"
789        );
790        assert_matches!(from_arg::<MapKey>("name=a,ids=b"), Err(Error::Ignored(k)) if k == "ids");
791        assert_matches!(from_arg::<MapKey>("name=a,ids=b,id=1"), Err(Error::Ignored(k)) if k == "ids");
792
793        assert_eq!(
794            from_args::<HashMap<MapKey, MapVal>>(
795                "id_key1=id_val1,id_key2=id_val2",
796                &HashMap::from([
797                    ("id_key1", "name=gic,id=1"),
798                    ("id_key2", "name=pci,id=2"),
799                    ("id_val1", "addr=0xff,info=id_info1"),
800                    ("id_info1", "compatible=id_gic,msi-controller=,#msi-cells=1"),
801                    ("id_gic", "arm,gic-v3-its"),
802                    ("id_val2", "addr=0xcc,info=compatible=pci-host-ecam-generic"),
803                ])
804            )
805            .unwrap(),
806            HashMap::from([
807                (
808                    MapKey {
809                        name: "gic".to_owned(),
810                        id: 1
811                    },
812                    MapVal {
813                        addr: "0xff".to_owned(),
814                        info: HashMap::from([
815                            ("compatible".to_owned(), "arm,gic-v3-its".to_owned()),
816                            ("msi-controller".to_owned(), "".to_owned()),
817                            ("#msi-cells".to_owned(), "1".to_owned())
818                        ])
819                    }
820                ),
821                (
822                    MapKey {
823                        name: "pci".to_owned(),
824                        id: 2
825                    },
826                    MapVal {
827                        addr: "0xcc".to_owned(),
828                        info: HashMap::from([(
829                            "compatible".to_owned(),
830                            "pci-host-ecam-generic".to_owned()
831                        )])
832                    }
833                )
834            ])
835        );
836    }
837
838    #[test]
839    fn test_nested_struct() {
840        #[derive(Debug, Deserialize, PartialEq, Eq)]
841        struct Param {
842            byte: u8,
843            word: u16,
844            dw: u32,
845            long: u64,
846            enable_1: bool,
847            enable_2: bool,
848            enable_3: Option<bool>,
849            sub: SubParam,
850            addr: Addr,
851        }
852
853        #[derive(Debug, Deserialize, PartialEq, Eq)]
854        struct SubParam {
855            b: u8,
856            w: u16,
857            enable: Option<bool>,
858            s: String,
859        }
860
861        #[derive(Debug, Deserialize, PartialEq, Eq)]
862        struct Addr(u32);
863
864        assert_eq!(
865            from_args::<Param>(
866                "byte=0b10,word=0o7k,dw=0x8m,long=10t,enable_1=on,enable_2=off,sub=id_1,addr=1g",
867                &[("id_1", "b=1,w=2,s=s1,enable=on")].into()
868            )
869            .unwrap(),
870            Param {
871                byte: 0b10,
872                word: 0o7 << 10,
873                dw: 0x8 << 20,
874                long: 10 << 40,
875                enable_1: true,
876                enable_2: false,
877                enable_3: None,
878                sub: SubParam {
879                    b: 1,
880                    w: 2,
881                    enable: Some(true),
882                    s: "s1".to_owned(),
883                },
884                addr: Addr(1 << 30)
885            }
886        );
887        assert_matches!(
888            from_arg::<SubParam>("b=1,w=2,enable,s=s1"),
889            Err(Error::ExpectedMapEq)
890        );
891        assert_matches!(
892            from_arg::<SubParam>("b=1,w=2,s=s1,enable"),
893            Err(Error::ExpectedMapEq)
894        );
895    }
896
897    #[test]
898    fn test_bool() {
899        assert_matches!(from_arg::<bool>("on"), Ok(true));
900        assert_matches!(from_arg::<bool>("off"), Ok(false));
901        assert_matches!(from_arg::<bool>("true"), Ok(true));
902        assert_matches!(from_arg::<bool>("false"), Ok(false));
903        assert_matches!(from_arg::<bool>("on,off"), Err(Error::Trailing(t)) if t == "off");
904
905        #[derive(Debug, Deserialize, PartialEq, Eq)]
906        struct BoolStruct {
907            val: bool,
908        }
909        assert_eq!(
910            from_arg::<BoolStruct>("val=on").unwrap(),
911            BoolStruct { val: true }
912        );
913        assert_eq!(
914            from_arg::<BoolStruct>("val=off").unwrap(),
915            BoolStruct { val: false }
916        );
917        assert_eq!(
918            from_arg::<BoolStruct>("val=true").unwrap(),
919            BoolStruct { val: true }
920        );
921        assert_eq!(
922            from_arg::<BoolStruct>("val=false").unwrap(),
923            BoolStruct { val: false }
924        );
925        assert_matches!(from_arg::<BoolStruct>("val=a"), Err(Error::ExpectedBool));
926
927        assert_matches!(
928            from_arg::<BoolStruct>("val=on,key=off"),
929            Err(Error::Ignored(k)) if k == "key"
930        );
931    }
932
933    #[test]
934    fn test_enum() {
935        #[derive(Debug, Deserialize, PartialEq, Eq)]
936        struct SubStruct {
937            a: u32,
938            b: bool,
939        }
940
941        #[derive(Debug, Deserialize, PartialEq, Eq)]
942        enum TestEnum {
943            A {
944                #[serde(default)]
945                val: u32,
946            },
947            B(u64),
948            C(u8, u8),
949            D,
950            #[serde(alias = "e")]
951            E,
952            F(SubStruct),
953            G(u16, String, bool),
954        }
955
956        #[derive(Debug, Deserialize, PartialEq, Eq)]
957        struct TestStruct {
958            num: u32,
959            e: TestEnum,
960        }
961
962        assert_eq!(
963            from_args::<TestStruct>("num=3,e=id_a", &[("id_a", "A,val=1")].into()).unwrap(),
964            TestStruct {
965                num: 3,
966                e: TestEnum::A { val: 1 }
967            }
968        );
969        assert_eq!(
970            from_arg::<TestStruct>("num=4,e=A").unwrap(),
971            TestStruct {
972                num: 4,
973                e: TestEnum::A { val: 0 },
974            }
975        );
976        assert_eq!(
977            from_args::<TestStruct>("num=4,e=id_a", &[("id_a", "A")].into()).unwrap(),
978            TestStruct {
979                num: 4,
980                e: TestEnum::A { val: 0 },
981            }
982        );
983        assert_eq!(
984            from_arg::<TestStruct>("num=4,e=D").unwrap(),
985            TestStruct {
986                num: 4,
987                e: TestEnum::D,
988            }
989        );
990        assert_eq!(
991            from_args::<TestStruct>("num=4,e=id_d", &[("id_d", "D")].into()).unwrap(),
992            TestStruct {
993                num: 4,
994                e: TestEnum::D,
995            }
996        );
997        assert_eq!(
998            from_arg::<TestStruct>("num=3,e=e").unwrap(),
999            TestStruct {
1000                num: 3,
1001                e: TestEnum::E
1002            }
1003        );
1004        assert_matches!(
1005            from_arg::<TestStruct>("num=4,e=id_d"),
1006            Err(Error::IdNotFound(id)) if id == "id_d"
1007        );
1008        assert_matches!(
1009            from_args::<TestStruct>("num=4,e=id_d", &[].into()),
1010            Err(Error::IdNotFound(id)) if id == "id_d"
1011        );
1012        assert_eq!(from_arg::<TestEnum>("B,1").unwrap(), TestEnum::B(1));
1013        assert_eq!(from_arg::<TestEnum>("D").unwrap(), TestEnum::D);
1014        assert_eq!(
1015            from_arg::<TestEnum>("F,a=1,b=on").unwrap(),
1016            TestEnum::F(SubStruct { a: 1, b: true })
1017        );
1018        assert_eq!(
1019            from_arg::<TestEnum>("G,1,a,true").unwrap(),
1020            TestEnum::G(1, "a".to_owned(), true)
1021        );
1022        assert_matches!(
1023            from_arg::<TestEnum>("G,1,a,true,false"),
1024            Err(Error::Trailing(t)) if t == "false"
1025        );
1026        assert_matches!(
1027            from_args::<TestStruct>(
1028                "num=4,e=id_e",
1029                &HashMap::from([("id_e", "G,1,a,true,false")])
1030            ),
1031            Err(Error::Trailing(t)) if t == "false"
1032        );
1033    }
1034}