aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/de.rs66
1 files changed, 60 insertions, 6 deletions
diff --git a/src/de.rs b/src/de.rs
index 85009ed..517a62b 100644
--- a/src/de.rs
+++ b/src/de.rs
@@ -159,6 +159,9 @@ enum ErrorKind {
/// A struct was expected but something else was found
ExpectedString,
+ /// Dotted key attempted to extend something that is not a table.
+ DottedKeyInvalidType,
+
#[doc(hidden)]
__Nonexhaustive,
}
@@ -210,7 +213,7 @@ impl<'de, 'b> de::Deserializer<'de> for &'b mut Deserializer<'de> {
if cur_table.values.is_none() {
cur_table.values = Some(Vec::new());
}
- cur_table.values.as_mut().unwrap().push((key, value));
+ self.add_dotted_key(key, value, cur_table.values.as_mut().unwrap())?;
}
}
}
@@ -523,7 +526,7 @@ impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
s.end()?;
Ok(ret)
}
- E::InlineTable(values) => {
+ E::InlineTable(values) | E::DottedTable(values) => {
visitor.visit_map(InlineTableDeserializer {
values: values.into_iter(),
next_value: None,
@@ -796,7 +799,7 @@ impl<'a> Deserializer<'a> {
}
fn key_value(&mut self) -> Result<Line<'a>, Error> {
- let key = self.table_key()?;
+ let key = self.dotted_key()?;
self.eat_whitespace()?;
self.expect(Token::Equals)?;
self.eat_whitespace()?;
@@ -1095,11 +1098,12 @@ impl<'a> Deserializer<'a> {
return Ok((span, ret))
}
loop {
- let key = self.table_key()?;
+ let key = self.dotted_key()?;
self.eat_whitespace()?;
self.expect(Token::Equals)?;
self.eat_whitespace()?;
- ret.push((key, self.value()?));
+ let value = self.value()?;
+ self.add_dotted_key(key, value, &mut ret)?;
self.eat_whitespace()?;
if let Some(span) = self.eat_spanned(Token::RightBrace)? {
@@ -1152,6 +1156,52 @@ impl<'a> Deserializer<'a> {
self.tokens.table_key().map(|t| t.1).map_err(|e| self.token_error(e))
}
+ fn dotted_key(&mut self) -> Result<Vec<Cow<'a, str>>, Error> {
+ let mut result = Vec::new();
+ result.push(self.table_key()?);
+ self.eat_whitespace()?;
+ while self.eat(Token::Period)? {
+ self.eat_whitespace()?;
+ result.push(self.table_key()?);
+ self.eat_whitespace()?;
+ }
+ Ok(result)
+ }
+
+ fn add_dotted_key(
+ &self,
+ mut key_parts: Vec<Cow<'a, str>>,
+ value: Value<'a>,
+ values: &mut Vec<(Cow<'a, str>, Value<'a>)>,
+ ) -> Result<(), Error> {
+ let key = key_parts.remove(0);
+ if key_parts.is_empty() {
+ values.push((key, value));
+ return Ok(());
+ }
+ match values.iter_mut().find(|&&mut (ref k, _)| *k == key) {
+ Some(&mut (_, Value { e: E::DottedTable(ref mut v), .. })) => {
+ return self.add_dotted_key(key_parts, value, v);
+ }
+ Some(&mut (_, Value { start, .. })) => {
+ return Err(self.error(start, ErrorKind::DottedKeyInvalidType));
+ }
+ None => {}
+ }
+ // The start/end value is somewhat misleading here.
+ let inline_table = Value {
+ e: E::DottedTable(Vec::new()),
+ start: value.start,
+ end: value.end,
+ };
+ values.push((key, inline_table));
+ let last_i = values.len() - 1;
+ if let (_, Value { e: E::DottedTable(ref mut v), .. }) = values[last_i] {
+ self.add_dotted_key(key_parts, value, v)?;
+ }
+ Ok(())
+ }
+
fn eat_whitespace(&mut self) -> Result<(), Error> {
self.tokens.eat_whitespace().map_err(|e| self.token_error(e))
}
@@ -1329,6 +1379,7 @@ impl fmt::Display for Error {
ErrorKind::EmptyTableKey => "empty table key found".fmt(f)?,
ErrorKind::Custom => self.inner.message.fmt(f)?,
ErrorKind::ExpectedString => "expected string".fmt(f)?,
+ ErrorKind::DottedKeyInvalidType => "dotted key attempted to extend non-table type".fmt(f)?,
ErrorKind::__Nonexhaustive => panic!(),
}
@@ -1372,6 +1423,7 @@ impl error::Error for Error {
ErrorKind::EmptyTableKey => "empty table key found",
ErrorKind::Custom => "a custom error",
ErrorKind::ExpectedString => "expected string",
+ ErrorKind::DottedKeyInvalidType => "dotted key invalid type",
ErrorKind::__Nonexhaustive => panic!(),
}
}
@@ -1385,7 +1437,7 @@ impl de::Error for Error {
enum Line<'a> {
Table { at: usize, header: Header<'a>, array: bool },
- KeyValue(Cow<'a, str>, Value<'a>),
+ KeyValue(Vec<Cow<'a, str>>, Value<'a>),
}
struct Header<'a> {
@@ -1447,6 +1499,7 @@ enum E<'a> {
Datetime(&'a str),
Array(Vec<Value<'a>>),
InlineTable(Vec<(Cow<'a, str>, Value<'a>)>),
+ DottedTable(Vec<(Cow<'a, str>, Value<'a>)>),
}
impl<'a> Value<'a> {
@@ -1459,6 +1512,7 @@ impl<'a> Value<'a> {
(&E::Datetime(..), &E::Datetime(..)) |
(&E::Array(..), &E::Array(..)) |
(&E::InlineTable(..), &E::InlineTable(..)) => true,
+ (&E::DottedTable(..), &E::DottedTable(..)) => true,
_ => false,
}