mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-08 19:33:07 +00:00
serde_keyvalue: allow parsing of inner structs
Structs can be parsed as part of the command-line input, if they are enclosed within braces. BUG=b:218223240 TEST=cargo test -p serde_keyvalue Change-Id: I05d9d1237036c6ba464408d56c216072e285d801 Reviewed-on: https://chromium-review.googlesource.com/c/crosvm/crosvm/+/3979490 Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Commit-Queue: Daniel Verkamp <dverkamp@chromium.org> Reviewed-by: Pujun Lun <lunpujun@google.com> Auto-Submit: Alexandre Courbot <acourbot@chromium.org>
This commit is contained in:
parent
eb8d6c1462
commit
e288105e56
1 changed files with 111 additions and 1 deletions
|
@ -234,6 +234,9 @@ pub struct KeyValueDeserializer<'de> {
|
|||
/// Whether the '=' sign has been parsed after a key. The absence of '=' is only valid for
|
||||
/// boolean fields, in which case the field's value will be `true`.
|
||||
has_equal: bool,
|
||||
/// Whether the top structure has been parsed yet or not. The top structure is the only one that
|
||||
/// does not require to be enclosed within braces.
|
||||
top_struct_parsed: bool,
|
||||
}
|
||||
|
||||
impl<'de> From<&'de str> for KeyValueDeserializer<'de> {
|
||||
|
@ -243,6 +246,7 @@ impl<'de> From<&'de str> for KeyValueDeserializer<'de> {
|
|||
input,
|
||||
next_identifier: None,
|
||||
has_equal: false,
|
||||
top_struct_parsed: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -777,6 +781,18 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut KeyValueDeserializer<'de> {
|
|||
where
|
||||
V: serde::de::Visitor<'de>,
|
||||
{
|
||||
// The top structure (i.e. the first structure that we will ever parse) does not need to be
|
||||
// enclosed in braces, but inner structures do.
|
||||
let top_struct_parsed = std::mem::replace(&mut self.top_struct_parsed, true);
|
||||
|
||||
if top_struct_parsed {
|
||||
if self.peek_char() == Some('[') {
|
||||
self.next_char();
|
||||
} else {
|
||||
return Err(self.error_here(ErrorKind::ExpectedOpenBracket));
|
||||
}
|
||||
}
|
||||
|
||||
// The name of the first field of a struct can be omitted (see documentation of
|
||||
// `next_identifier` for details).
|
||||
//
|
||||
|
@ -797,7 +813,18 @@ impl<'de, 'a> de::Deserializer<'de> for &'a mut KeyValueDeserializer<'de> {
|
|||
// Not an identifier, probably means this is a value for the first field then.
|
||||
Err(_) => fields.get(0).copied(),
|
||||
};
|
||||
visitor.visit_map(self)
|
||||
|
||||
let ret = visitor.visit_map(&mut *self)?;
|
||||
|
||||
if top_struct_parsed {
|
||||
if self.peek_char() == Some(']') {
|
||||
self.next_char();
|
||||
} else {
|
||||
return Err(self.error_here(ErrorKind::ExpectedCloseBracket));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
fn deserialize_enum<V>(
|
||||
|
@ -1381,6 +1408,89 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_vector_of_structs() {
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct Display {
|
||||
size: (u32, u32),
|
||||
#[serde(default)]
|
||||
disabled: bool,
|
||||
}
|
||||
|
||||
#[derive(Deserialize, PartialEq, Debug)]
|
||||
#[serde(deny_unknown_fields)]
|
||||
struct TestStruct {
|
||||
displays: Vec<Display>,
|
||||
hostname: Option<String>,
|
||||
}
|
||||
|
||||
let res: TestStruct = from_key_values("displays=[[size=[640,480]]]").unwrap();
|
||||
assert_eq!(
|
||||
res,
|
||||
TestStruct {
|
||||
displays: vec![Display {
|
||||
size: (640, 480),
|
||||
disabled: false,
|
||||
}],
|
||||
hostname: None,
|
||||
}
|
||||
);
|
||||
|
||||
let res: TestStruct =
|
||||
from_key_values("hostname=crosmatic,displays=[[size=[800,600],disabled]]").unwrap();
|
||||
assert_eq!(
|
||||
res,
|
||||
TestStruct {
|
||||
displays: vec![Display {
|
||||
size: (800, 600),
|
||||
disabled: true,
|
||||
}],
|
||||
hostname: Some("crosmatic".to_string()),
|
||||
}
|
||||
);
|
||||
|
||||
// First field of a struct does not need to be named even if it is not the top-level struct.
|
||||
let res: TestStruct =
|
||||
from_key_values("displays=[[[640,480]],[[800,600],disabled]]").unwrap();
|
||||
assert_eq!(
|
||||
res,
|
||||
TestStruct {
|
||||
displays: vec![
|
||||
Display {
|
||||
size: (640, 480),
|
||||
disabled: false,
|
||||
},
|
||||
Display {
|
||||
size: (800, 600),
|
||||
disabled: true,
|
||||
}
|
||||
],
|
||||
hostname: None,
|
||||
}
|
||||
);
|
||||
|
||||
let res: TestStruct =
|
||||
from_key_values("displays=[[[1024,768]],[size=[800,600],disabled]],hostname=crosmatic")
|
||||
.unwrap();
|
||||
assert_eq!(
|
||||
res,
|
||||
TestStruct {
|
||||
displays: vec![
|
||||
Display {
|
||||
size: (1024, 768),
|
||||
disabled: false,
|
||||
},
|
||||
Display {
|
||||
size: (800, 600),
|
||||
disabled: true,
|
||||
}
|
||||
],
|
||||
hostname: Some("crosmatic".to_string()),
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn deserialize_set() {
|
||||
#[derive(Deserialize, PartialEq, Eq, Debug, PartialOrd, Ord)]
|
||||
|
|
Loading…
Reference in a new issue