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:
Alexandre Courbot 2022-10-26 12:11:57 +09:00 committed by crosvm LUCI
parent eb8d6c1462
commit e288105e56

View file

@ -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)]