de.rs98.72%
1
// Copyright 2024 Google LLC2
//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 at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// 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 and13
// limitations under the License.14
15
use std::collections::HashMap;16
17
use serde::Deserialize;18
use serde::de::{self, DeserializeSeed, EnumAccess, MapAccess, SeqAccess, VariantAccess, Visitor};19
20
use crate::error::{Error, Result};21
22
#[derive(Debug)]23
pub 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
30
impl<'s> de::Deserializer<'s> for &mut Deserializer<'s, '_> {31
type Error = Error;32
33
fn deserialize_any<V>(self, _visitor: V) -> Result<V::Value>34
where35
V: Visitor<'s>,36
{37
Err(Error::UnknownType)38
}39
40
fn deserialize_bool<V>(self, visitor: V) -> Result<V::Value>91x41
where91x42
V: Visitor<'s>,91x43
{44
let s = self.consume_input();91x45
match s {91x46
"on" | "true" => visitor.visit_bool(true),91x47
"off" | "false" => visitor.visit_bool(false),21x48
_ => Err(Error::ExpectedBool),3x49
}50
}91x51
52
fn deserialize_i8<V>(self, visitor: V) -> Result<V::Value>21x53
where21x54
V: Visitor<'s>,21x55
{56
visitor.visit_i8(self.parse_signed()?)21x57
}21x58
59
fn deserialize_i16<V>(self, visitor: V) -> Result<V::Value>3x60
where3x61
V: Visitor<'s>,3x62
{63
visitor.visit_i16(self.parse_signed()?)3x64
}3x65
66
fn deserialize_i32<V>(self, visitor: V) -> Result<V::Value>9x67
where9x68
V: Visitor<'s>,9x69
{70
visitor.visit_i32(self.parse_signed()?)9x71
}9x72
73
fn deserialize_i64<V>(self, visitor: V) -> Result<V::Value>6x74
where6x75
V: Visitor<'s>,6x76
{77
visitor.visit_i64(self.parse_signed()?)6x78
}6x79
80
fn deserialize_u8<V>(self, visitor: V) -> Result<V::Value>87x81
where87x82
V: Visitor<'s>,87x83
{84
visitor.visit_u8(self.parse_unsigned()?)87x85
}87x86
87
fn deserialize_u16<V>(self, visitor: V) -> Result<V::Value>53x88
where53x89
V: Visitor<'s>,53x90
{91
visitor.visit_u16(self.parse_unsigned()?)53x92
}53x93
94
fn deserialize_u32<V>(self, visitor: V) -> Result<V::Value>93x95
where93x96
V: Visitor<'s>,93x97
{98
visitor.visit_u32(self.parse_unsigned()?)93x99
}93x100
101
fn deserialize_u64<V>(self, visitor: V) -> Result<V::Value>32x102
where32x103
V: Visitor<'s>,32x104
{105
visitor.visit_u64(self.parse_unsigned()?)32x106
}32x107
108
fn deserialize_f32<V>(self, visitor: V) -> Result<V::Value>3x109
where3x110
V: Visitor<'s>,3x111
{112
let s = self.consume_input();3x113
visitor.visit_f32(s.parse().map_err(|_| Error::ExpectedFloat)?)3x114
}3x115
116
fn deserialize_f64<V>(self, visitor: V) -> Result<V::Value>3x117
where3x118
V: Visitor<'s>,3x119
{120
let s = self.consume_input();3x121
visitor.visit_f64(s.parse().map_err(|_| Error::ExpectedFloat)?)3x122
}3x123
124
fn deserialize_char<V>(self, visitor: V) -> Result<V::Value>27x125
where27x126
V: Visitor<'s>,27x127
{128
self.deserialize_str(visitor)27x129
}27x130
131
fn deserialize_str<V>(self, visitor: V) -> Result<V::Value>178x132
where178x133
V: Visitor<'s>,178x134
{135
if self.top_level {178x136
visitor.visit_borrowed_str(self.consume_all())21x137
} else {138
let id = self.consume_input();157x139
visitor.visit_borrowed_str(self.deref_id(id)?)157x140
}141
}178x142
143
fn deserialize_string<V>(self, visitor: V) -> Result<V::Value>135x144
where135x145
V: Visitor<'s>,135x146
{147
self.deserialize_str(visitor)135x148
}135x149
150
fn deserialize_bytes<V>(self, visitor: V) -> Result<V::Value>12x151
where12x152
V: Visitor<'s>,12x153
{154
self.deserialize_seq(visitor)12x155
}12x156
157
fn deserialize_byte_buf<V>(self, visitor: V) -> Result<V::Value>3x158
where3x159
V: Visitor<'s>,3x160
{161
self.deserialize_bytes(visitor)3x162
}3x163
164
fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>68x165
where68x166
V: Visitor<'s>,68x167
{168
let id = self.consume_input();68x169
let s = self.deref_id(id)?;68x170
if id.starts_with("id_") && s.is_empty() {65x171
visitor.visit_none()12x172
} else {173
let mut sub_de = Deserializer { input: s, ..*self };53x174
visitor.visit_some(&mut sub_de)53x175
}176
}68x177
178
fn deserialize_unit<V>(self, visitor: V) -> Result<V::Value>18x179
where18x180
V: Visitor<'s>,18x181
{182
let s = self.consume_input();18x183
if s.is_empty() {18x184
visitor.visit_unit()9x185
} else {186
Err(Error::ExpectedUnit)9x187
}188
}18x189
190
fn deserialize_unit_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>12x191
where12x192
V: Visitor<'s>,12x193
{194
self.deserialize_unit(visitor)12x195
}12x196
197
fn deserialize_newtype_struct<V>(self, _name: &'static str, visitor: V) -> Result<V::Value>3x198
where3x199
V: Visitor<'s>,3x200
{201
visitor.visit_newtype_struct(self)3x202
}3x203
204
fn deserialize_seq<V>(self, visitor: V) -> Result<V::Value>62x205
where62x206
V: Visitor<'s>,62x207
{208
self.deserialize_nested(|de| visitor.visit_seq(CommaSeparated::new(de)))62x209
}62x210
211
fn deserialize_tuple<V>(self, _len: usize, visitor: V) -> Result<V::Value>12x212
where12x213
V: Visitor<'s>,12x214
{215
self.deserialize_seq(visitor)12x216
}12x217
218
fn deserialize_tuple_struct<V>(3x219
self,3x220
_name: &'static str,3x221
_len: usize,3x222
visitor: V,3x223
) -> Result<V::Value>3x224
where3x225
V: Visitor<'s>,3x226
{227
self.deserialize_seq(visitor)3x228
}3x229
230
fn deserialize_map<V>(self, visitor: V) -> Result<V::Value>192x231
where192x232
V: Visitor<'s>,192x233
{234
self.deserialize_nested(|de| visitor.visit_map(CommaSeparated::new(de)))192x235
}192x236
237
fn deserialize_struct<V>(177x238
self,177x239
_name: &'static str,177x240
_fields: &'static [&'static str],177x241
visitor: V,177x242
) -> Result<V::Value>177x243
where177x244
V: Visitor<'s>,177x245
{246
self.deserialize_map(visitor)177x247
}177x248
249
fn deserialize_enum<V>(86x250
self,86x251
_name: &'static str,86x252
_variants: &'static [&'static str],86x253
visitor: V,86x254
) -> Result<V::Value>86x255
where86x256
V: Visitor<'s>,86x257
{258
self.deserialize_nested(|de| visitor.visit_enum(Enum::new(de)))86x259
}86x260
261
fn deserialize_identifier<V>(self, visitor: V) -> Result<V::Value>446x262
where446x263
V: Visitor<'s>,446x264
{265
visitor.visit_borrowed_str(self.consume_input())446x266
}446x267
268
fn deserialize_ignored_any<V>(self, _visitor: V) -> Result<V::Value>15x269
where15x270
V: Visitor<'s>,15x271
{272
Err(Error::Ignored(self.key.to_owned()))15x273
}15x274
}275
276
impl<'s, 'o> Deserializer<'s, 'o> {277
pub fn from_args(input: &'s str, objects: &'o HashMap<&'s str, &'s str>) -> Self {124x278
Deserializer {124x279
input,124x280
objects: Some(objects),124x281
top_level: true,124x282
key: "",124x283
}124x284
}124x285
286
pub fn from_arg(input: &'s str) -> Self {207x287
Deserializer {207x288
input,207x289
objects: None,207x290
top_level: true,207x291
key: "",207x292
}207x293
}207x294
295
fn end(&self) -> Result<()> {522x296
if self.input.is_empty() {522x297
Ok(())504x298
} else {299
Err(Error::Trailing(self.input.to_owned()))18x300
}301
}522x302
303
fn deserialize_nested<F, V>(&mut self, f: F) -> Result<V>340x304
where340x305
F: FnOnce(&mut Self) -> Result<V>,340x306
{307
let mut sub_de;308
let de = if !self.top_level {340x309
let id = self.consume_input();91x310
let sub_input = self.deref_id(id)?;91x311
sub_de = Deserializer {85x312
input: sub_input,85x313
..*self85x314
};85x315
&mut sub_de85x316
} else {317
self.top_level = false;249x318
self249x319
};320
let val = f(de)?;334x321
de.end()?;282x322
Ok(val)267x323
}340x324
325
fn consume_input_until(&mut self, end: char) -> Option<&'s str> {1586x326
let len = self.input.find(end)?;1586x327
let s = &self.input[..len];809x328
self.input = &self.input[len + end.len_utf8()..];809x329
Some(s)809x330
}1586x331
332
fn consume_all(&mut self) -> &'s str {792x333
let s = self.input;792x334
self.input = "";792x335
s792x336
}792x337
338
fn consume_input(&mut self) -> &'s str {1181x339
match self.consume_input_until(',') {1181x340
Some(s) => s,410x341
None => self.consume_all(),771x342
}343
}1181x344
345
fn deref_id(&self, id: &'s str) -> Result<&'s str> {316x346
if id.starts_with("id_") {316x347
if let Some(s) = self.objects.and_then(|objects| objects.get(id)) {98x348
Ok(s)89x349
} else {350
Err(Error::IdNotFound(id.to_owned()))9x351
}352
} else {353
Ok(id)218x354
}355
}316x356
357
fn parse_unsigned<T>(&mut self) -> Result<T>295x358
where295x359
T: TryFrom<u64>,295x360
{361
let s = self.consume_input();295x362
let (num, shift) = if let Some((num, "")) = s.split_once(['k', 'K']) {295x363
(num, 10)6x364
} else if let Some((num, "")) = s.split_once(['m', 'M']) {289x365
(num, 20)3x366
} else if let Some((num, "")) = s.split_once(['g', 'G']) {286x367
(num, 30)32x368
} else if let Some((num, "")) = s.split_once(['t', 'T']) {254x369
(num, 40)3x370
} else {371
(s, 0)251x372
};373
let n = if let Some(num_h) = num.strip_prefix("0x") {295x374
u64::from_str_radix(num_h, 16)78x375
} else if let Some(num_o) = num.strip_prefix("0o") {217x376
u64::from_str_radix(num_o, 8)3x377
} else if let Some(num_b) = num.strip_prefix("0b") {214x378
u64::from_str_radix(num_b, 2)3x379
} else {380
num.parse::<u64>()211x381
}382
.map_err(|_| Error::ExpectedInteger)?;295x383
384
let shifted_n = n.checked_shl(shift).ok_or(Error::Overflow)?;289x385
386
T::try_from(shifted_n).map_err(|_| Error::Overflow)289x387
}295x388
389
fn parse_signed<T>(&mut self) -> Result<T>39x390
where39x391
T: TryFrom<i64>,39x392
{393
let i = if self.input.starts_with('-') {39x394
let s = self.consume_input();9x395
s.parse().map_err(|_| Error::ExpectedInteger)9x396
} else {397
let n = self.parse_unsigned::<u64>()?;30x398
i64::try_from(n).map_err(|_| Error::Overflow)27x399
}?;400
T::try_from(i).map_err(|_| Error::Overflow)36x401
}39x402
}403
404
pub fn from_args<'s, 'o, T>(s: &'s str, objects: &'o HashMap<&'s str, &'s str>) -> Result<T>124x405
where124x406
T: Deserialize<'s>,124x407
{408
let mut deserializer = Deserializer::from_args(s, objects);124x409
let value = T::deserialize(&mut deserializer)?;124x410
deserializer.end()?;102x411
Ok(value)102x412
}124x413
414
pub fn from_arg<'s, T>(s: &'s str) -> Result<T>207x415
where207x416
T: Deserialize<'s>,207x417
{418
let mut deserializer = Deserializer::from_arg(s);207x419
let value = T::deserialize(&mut deserializer)?;207x420
deserializer.end()?;138x421
Ok(value)135x422
}207x423
424
struct CommaSeparated<'a, 's: 'a, 'o: 'a> {425
de: &'a mut Deserializer<'s, 'o>,426
}427
428
impl<'a, 's, 'o> CommaSeparated<'a, 's, 'o> {429
fn new(de: &'a mut Deserializer<'s, 'o>) -> Self {272x430
CommaSeparated { de }272x431
}272x432
}433
434
impl<'s> SeqAccess<'s> for CommaSeparated<'_, 's, '_> {435
type Error = Error;436
437
fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>>219x438
where219x439
T: DeserializeSeed<'s>,219x440
{441
if self.de.input.is_empty() {219x442
return Ok(None);38x443
}181x444
seed.deserialize(&mut *self.de).map(Some)181x445
}219x446
}447
448
impl<'s> MapAccess<'s> for CommaSeparated<'_, 's, '_> {449
type Error = Error;450
451
fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>>564x452
where564x453
K: DeserializeSeed<'s>,564x454
{455
if self.de.input.is_empty() {564x456
return Ok(None);159x457
}405x458
let Some(key) = self.de.consume_input_until('=') else {405x459
return Err(Error::ExpectedMapEq);6x460
};461
if key.contains(',') {399x462
return Err(Error::ExpectedMapEq);3x463
}396x464
self.de.key = key;396x465
let mut sub_de = Deserializer {396x466
input: key,396x467
key: "",396x468
..*self.de396x469
};396x470
seed.deserialize(&mut sub_de).map(Some)396x471
}564x472
473
fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value>396x474
where396x475
V: DeserializeSeed<'s>,396x476
{477
seed.deserialize(&mut *self.de)396x478
}396x479
}480
481
struct Enum<'a, 's: 'a, 'o: 'a> {482
de: &'a mut Deserializer<'s, 'o>,483
}484
485
impl<'a, 's, 'o> Enum<'a, 's, 'o> {486
fn new(de: &'a mut Deserializer<'s, 'o>) -> Self {80x487
Enum { de }80x488
}80x489
}490
491
impl<'s> EnumAccess<'s> for Enum<'_, 's, '_> {492
type Error = Error;493
type Variant = Self;494
495
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant)>80x496
where80x497
V: DeserializeSeed<'s>,80x498
{499
let val = seed.deserialize(&mut *self.de)?;80x500
Ok((val, self))70x501
}80x502
}503
504
impl<'s> VariantAccess<'s> for Enum<'_, 's, '_> {505
type Error = Error;506
507
fn unit_variant(self) -> Result<()> {23x508
Ok(())23x509
}23x510
511
fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value>29x512
where29x513
T: DeserializeSeed<'s>,29x514
{515
self.de.top_level = true;29x516
seed.deserialize(self.de)29x517
}29x518
519
fn tuple_variant<V>(self, _len: usize, visitor: V) -> Result<V::Value>9x520
where9x521
V: Visitor<'s>,9x522
{523
visitor.visit_seq(CommaSeparated::new(self.de))9x524
}9x525
526
fn struct_variant<V>(self, _fields: &'static [&'static str], visitor: V) -> Result<V::Value>9x527
where9x528
V: Visitor<'s>,9x529
{530
visitor.visit_map(CommaSeparated::new(self.de))9x531
}9x532
}533
534
#[cfg(test)]535
mod test {536
use std::collections::HashMap;537
use std::marker::PhantomData;538
539
use assert_matches::assert_matches;540
use serde::Deserialize;541
use serde_bytes::{ByteArray, ByteBuf};542
543
use crate::{Error, from_arg, from_args};544
545
#[test]546
fn test_option() {3x547
assert_matches!(from_arg::<Option<u32>>(""), Err(Error::ExpectedInteger));3x548
assert_eq!(from_arg::<Option<u32>>("12").unwrap(), Some(12));3x549
550
assert_eq!(from_arg::<Option<&'static str>>("").unwrap(), Some(""));3x551
assert_eq!(3x552
from_args::<Option<&'static str>>("id_1", &HashMap::from([("id_1", "")])).unwrap(),3x553
None554
);555
assert_eq!(from_arg::<Option<&'static str>>("12").unwrap(), Some("12"));3x556
assert_matches!(3x557
from_arg::<Option<&'static str>>("id_1"),3x558
Err(Error::IdNotFound(id)) if id == "id_1"3x559
);560
assert_eq!(3x561
from_args::<Option<&'static str>>("id_1", &HashMap::from([("id_1", "id_2")])).unwrap(),3x562
Some("id_2")563
);564
565
let map_none = HashMap::from([("id_none", "")]);3x566
assert_eq!(from_arg::<Vec<Option<u32>>>("").unwrap(), vec![]);3x567
assert_eq!(3x568
from_args::<Vec<Option<u32>>>("id_none,", &map_none).unwrap(),3x569
vec![None]3x570
);571
assert_eq!(from_arg::<Vec<Option<u32>>>("1,").unwrap(), vec![Some(1)]);3x572
assert_eq!(3x573
from_arg::<Vec<Option<u32>>>("1,2,").unwrap(),3x574
vec![Some(1), Some(2)]3x575
);576
assert_eq!(3x577
from_args::<Vec<Option<u32>>>("1,2,id_none,", &map_none).unwrap(),3x578
vec![Some(1), Some(2), None]3x579
);580
assert_eq!(3x581
from_args::<Vec<Option<u32>>>("id_none,2", &map_none).unwrap(),3x582
vec![None, Some(2)]3x583
);584
}3x585
586
#[test]587
fn test_unit() {3x588
assert!(from_arg::<()>("").is_ok());3x589
assert_matches!(from_arg::<()>("unit"), Err(Error::ExpectedUnit));3x590
591
assert!(from_arg::<PhantomData<u8>>("").is_ok());3x592
assert_matches!(from_arg::<PhantomData<u8>>("12"), Err(Error::ExpectedUnit));3x593
594
#[derive(Debug, Deserialize, PartialEq, Eq)]595
struct Param {596
p: PhantomData<u8>,597
}598
assert_eq!(from_arg::<Param>("p=").unwrap(), Param { p: PhantomData });3x599
assert_matches!(from_arg::<Param>("p=1,"), Err(Error::ExpectedUnit));3x600
}3x601
602
#[test]603
fn test_numbers() {3x604
assert_eq!(from_arg::<i8>("0").unwrap(), 0);3x605
assert_eq!(from_arg::<i8>("1").unwrap(), 1);3x606
assert_eq!(from_arg::<i8>("127").unwrap(), 127);3x607
assert_matches!(from_arg::<i8>("128"), Err(Error::Overflow));3x608
assert_eq!(from_arg::<i8>("-1").unwrap(), -1);3x609
assert_eq!(from_arg::<i8>("-128").unwrap(), -128);3x610
assert_matches!(from_arg::<i8>("-129"), Err(Error::Overflow));3x611
612
assert_eq!(from_arg::<i16>("1k").unwrap(), 1 << 10);3x613
614
assert_eq!(from_arg::<i32>("1g").unwrap(), 1 << 30);3x615
assert_matches!(from_arg::<i32>("2g"), Err(Error::Overflow));3x616
assert_matches!(from_arg::<i32>("0xffffffff"), Err(Error::Overflow));3x617
618
assert_eq!(from_arg::<i64>("0xffffffff").unwrap(), 0xffffffff);3x619
620
assert_matches!(from_arg::<i64>("gg"), Err(Error::ExpectedInteger));3x621
622
assert_matches!(from_arg::<f32>("0.125").unwrap(), 0.125);3x623
624
assert_matches!(from_arg::<f64>("-0.5").unwrap(), -0.5);3x625
}3x626
627
#[test]628
fn test_char() {3x629
assert_eq!(from_arg::<char>("=").unwrap(), '=');3x630
assert_eq!(from_arg::<char>("a").unwrap(), 'a');3x631
assert_matches!(from_arg::<char>("an"), Err(Error::Message(_)));3x632
633
assert_eq!(3x634
from_args::<HashMap<char, char>>(3x635
"id_1=a,b=id_2,id_2=id_1",3x636
&HashMap::from([("id_1", ","), ("id_2", "="),])3x637
)638
.unwrap(),3x639
HashMap::from([(',', 'a'), ('b', '='), ('=', ',')])3x640
);641
}3x642
643
#[test]644
fn test_bytes() {3x645
assert!(from_arg::<ByteArray<6>>("0xea,0xd7,0xa8,0xe8,0xc6,0x2f").is_ok());3x646
assert_matches!(3x647
from_arg::<ByteArray<5>>("0xea,0xd7,0xa8,0xe8,0xc6,0x2f"),3x648
Err(Error::Trailing(t)) if t == "0x2f"3x649
);650
assert_eq!(3x651
from_arg::<ByteBuf>("0xea,0xd7,0xa8,0xe8,0xc6,0x2f").unwrap(),3x652
vec![0xea, 0xd7, 0xa8, 0xe8, 0xc6, 0x2f]3x653
);654
655
#[derive(Debug, Deserialize, Eq, PartialEq)]656
struct MacAddr {657
addr: ByteArray<6>,658
}659
assert_eq!(3x660
from_args::<MacAddr>(3x661
"addr=id_addr",3x662
&HashMap::from([("id_addr", "0xea,0xd7,0xa8,0xe8,0xc6,0x2f")])3x663
)664
.unwrap(),3x665
MacAddr {3x666
addr: ByteArray::new([0xea, 0xd7, 0xa8, 0xe8, 0xc6, 0x2f])3x667
}3x668
)669
}3x670
671
#[test]672
fn test_string() {3x673
assert_eq!(3x674
from_arg::<String>("test,s=1,c").unwrap(),3x675
"test,s=1,c".to_owned()3x676
);677
assert_eq!(3x678
from_args::<HashMap<String, String>>(3x679
"cmd=id_1",3x680
&HashMap::from([("id_1", "console=ttyS0")])3x681
)682
.unwrap(),3x683
HashMap::from([("cmd".to_owned(), "console=ttyS0".to_owned())])3x684
)685
}3x686
687
#[test]688
fn test_seq() {3x689
assert_eq!(from_arg::<Vec<u32>>("").unwrap(), vec![]);3x690
691
assert_eq!(from_arg::<Vec<u32>>("1").unwrap(), vec![1]);3x692
693
assert_eq!(from_arg::<Vec<u32>>("1,2,3,4").unwrap(), vec![1, 2, 3, 4]);3x694
695
assert_eq!(from_arg::<(u16, bool)>("12,true").unwrap(), (12, true));3x696
assert_matches!(3x697
from_arg::<(u16, bool)>("12,true,false"),3x698
Err(Error::Trailing(t)) if t == "false"3x699
);700
701
#[derive(Debug, Deserialize, PartialEq, Eq)]702
struct TestStruct {703
a: (u16, bool),704
}705
assert_eq!(3x706
from_args::<TestStruct>("a=id_a", &HashMap::from([("id_a", "12,true")])).unwrap(),3x707
TestStruct { a: (12, true) }708
);709
assert_matches!(3x710
from_args::<TestStruct>("a=id_a", &HashMap::from([("id_a", "12,true,true")])),3x711
Err(Error::Trailing(t)) if t == "true"3x712
);713
714
#[derive(Debug, Deserialize, PartialEq, Eq)]715
struct Node {716
#[serde(default)]717
name: String,718
#[serde(default)]719
start: u64,720
size: u64,721
}722
#[derive(Debug, Deserialize, PartialEq, Eq)]723
struct Numa {724
nodes: Vec<Node>,725
}726
727
assert_eq!(3x728
from_args::<Numa>(3x729
"nodes=id_nodes",3x730
&HashMap::from([3x731
("id_nodes", "id_node1,id_node2"),3x732
("id_node1", "name=a,start=0,size=2g"),3x733
("id_node2", "name=b,start=4g,size=2g"),3x734
])3x735
)736
.unwrap(),3x737
Numa {3x738
nodes: vec![3x739
Node {3x740
name: "a".to_owned(),3x741
start: 0,3x742
size: 2 << 303x743
},3x744
Node {3x745
name: "b".to_owned(),3x746
start: 4 << 30,3x747
size: 2 << 303x748
}3x749
]3x750
}3x751
);752
753
assert_eq!(3x754
from_arg::<Numa>("nodes=size=2g,").unwrap(),3x755
Numa {3x756
nodes: vec![Node {3x757
name: "".to_owned(),3x758
start: 0,3x759
size: 2 << 303x760
}]3x761
}3x762
);763
764
#[derive(Debug, Deserialize, PartialEq, Eq)]765
struct Info(bool, u32);766
767
assert_eq!(from_arg::<Info>("true,32").unwrap(), Info(true, 32));3x768
}3x769
770
#[test]771
fn test_map() {3x772
#[derive(Debug, Deserialize, PartialEq, Eq, Hash)]773
struct MapKey {774
name: String,775
id: u32,776
}777
#[derive(Debug, Deserialize, PartialEq, Eq)]778
struct MapVal {779
addr: String,780
info: HashMap<String, String>,781
}782
783
assert_matches!(3x784
from_arg::<MapKey>("name=a,id=1,addr=b"),3x785
Err(Error::Ignored(k)) if k == "addr"3x786
);787
assert_matches!(3x788
from_arg::<MapKey>("name=a,addr=b,id=1"),3x789
Err(Error::Ignored(k)) if k == "addr"3x790
);791
assert_matches!(from_arg::<MapKey>("name=a,ids=b"), Err(Error::Ignored(k)) if k == "ids");3x792
assert_matches!(from_arg::<MapKey>("name=a,ids=b,id=1"), Err(Error::Ignored(k)) if k == "ids");3x793
794
assert_eq!(3x795
from_args::<HashMap<MapKey, MapVal>>(3x796
"id_key1=id_val1,id_key2=id_val2",3x797
&HashMap::from([3x798
("id_key1", "name=gic,id=1"),3x799
("id_key2", "name=pci,id=2"),3x800
("id_val1", "addr=0xff,info=id_info1"),3x801
("id_info1", "compatible=id_gic,msi-controller=,#msi-cells=1"),3x802
("id_gic", "arm,gic-v3-its"),3x803
("id_val2", "addr=0xcc,info=compatible=pci-host-ecam-generic"),3x804
])3x805
)806
.unwrap(),3x807
HashMap::from([3x808
(3x809
MapKey {3x810
name: "gic".to_owned(),3x811
id: 13x812
},3x813
MapVal {3x814
addr: "0xff".to_owned(),3x815
info: HashMap::from([3x816
("compatible".to_owned(), "arm,gic-v3-its".to_owned()),3x817
("msi-controller".to_owned(), "".to_owned()),3x818
("#msi-cells".to_owned(), "1".to_owned())3x819
])3x820
}3x821
),3x822
(3x823
MapKey {3x824
name: "pci".to_owned(),3x825
id: 23x826
},3x827
MapVal {3x828
addr: "0xcc".to_owned(),3x829
info: HashMap::from([(3x830
"compatible".to_owned(),3x831
"pci-host-ecam-generic".to_owned()3x832
)])3x833
}3x834
)3x835
])3x836
);837
}3x838
839
#[test]840
fn test_nested_struct() {3x841
#[derive(Debug, Deserialize, PartialEq, Eq)]842
struct Param {843
byte: u8,844
word: u16,845
dw: u32,846
long: u64,847
enable_1: bool,848
enable_2: bool,849
enable_3: Option<bool>,850
sub: SubParam,851
addr: Addr,852
}853
854
#[derive(Debug, Deserialize, PartialEq, Eq)]855
struct SubParam {856
b: u8,857
w: u16,858
enable: Option<bool>,859
s: String,860
}861
862
#[derive(Debug, Deserialize, PartialEq, Eq)]863
struct Addr(u32);864
865
assert_eq!(3x866
from_args::<Param>(3x867
"byte=0b10,word=0o7k,dw=0x8m,long=10t,enable_1=on,enable_2=off,sub=id_1,addr=1g",3x868
&[("id_1", "b=1,w=2,s=s1,enable=on")].into()3x869
)870
.unwrap(),3x871
Param {3x872
byte: 0b10,3x873
word: 0o7 << 10,3x874
dw: 0x8 << 20,3x875
long: 10 << 40,3x876
enable_1: true,3x877
enable_2: false,3x878
enable_3: None,3x879
sub: SubParam {3x880
b: 1,3x881
w: 2,3x882
enable: Some(true),3x883
s: "s1".to_owned(),3x884
},3x885
addr: Addr(1 << 30)3x886
}3x887
);888
assert_matches!(889
from_arg::<SubParam>("b=1,w=2,enable,s=s1"),3x890
Err(Error::ExpectedMapEq)891
);892
assert_matches!(893
from_arg::<SubParam>("b=1,w=2,s=s1,enable"),3x894
Err(Error::ExpectedMapEq)895
);896
}3x897
898
#[test]899
fn test_bool() {3x900
assert_matches!(from_arg::<bool>("on"), Ok(true));3x901
assert_matches!(from_arg::<bool>("off"), Ok(false));3x902
assert_matches!(from_arg::<bool>("true"), Ok(true));3x903
assert_matches!(from_arg::<bool>("false"), Ok(false));3x904
assert_matches!(from_arg::<bool>("on,off"), Err(Error::Trailing(t)) if t == "off");3x905
906
#[derive(Debug, Deserialize, PartialEq, Eq)]907
struct BoolStruct {908
val: bool,909
}910
assert_eq!(3x911
from_arg::<BoolStruct>("val=on").unwrap(),3x912
BoolStruct { val: true }913
);914
assert_eq!(3x915
from_arg::<BoolStruct>("val=off").unwrap(),3x916
BoolStruct { val: false }917
);918
assert_eq!(3x919
from_arg::<BoolStruct>("val=true").unwrap(),3x920
BoolStruct { val: true }921
);922
assert_eq!(3x923
from_arg::<BoolStruct>("val=false").unwrap(),3x924
BoolStruct { val: false }925
);926
assert_matches!(from_arg::<BoolStruct>("val=a"), Err(Error::ExpectedBool));3x927
928
assert_matches!(3x929
from_arg::<BoolStruct>("val=on,key=off"),3x930
Err(Error::Ignored(k)) if k == "key"3x931
);932
}3x933
934
#[test]935
fn test_enum() {3x936
#[derive(Debug, Deserialize, PartialEq, Eq)]937
struct SubStruct {938
a: u32,939
b: bool,940
}941
942
#[derive(Debug, Deserialize, PartialEq, Eq)]943
enum TestEnum {944
A {945
#[serde(default)]946
val: u32,947
},948
B(u64),949
C(u8, u8),950
D,951
#[serde(alias = "e")]952
E,953
F(SubStruct),954
G(u16, String, bool),955
}956
957
#[derive(Debug, Deserialize, PartialEq, Eq)]958
struct TestStruct {959
num: u32,960
e: TestEnum,961
}962
963
assert_eq!(3x964
from_args::<TestStruct>("num=3,e=id_a", &[("id_a", "A,val=1")].into()).unwrap(),3x965
TestStruct {966
num: 3,967
e: TestEnum::A { val: 1 }968
}969
);970
assert_eq!(3x971
from_arg::<TestStruct>("num=4,e=A").unwrap(),3x972
TestStruct {973
num: 4,974
e: TestEnum::A { val: 0 },975
}976
);977
assert_eq!(3x978
from_args::<TestStruct>("num=4,e=id_a", &[("id_a", "A")].into()).unwrap(),3x979
TestStruct {980
num: 4,981
e: TestEnum::A { val: 0 },982
}983
);984
assert_eq!(3x985
from_arg::<TestStruct>("num=4,e=D").unwrap(),3x986
TestStruct {987
num: 4,988
e: TestEnum::D,989
}990
);991
assert_eq!(3x992
from_args::<TestStruct>("num=4,e=id_d", &[("id_d", "D")].into()).unwrap(),3x993
TestStruct {994
num: 4,995
e: TestEnum::D,996
}997
);998
assert_eq!(3x999
from_arg::<TestStruct>("num=3,e=e").unwrap(),3x1000
TestStruct {1001
num: 3,1002
e: TestEnum::E1003
}1004
);1005
assert_matches!(3x1006
from_arg::<TestStruct>("num=4,e=id_d"),3x1007
Err(Error::IdNotFound(id)) if id == "id_d"3x1008
);1009
assert_matches!(3x1010
from_args::<TestStruct>("num=4,e=id_d", &[].into()),3x1011
Err(Error::IdNotFound(id)) if id == "id_d"3x1012
);1013
assert_eq!(from_arg::<TestEnum>("B,1").unwrap(), TestEnum::B(1));3x1014
assert_eq!(from_arg::<TestEnum>("D").unwrap(), TestEnum::D);3x1015
assert_eq!(3x1016
from_arg::<TestEnum>("F,a=1,b=on").unwrap(),3x1017
TestEnum::F(SubStruct { a: 1, b: true })1018
);1019
assert_eq!(3x1020
from_arg::<TestEnum>("G,1,a,true").unwrap(),3x1021
TestEnum::G(1, "a".to_owned(), true)3x1022
);1023
assert_matches!(3x1024
from_arg::<TestEnum>("G,1,a,true,false"),3x1025
Err(Error::Trailing(t)) if t == "false"3x1026
);1027
assert_matches!(3x1028
from_args::<TestStruct>(3x1029
"num=4,e=id_e",3x1030
&HashMap::from([("id_e", "G,1,a,true,false")])3x1031
),1032
Err(Error::Trailing(t)) if t == "false"3x1033
);1034
}3x1035
}1036