1use 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}