From 9796059c58ec315dfc9b4ed0ba37c9e9318cb3fc Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Tue, 10 Jul 2018 23:29:47 -0700 Subject: 0.5: Support dotted keys. cc #224 --- src/de.rs | 62 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 57 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/de.rs b/src/de.rs index 85009ed..d41ca12 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())?; } } } @@ -796,7 +799,7 @@ impl<'a> Deserializer<'a> { } fn key_value(&mut self) -> Result, 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>, 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>, + 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(|(k, _)| *k == key) { + Some((_, Value { e: E::InlineTable(ref mut v), .. })) => { + return self.add_dotted_key(key_parts, value, v); + } + Some((_, Value { start, .. })) => { + return Err(self.error(*start, ErrorKind::DottedKeyInvalidType)); + } + None => {} + } + // The start/end value is somewhat misleading here. + let inline_table = Value { + e: E::InlineTable(Vec::new()), + start: value.start, + end: value.end, + }; + values.push((key, inline_table)); + let last_i = values.len() - 1; + if let (_, Value { e: E::InlineTable(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>, Value<'a>), } struct Header<'a> { -- cgit v1.2.3 From 2b6e286fb6244690a6572ebde4e139cbf7a52053 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Wed, 11 Jul 2018 00:13:47 -0700 Subject: Support older rustc. --- src/de.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/de.rs b/src/de.rs index d41ca12..65632fc 100644 --- a/src/de.rs +++ b/src/de.rs @@ -1179,12 +1179,12 @@ impl<'a> Deserializer<'a> { values.push((key, value)); return Ok(()); } - match values.iter_mut().find(|(k, _)| *k == key) { - Some((_, Value { e: E::InlineTable(ref mut v), .. })) => { + match values.iter_mut().find(|&&mut (ref k, _)| *k == key) { + Some(&mut (_, Value { e: E::InlineTable(ref mut v), .. })) => { return self.add_dotted_key(key_parts, value, v); } - Some((_, Value { start, .. })) => { - return Err(self.error(*start, ErrorKind::DottedKeyInvalidType)); + Some(&mut (_, Value { start, .. })) => { + return Err(self.error(start, ErrorKind::DottedKeyInvalidType)); } None => {} } -- cgit v1.2.3 From d6f383d20c2dbefd9ece0834b05310dfae4e2a88 Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Fri, 27 Jul 2018 11:49:30 -0700 Subject: Don't allow intermixing inline tables and dotted key tables. --- src/de.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/de.rs b/src/de.rs index 65632fc..517a62b 100644 --- a/src/de.rs +++ b/src/de.rs @@ -526,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, @@ -1180,7 +1180,7 @@ impl<'a> Deserializer<'a> { return Ok(()); } match values.iter_mut().find(|&&mut (ref k, _)| *k == key) { - Some(&mut (_, Value { e: E::InlineTable(ref mut v), .. })) => { + Some(&mut (_, Value { e: E::DottedTable(ref mut v), .. })) => { return self.add_dotted_key(key_parts, value, v); } Some(&mut (_, Value { start, .. })) => { @@ -1190,13 +1190,13 @@ impl<'a> Deserializer<'a> { } // The start/end value is somewhat misleading here. let inline_table = Value { - e: E::InlineTable(Vec::new()), + 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::InlineTable(ref mut v), .. }) = values[last_i] { + if let (_, Value { e: E::DottedTable(ref mut v), .. }) = values[last_i] { self.add_dotted_key(key_parts, value, v)?; } Ok(()) @@ -1499,6 +1499,7 @@ enum E<'a> { Datetime(&'a str), Array(Vec>), InlineTable(Vec<(Cow<'a, str>, Value<'a>)>), + DottedTable(Vec<(Cow<'a, str>, Value<'a>)>), } impl<'a> Value<'a> { @@ -1511,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, } -- cgit v1.2.3