summaryrefslogtreecommitdiffstats
path: root/vendor/toml-0.5.11/src/de.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/toml-0.5.11/src/de.rs')
-rw-r--r--vendor/toml-0.5.11/src/de.rs2246
1 files changed, 2246 insertions, 0 deletions
diff --git a/vendor/toml-0.5.11/src/de.rs b/vendor/toml-0.5.11/src/de.rs
new file mode 100644
index 000000000..67b53156a
--- /dev/null
+++ b/vendor/toml-0.5.11/src/de.rs
@@ -0,0 +1,2246 @@
+//! Deserializing TOML into Rust structures.
+//!
+//! This module contains all the Serde support for deserializing TOML documents
+//! into Rust structures. Note that some top-level functions here are also
+//! provided at the top of the crate.
+
+use std::borrow::Cow;
+use std::collections::HashMap;
+use std::error;
+use std::f64;
+use std::fmt;
+use std::iter;
+use std::marker::PhantomData;
+use std::str;
+use std::vec;
+
+use serde::de;
+use serde::de::value::BorrowedStrDeserializer;
+use serde::de::IntoDeserializer;
+
+use crate::datetime;
+use crate::spanned;
+use crate::tokens::{Error as TokenError, Span, Token, Tokenizer};
+
+/// Type Alias for a TOML Table pair
+type TablePair<'a> = ((Span, Cow<'a, str>), Value<'a>);
+
+/// Deserializes a byte slice into a type.
+///
+/// This function will attempt to interpret `bytes` as UTF-8 data and then
+/// deserialize `T` from the TOML document provided.
+pub fn from_slice<'de, T>(bytes: &'de [u8]) -> Result<T, Error>
+where
+ T: de::Deserialize<'de>,
+{
+ match str::from_utf8(bytes) {
+ Ok(s) => from_str(s),
+ Err(e) => Err(Error::custom(None, e.to_string())),
+ }
+}
+
+/// Deserializes a string into a type.
+///
+/// This function will attempt to interpret `s` as a TOML document and
+/// deserialize `T` from the document.
+///
+/// # Examples
+///
+/// ```
+/// use serde_derive::Deserialize;
+///
+/// #[derive(Deserialize)]
+/// struct Config {
+/// title: String,
+/// owner: Owner,
+/// }
+///
+/// #[derive(Deserialize)]
+/// struct Owner {
+/// name: String,
+/// }
+///
+/// let config: Config = toml::from_str(r#"
+/// title = 'TOML Example'
+///
+/// [owner]
+/// name = 'Lisa'
+/// "#).unwrap();
+///
+/// assert_eq!(config.title, "TOML Example");
+/// assert_eq!(config.owner.name, "Lisa");
+/// ```
+pub fn from_str<'de, T>(s: &'de str) -> Result<T, Error>
+where
+ T: de::Deserialize<'de>,
+{
+ let mut d = Deserializer::new(s);
+ let ret = T::deserialize(&mut d)?;
+ d.end()?;
+ Ok(ret)
+}
+
+/// Errors that can occur when deserializing a type.
+#[derive(Debug, PartialEq, Eq, Clone)]
+pub struct Error {
+ inner: Box<ErrorInner>,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone)]
+struct ErrorInner {
+ kind: ErrorKind,
+ line: Option<usize>,
+ col: usize,
+ at: Option<usize>,
+ message: String,
+ key: Vec<String>,
+}
+
+/// Errors that can occur when deserializing a type.
+#[derive(Debug, PartialEq, Eq, Clone)]
+#[non_exhaustive]
+enum ErrorKind {
+ /// EOF was reached when looking for a value
+ UnexpectedEof,
+
+ /// An invalid character not allowed in a string was found
+ InvalidCharInString(char),
+
+ /// An invalid character was found as an escape
+ InvalidEscape(char),
+
+ /// An invalid character was found in a hex escape
+ InvalidHexEscape(char),
+
+ /// An invalid escape value was specified in a hex escape in a string.
+ ///
+ /// Valid values are in the plane of unicode codepoints.
+ InvalidEscapeValue(u32),
+
+ /// A newline in a string was encountered when one was not allowed.
+ NewlineInString,
+
+ /// An unexpected character was encountered, typically when looking for a
+ /// value.
+ Unexpected(char),
+
+ /// An unterminated string was found where EOF was found before the ending
+ /// EOF mark.
+ UnterminatedString,
+
+ /// A newline was found in a table key.
+ NewlineInTableKey,
+
+ /// A number failed to parse
+ NumberInvalid,
+
+ /// A date or datetime was invalid
+ DateInvalid,
+
+ /// Wanted one sort of token, but found another.
+ Wanted {
+ /// Expected token type
+ expected: &'static str,
+ /// Actually found token type
+ found: &'static str,
+ },
+
+ /// A duplicate table definition was found.
+ DuplicateTable(String),
+
+ /// A previously defined table was redefined as an array.
+ RedefineAsArray,
+
+ /// An empty table key was found.
+ EmptyTableKey,
+
+ /// Multiline strings are not allowed for key
+ MultilineStringKey,
+
+ /// A custom error which could be generated when deserializing a particular
+ /// type.
+ Custom,
+
+ /// A tuple with a certain number of elements was expected but something
+ /// else was found.
+ ExpectedTuple(usize),
+
+ /// Expected table keys to be in increasing tuple index order, but something
+ /// else was found.
+ ExpectedTupleIndex {
+ /// Expected index.
+ expected: usize,
+ /// Key that was specified.
+ found: String,
+ },
+
+ /// An empty table was expected but entries were found
+ ExpectedEmptyTable,
+
+ /// Dotted key attempted to extend something that is not a table.
+ DottedKeyInvalidType,
+
+ /// An unexpected key was encountered.
+ ///
+ /// Used when deserializing a struct with a limited set of fields.
+ UnexpectedKeys {
+ /// The unexpected keys.
+ keys: Vec<String>,
+ /// Keys that may be specified.
+ available: &'static [&'static str],
+ },
+
+ /// Unquoted string was found when quoted one was expected
+ UnquotedString,
+}
+
+/// Deserialization implementation for TOML.
+pub struct Deserializer<'a> {
+ require_newline_after_table: bool,
+ allow_duplciate_after_longer_table: bool,
+ input: &'a str,
+ tokens: Tokenizer<'a>,
+}
+
+impl<'de, 'b> de::Deserializer<'de> for &'b mut Deserializer<'de> {
+ type Error = Error;
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ let mut tables = self.tables()?;
+ let table_indices = build_table_indices(&tables);
+ let table_pindices = build_table_pindices(&tables);
+
+ let res = visitor.visit_map(MapVisitor {
+ values: Vec::new().into_iter().peekable(),
+ next_value: None,
+ depth: 0,
+ cur: 0,
+ cur_parent: 0,
+ max: tables.len(),
+ table_indices: &table_indices,
+ table_pindices: &table_pindices,
+ tables: &mut tables,
+ array: false,
+ de: self,
+ });
+ res.map_err(|mut err| {
+ // Errors originating from this library (toml), have an offset
+ // attached to them already. Other errors, like those originating
+ // from serde (like "missing field") or from a custom deserializer,
+ // do not have offsets on them. Here, we do a best guess at their
+ // location, by attributing them to the "current table" (the last
+ // item in `tables`).
+ err.fix_offset(|| tables.last().map(|table| table.at));
+ err.fix_linecol(|at| self.to_linecol(at));
+ err
+ })
+ }
+
+ // Called when the type to deserialize is an enum, as opposed to a field in the type.
+ fn deserialize_enum<V>(
+ self,
+ _name: &'static str,
+ _variants: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ let (value, name) = self.string_or_table()?;
+ match value.e {
+ E::String(val) => visitor.visit_enum(val.into_deserializer()),
+ E::InlineTable(values) => {
+ if values.len() != 1 {
+ Err(Error::from_kind(
+ Some(value.start),
+ ErrorKind::Wanted {
+ expected: "exactly 1 element",
+ found: if values.is_empty() {
+ "zero elements"
+ } else {
+ "more than 1 element"
+ },
+ },
+ ))
+ } else {
+ visitor.visit_enum(InlineTableDeserializer {
+ values: values.into_iter(),
+ next_value: None,
+ })
+ }
+ }
+ E::DottedTable(_) => visitor.visit_enum(DottedTableDeserializer {
+ name: name.expect("Expected table header to be passed."),
+ value,
+ }),
+ e => Err(Error::from_kind(
+ Some(value.start),
+ ErrorKind::Wanted {
+ expected: "string or table",
+ found: e.type_name(),
+ },
+ )),
+ }
+ }
+
+ fn deserialize_struct<V>(
+ self,
+ name: &'static str,
+ fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ if name == spanned::NAME && fields == [spanned::START, spanned::END, spanned::VALUE] {
+ let start = 0;
+ let end = self.input.len();
+
+ let res = visitor.visit_map(SpannedDeserializer {
+ phantom_data: PhantomData,
+ start: Some(start),
+ value: Some(self),
+ end: Some(end),
+ });
+ return res;
+ }
+
+ self.deserialize_any(visitor)
+ }
+
+ serde::forward_to_deserialize_any! {
+ bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
+ bytes byte_buf map unit newtype_struct
+ ignored_any unit_struct tuple_struct tuple option identifier
+ }
+}
+
+// Builds a datastructure that allows for efficient sublinear lookups.
+// The returned HashMap contains a mapping from table header (like [a.b.c])
+// to list of tables with that precise name. The tables are being identified
+// by their index in the passed slice. We use a list as the implementation
+// uses this data structure for arrays as well as tables,
+// so if any top level [[name]] array contains multiple entries,
+// there are multiple entries in the list.
+// The lookup is performed in the `SeqAccess` implementation of `MapVisitor`.
+// The lists are ordered, which we exploit in the search code by using
+// bisection.
+fn build_table_indices<'de>(tables: &[Table<'de>]) -> HashMap<Vec<Cow<'de, str>>, Vec<usize>> {
+ let mut res = HashMap::new();
+ for (i, table) in tables.iter().enumerate() {
+ let header = table.header.iter().map(|v| v.1.clone()).collect::<Vec<_>>();
+ res.entry(header).or_insert_with(Vec::new).push(i);
+ }
+ res
+}
+
+// Builds a datastructure that allows for efficient sublinear lookups.
+// The returned HashMap contains a mapping from table header (like [a.b.c])
+// to list of tables whose name at least starts with the specified
+// name. So searching for [a.b] would give both [a.b.c.d] as well as [a.b.e].
+// The tables are being identified by their index in the passed slice.
+//
+// A list is used for two reasons: First, the implementation also
+// stores arrays in the same data structure and any top level array
+// of size 2 or greater creates multiple entries in the list with the
+// same shared name. Second, there can be multiple tables sharing
+// the same prefix.
+//
+// The lookup is performed in the `MapAccess` implementation of `MapVisitor`.
+// The lists are ordered, which we exploit in the search code by using
+// bisection.
+fn build_table_pindices<'de>(tables: &[Table<'de>]) -> HashMap<Vec<Cow<'de, str>>, Vec<usize>> {
+ let mut res = HashMap::new();
+ for (i, table) in tables.iter().enumerate() {
+ let header = table.header.iter().map(|v| v.1.clone()).collect::<Vec<_>>();
+ for len in 0..=header.len() {
+ res.entry(header[..len].to_owned())
+ .or_insert_with(Vec::new)
+ .push(i);
+ }
+ }
+ res
+}
+
+fn headers_equal<'a, 'b>(hdr_a: &[(Span, Cow<'a, str>)], hdr_b: &[(Span, Cow<'b, str>)]) -> bool {
+ if hdr_a.len() != hdr_b.len() {
+ return false;
+ }
+ hdr_a.iter().zip(hdr_b.iter()).all(|(h1, h2)| h1.1 == h2.1)
+}
+
+struct Table<'a> {
+ at: usize,
+ header: Vec<(Span, Cow<'a, str>)>,
+ values: Option<Vec<TablePair<'a>>>,
+ array: bool,
+}
+
+struct MapVisitor<'de, 'b> {
+ values: iter::Peekable<vec::IntoIter<TablePair<'de>>>,
+ next_value: Option<TablePair<'de>>,
+ depth: usize,
+ cur: usize,
+ cur_parent: usize,
+ max: usize,
+ table_indices: &'b HashMap<Vec<Cow<'de, str>>, Vec<usize>>,
+ table_pindices: &'b HashMap<Vec<Cow<'de, str>>, Vec<usize>>,
+ tables: &'b mut [Table<'de>],
+ array: bool,
+ de: &'b mut Deserializer<'de>,
+}
+
+impl<'de, 'b> de::MapAccess<'de> for MapVisitor<'de, 'b> {
+ type Error = Error;
+
+ fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
+ where
+ K: de::DeserializeSeed<'de>,
+ {
+ if self.cur_parent == self.max || self.cur == self.max {
+ return Ok(None);
+ }
+
+ loop {
+ assert!(self.next_value.is_none());
+ if let Some((key, value)) = self.values.next() {
+ let ret = seed.deserialize(StrDeserializer::spanned(key.clone()))?;
+ self.next_value = Some((key, value));
+ return Ok(Some(ret));
+ }
+
+ let next_table = {
+ let prefix_stripped = self.tables[self.cur_parent].header[..self.depth]
+ .iter()
+ .map(|v| v.1.clone())
+ .collect::<Vec<_>>();
+ self.table_pindices
+ .get(&prefix_stripped)
+ .and_then(|entries| {
+ let start = entries.binary_search(&self.cur).unwrap_or_else(|v| v);
+ if start == entries.len() || entries[start] < self.cur {
+ return None;
+ }
+ entries[start..]
+ .iter()
+ .filter_map(|i| if *i < self.max { Some(*i) } else { None })
+ .map(|i| (i, &self.tables[i]))
+ .find(|(_, table)| table.values.is_some())
+ .map(|p| p.0)
+ })
+ };
+
+ let pos = match next_table {
+ Some(pos) => pos,
+ None => return Ok(None),
+ };
+ self.cur = pos;
+
+ // Test to see if we're duplicating our parent's table, and if so
+ // then this is an error in the toml format
+ if self.cur_parent != pos {
+ if headers_equal(
+ &self.tables[self.cur_parent].header,
+ &self.tables[pos].header,
+ ) {
+ let at = self.tables[pos].at;
+ let name = self.tables[pos]
+ .header
+ .iter()
+ .map(|k| k.1.to_owned())
+ .collect::<Vec<_>>()
+ .join(".");
+ return Err(self.de.error(at, ErrorKind::DuplicateTable(name)));
+ }
+
+ // If we're here we know we should share the same prefix, and if
+ // the longer table was defined first then we want to narrow
+ // down our parent's length if possible to ensure that we catch
+ // duplicate tables defined afterwards.
+ if !self.de.allow_duplciate_after_longer_table {
+ let parent_len = self.tables[self.cur_parent].header.len();
+ let cur_len = self.tables[pos].header.len();
+ if cur_len < parent_len {
+ self.cur_parent = pos;
+ }
+ }
+ }
+
+ let table = &mut self.tables[pos];
+
+ // If we're not yet at the appropriate depth for this table then we
+ // just next the next portion of its header and then continue
+ // decoding.
+ if self.depth != table.header.len() {
+ let key = &table.header[self.depth];
+ let key = seed.deserialize(StrDeserializer::spanned(key.clone()))?;
+ return Ok(Some(key));
+ }
+
+ // Rule out cases like:
+ //
+ // [[foo.bar]]
+ // [[foo]]
+ if table.array {
+ let kind = ErrorKind::RedefineAsArray;
+ return Err(self.de.error(table.at, kind));
+ }
+
+ self.values = table
+ .values
+ .take()
+ .expect("Unable to read table values")
+ .into_iter()
+ .peekable();
+ }
+ }
+
+ fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
+ where
+ V: de::DeserializeSeed<'de>,
+ {
+ if let Some((k, v)) = self.next_value.take() {
+ match seed.deserialize(ValueDeserializer::new(v)) {
+ Ok(v) => return Ok(v),
+ Err(mut e) => {
+ e.add_key_context(&k.1);
+ return Err(e);
+ }
+ }
+ }
+
+ let array =
+ self.tables[self.cur].array && self.depth == self.tables[self.cur].header.len() - 1;
+ self.cur += 1;
+ let res = seed.deserialize(MapVisitor {
+ values: Vec::new().into_iter().peekable(),
+ next_value: None,
+ depth: self.depth + if array { 0 } else { 1 },
+ cur_parent: self.cur - 1,
+ cur: 0,
+ max: self.max,
+ array,
+ table_indices: self.table_indices,
+ table_pindices: self.table_pindices,
+ tables: &mut *self.tables,
+ de: &mut *self.de,
+ });
+ res.map_err(|mut e| {
+ e.add_key_context(&self.tables[self.cur - 1].header[self.depth].1);
+ e
+ })
+ }
+}
+
+impl<'de, 'b> de::SeqAccess<'de> for MapVisitor<'de, 'b> {
+ type Error = Error;
+
+ fn next_element_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
+ where
+ K: de::DeserializeSeed<'de>,
+ {
+ assert!(self.next_value.is_none());
+ assert!(self.values.next().is_none());
+
+ if self.cur_parent == self.max {
+ return Ok(None);
+ }
+
+ let header_stripped = self.tables[self.cur_parent]
+ .header
+ .iter()
+ .map(|v| v.1.clone())
+ .collect::<Vec<_>>();
+ let start_idx = self.cur_parent + 1;
+ let next = self
+ .table_indices
+ .get(&header_stripped)
+ .and_then(|entries| {
+ let start = entries.binary_search(&start_idx).unwrap_or_else(|v| v);
+ if start == entries.len() || entries[start] < start_idx {
+ return None;
+ }
+ entries[start..]
+ .iter()
+ .filter_map(|i| if *i < self.max { Some(*i) } else { None })
+ .map(|i| (i, &self.tables[i]))
+ .find(|(_, table)| table.array)
+ .map(|p| p.0)
+ })
+ .unwrap_or(self.max);
+
+ let ret = seed.deserialize(MapVisitor {
+ values: self.tables[self.cur_parent]
+ .values
+ .take()
+ .expect("Unable to read table values")
+ .into_iter()
+ .peekable(),
+ next_value: None,
+ depth: self.depth + 1,
+ cur_parent: self.cur_parent,
+ max: next,
+ cur: 0,
+ array: false,
+ table_indices: self.table_indices,
+ table_pindices: self.table_pindices,
+ tables: self.tables,
+ de: self.de,
+ })?;
+ self.cur_parent = next;
+ Ok(Some(ret))
+ }
+}
+
+impl<'de, 'b> de::Deserializer<'de> for MapVisitor<'de, 'b> {
+ type Error = Error;
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ if self.array {
+ visitor.visit_seq(self)
+ } else {
+ visitor.visit_map(self)
+ }
+ }
+
+ // `None` is interpreted as a missing field so be sure to implement `Some`
+ // as a present field.
+ fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ visitor.visit_some(self)
+ }
+
+ fn deserialize_newtype_struct<V>(
+ self,
+ _name: &'static str,
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ visitor.visit_newtype_struct(self)
+ }
+
+ fn deserialize_struct<V>(
+ mut self,
+ name: &'static str,
+ fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ if name == spanned::NAME
+ && fields == [spanned::START, spanned::END, spanned::VALUE]
+ && !(self.array && self.values.peek().is_some())
+ {
+ // TODO we can't actually emit spans here for the *entire* table/array
+ // due to the format that toml uses. Setting the start and end to 0 is
+ // *detectable* (and no reasonable span would look like that),
+ // it would be better to expose this in the API via proper
+ // ADTs like Option<T>.
+ let start = 0;
+ let end = 0;
+
+ let res = visitor.visit_map(SpannedDeserializer {
+ phantom_data: PhantomData,
+ start: Some(start),
+ value: Some(self),
+ end: Some(end),
+ });
+ return res;
+ }
+
+ self.deserialize_any(visitor)
+ }
+
+ fn deserialize_enum<V>(
+ self,
+ _name: &'static str,
+ _variants: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ if self.tables.len() != 1 {
+ return Err(Error::custom(
+ Some(self.cur),
+ "enum table must contain exactly one table".into(),
+ ));
+ }
+ let table = &mut self.tables[0];
+ let values = table.values.take().expect("table has no values?");
+ if table.header.is_empty() {
+ return Err(self.de.error(self.cur, ErrorKind::EmptyTableKey));
+ }
+ let name = table.header[table.header.len() - 1].1.to_owned();
+ visitor.visit_enum(DottedTableDeserializer {
+ name,
+ value: Value {
+ e: E::DottedTable(values),
+ start: 0,
+ end: 0,
+ },
+ })
+ }
+
+ serde::forward_to_deserialize_any! {
+ bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
+ bytes byte_buf map unit identifier
+ ignored_any unit_struct tuple_struct tuple
+ }
+}
+
+struct StrDeserializer<'a> {
+ span: Option<Span>,
+ key: Cow<'a, str>,
+}
+
+impl<'a> StrDeserializer<'a> {
+ fn spanned(inner: (Span, Cow<'a, str>)) -> StrDeserializer<'a> {
+ StrDeserializer {
+ span: Some(inner.0),
+ key: inner.1,
+ }
+ }
+ fn new(key: Cow<'a, str>) -> StrDeserializer<'a> {
+ StrDeserializer { span: None, key }
+ }
+}
+
+impl<'a> de::IntoDeserializer<'a, Error> for StrDeserializer<'a> {
+ type Deserializer = Self;
+
+ fn into_deserializer(self) -> Self::Deserializer {
+ self
+ }
+}
+
+impl<'de> de::Deserializer<'de> for StrDeserializer<'de> {
+ type Error = Error;
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ match self.key {
+ Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
+ Cow::Owned(s) => visitor.visit_string(s),
+ }
+ }
+
+ fn deserialize_struct<V>(
+ self,
+ name: &'static str,
+ fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ if name == spanned::NAME && fields == [spanned::START, spanned::END, spanned::VALUE] {
+ if let Some(span) = self.span {
+ return visitor.visit_map(SpannedDeserializer {
+ phantom_data: PhantomData,
+ start: Some(span.start),
+ value: Some(StrDeserializer::new(self.key)),
+ end: Some(span.end),
+ });
+ }
+ }
+ self.deserialize_any(visitor)
+ }
+
+ serde::forward_to_deserialize_any! {
+ bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
+ bytes byte_buf map option unit newtype_struct
+ ignored_any unit_struct tuple_struct tuple enum identifier
+ }
+}
+
+struct ValueDeserializer<'a> {
+ value: Value<'a>,
+ validate_struct_keys: bool,
+}
+
+impl<'a> ValueDeserializer<'a> {
+ fn new(value: Value<'a>) -> ValueDeserializer<'a> {
+ ValueDeserializer {
+ value,
+ validate_struct_keys: false,
+ }
+ }
+
+ fn with_struct_key_validation(mut self) -> Self {
+ self.validate_struct_keys = true;
+ self
+ }
+}
+
+impl<'de> de::Deserializer<'de> for ValueDeserializer<'de> {
+ type Error = Error;
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ let start = self.value.start;
+ let res = match self.value.e {
+ E::Integer(i) => visitor.visit_i64(i),
+ E::Boolean(b) => visitor.visit_bool(b),
+ E::Float(f) => visitor.visit_f64(f),
+ E::String(Cow::Borrowed(s)) => visitor.visit_borrowed_str(s),
+ E::String(Cow::Owned(s)) => visitor.visit_string(s),
+ E::Datetime(s) => visitor.visit_map(DatetimeDeserializer {
+ date: s,
+ visited: false,
+ }),
+ E::Array(values) => {
+ let mut s = de::value::SeqDeserializer::new(values.into_iter());
+ let ret = visitor.visit_seq(&mut s)?;
+ s.end()?;
+ Ok(ret)
+ }
+ E::InlineTable(values) | E::DottedTable(values) => {
+ visitor.visit_map(InlineTableDeserializer {
+ values: values.into_iter(),
+ next_value: None,
+ })
+ }
+ };
+ res.map_err(|mut err| {
+ // Attribute the error to whatever value returned the error.
+ err.fix_offset(|| Some(start));
+ err
+ })
+ }
+
+ fn deserialize_struct<V>(
+ self,
+ name: &'static str,
+ fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ if name == datetime::NAME && fields == [datetime::FIELD] {
+ if let E::Datetime(s) = self.value.e {
+ return visitor.visit_map(DatetimeDeserializer {
+ date: s,
+ visited: false,
+ });
+ }
+ }
+
+ if self.validate_struct_keys {
+ match self.value.e {
+ E::InlineTable(ref values) | E::DottedTable(ref values) => {
+ let extra_fields = values
+ .iter()
+ .filter_map(|key_value| {
+ let (ref key, ref _val) = *key_value;
+ if !fields.contains(&&*(key.1)) {
+ Some(key.clone())
+ } else {
+ None
+ }
+ })
+ .collect::<Vec<_>>();
+
+ if !extra_fields.is_empty() {
+ return Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::UnexpectedKeys {
+ keys: extra_fields
+ .iter()
+ .map(|k| k.1.to_string())
+ .collect::<Vec<_>>(),
+ available: fields,
+ },
+ ));
+ }
+ }
+ _ => {}
+ }
+ }
+
+ if name == spanned::NAME && fields == [spanned::START, spanned::END, spanned::VALUE] {
+ let start = self.value.start;
+ let end = self.value.end;
+
+ return visitor.visit_map(SpannedDeserializer {
+ phantom_data: PhantomData,
+ start: Some(start),
+ value: Some(self.value),
+ end: Some(end),
+ });
+ }
+
+ self.deserialize_any(visitor)
+ }
+
+ // `None` is interpreted as a missing field so be sure to implement `Some`
+ // as a present field.
+ fn deserialize_option<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ visitor.visit_some(self)
+ }
+
+ fn deserialize_enum<V>(
+ self,
+ _name: &'static str,
+ _variants: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ match self.value.e {
+ E::String(val) => visitor.visit_enum(val.into_deserializer()),
+ E::InlineTable(values) => {
+ if values.len() != 1 {
+ Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::Wanted {
+ expected: "exactly 1 element",
+ found: if values.is_empty() {
+ "zero elements"
+ } else {
+ "more than 1 element"
+ },
+ },
+ ))
+ } else {
+ visitor.visit_enum(InlineTableDeserializer {
+ values: values.into_iter(),
+ next_value: None,
+ })
+ }
+ }
+ e => Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::Wanted {
+ expected: "string or inline table",
+ found: e.type_name(),
+ },
+ )),
+ }
+ }
+
+ fn deserialize_newtype_struct<V>(
+ self,
+ _name: &'static str,
+ visitor: V,
+ ) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ visitor.visit_newtype_struct(self)
+ }
+
+ serde::forward_to_deserialize_any! {
+ bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
+ bytes byte_buf map unit identifier
+ ignored_any unit_struct tuple_struct tuple
+ }
+}
+
+impl<'de, 'b> de::IntoDeserializer<'de, Error> for MapVisitor<'de, 'b> {
+ type Deserializer = MapVisitor<'de, 'b>;
+
+ fn into_deserializer(self) -> Self::Deserializer {
+ self
+ }
+}
+
+impl<'de, 'b> de::IntoDeserializer<'de, Error> for &'b mut Deserializer<'de> {
+ type Deserializer = Self;
+
+ fn into_deserializer(self) -> Self::Deserializer {
+ self
+ }
+}
+
+impl<'de> de::IntoDeserializer<'de, Error> for Value<'de> {
+ type Deserializer = ValueDeserializer<'de>;
+
+ fn into_deserializer(self) -> Self::Deserializer {
+ ValueDeserializer::new(self)
+ }
+}
+
+struct SpannedDeserializer<'de, T: de::IntoDeserializer<'de, Error>> {
+ phantom_data: PhantomData<&'de ()>,
+ start: Option<usize>,
+ end: Option<usize>,
+ value: Option<T>,
+}
+
+impl<'de, T> de::MapAccess<'de> for SpannedDeserializer<'de, T>
+where
+ T: de::IntoDeserializer<'de, Error>,
+{
+ type Error = Error;
+
+ fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
+ where
+ K: de::DeserializeSeed<'de>,
+ {
+ if self.start.is_some() {
+ seed.deserialize(BorrowedStrDeserializer::new(spanned::START))
+ .map(Some)
+ } else if self.end.is_some() {
+ seed.deserialize(BorrowedStrDeserializer::new(spanned::END))
+ .map(Some)
+ } else if self.value.is_some() {
+ seed.deserialize(BorrowedStrDeserializer::new(spanned::VALUE))
+ .map(Some)
+ } else {
+ Ok(None)
+ }
+ }
+
+ fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
+ where
+ V: de::DeserializeSeed<'de>,
+ {
+ if let Some(start) = self.start.take() {
+ seed.deserialize(start.into_deserializer())
+ } else if let Some(end) = self.end.take() {
+ seed.deserialize(end.into_deserializer())
+ } else if let Some(value) = self.value.take() {
+ seed.deserialize(value.into_deserializer())
+ } else {
+ panic!("next_value_seed called before next_key_seed")
+ }
+ }
+}
+
+struct DatetimeDeserializer<'a> {
+ visited: bool,
+ date: &'a str,
+}
+
+impl<'de> de::MapAccess<'de> for DatetimeDeserializer<'de> {
+ type Error = Error;
+
+ fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
+ where
+ K: de::DeserializeSeed<'de>,
+ {
+ if self.visited {
+ return Ok(None);
+ }
+ self.visited = true;
+ seed.deserialize(DatetimeFieldDeserializer).map(Some)
+ }
+
+ fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
+ where
+ V: de::DeserializeSeed<'de>,
+ {
+ seed.deserialize(StrDeserializer::new(self.date.into()))
+ }
+}
+
+struct DatetimeFieldDeserializer;
+
+impl<'de> de::Deserializer<'de> for DatetimeFieldDeserializer {
+ type Error = Error;
+
+ fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ visitor.visit_borrowed_str(datetime::FIELD)
+ }
+
+ serde::forward_to_deserialize_any! {
+ bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string seq
+ bytes byte_buf map struct option unit newtype_struct
+ ignored_any unit_struct tuple_struct tuple enum identifier
+ }
+}
+
+struct DottedTableDeserializer<'a> {
+ name: Cow<'a, str>,
+ value: Value<'a>,
+}
+
+impl<'de> de::EnumAccess<'de> for DottedTableDeserializer<'de> {
+ type Error = Error;
+ type Variant = TableEnumDeserializer<'de>;
+
+ fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
+ where
+ V: de::DeserializeSeed<'de>,
+ {
+ let (name, value) = (self.name, self.value);
+ seed.deserialize(StrDeserializer::new(name))
+ .map(|val| (val, TableEnumDeserializer { value }))
+ }
+}
+
+struct InlineTableDeserializer<'a> {
+ values: vec::IntoIter<TablePair<'a>>,
+ next_value: Option<Value<'a>>,
+}
+
+impl<'de> de::MapAccess<'de> for InlineTableDeserializer<'de> {
+ type Error = Error;
+
+ fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error>
+ where
+ K: de::DeserializeSeed<'de>,
+ {
+ let (key, value) = match self.values.next() {
+ Some(pair) => pair,
+ None => return Ok(None),
+ };
+ self.next_value = Some(value);
+ seed.deserialize(StrDeserializer::spanned(key)).map(Some)
+ }
+
+ fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error>
+ where
+ V: de::DeserializeSeed<'de>,
+ {
+ let value = self.next_value.take().expect("Unable to read table values");
+ seed.deserialize(ValueDeserializer::new(value))
+ }
+}
+
+impl<'de> de::EnumAccess<'de> for InlineTableDeserializer<'de> {
+ type Error = Error;
+ type Variant = TableEnumDeserializer<'de>;
+
+ fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
+ where
+ V: de::DeserializeSeed<'de>,
+ {
+ let (key, value) = match self.values.next() {
+ Some(pair) => pair,
+ None => {
+ return Err(Error::from_kind(
+ None, // FIXME: How do we get an offset here?
+ ErrorKind::Wanted {
+ expected: "table with exactly 1 entry",
+ found: "empty table",
+ },
+ ));
+ }
+ };
+
+ seed.deserialize(StrDeserializer::new(key.1))
+ .map(|val| (val, TableEnumDeserializer { value }))
+ }
+}
+
+/// Deserializes table values into enum variants.
+struct TableEnumDeserializer<'a> {
+ value: Value<'a>,
+}
+
+impl<'de> de::VariantAccess<'de> for TableEnumDeserializer<'de> {
+ type Error = Error;
+
+ fn unit_variant(self) -> Result<(), Self::Error> {
+ match self.value.e {
+ E::InlineTable(values) | E::DottedTable(values) => {
+ if values.is_empty() {
+ Ok(())
+ } else {
+ Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::ExpectedEmptyTable,
+ ))
+ }
+ }
+ e => Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::Wanted {
+ expected: "table",
+ found: e.type_name(),
+ },
+ )),
+ }
+ }
+
+ fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
+ where
+ T: de::DeserializeSeed<'de>,
+ {
+ seed.deserialize(ValueDeserializer::new(self.value))
+ }
+
+ fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ match self.value.e {
+ E::InlineTable(values) | E::DottedTable(values) => {
+ let tuple_values = values
+ .into_iter()
+ .enumerate()
+ .map(|(index, (key, value))| match key.1.parse::<usize>() {
+ Ok(key_index) if key_index == index => Ok(value),
+ Ok(_) | Err(_) => Err(Error::from_kind(
+ Some(key.0.start),
+ ErrorKind::ExpectedTupleIndex {
+ expected: index,
+ found: key.1.to_string(),
+ },
+ )),
+ })
+ // Fold all values into a `Vec`, or return the first error.
+ .fold(Ok(Vec::with_capacity(len)), |result, value_result| {
+ result.and_then(move |mut tuple_values| match value_result {
+ Ok(value) => {
+ tuple_values.push(value);
+ Ok(tuple_values)
+ }
+ // `Result<de::Value, Self::Error>` to `Result<Vec<_>, Self::Error>`
+ Err(e) => Err(e),
+ })
+ })?;
+
+ if tuple_values.len() == len {
+ de::Deserializer::deserialize_seq(
+ ValueDeserializer::new(Value {
+ e: E::Array(tuple_values),
+ start: self.value.start,
+ end: self.value.end,
+ }),
+ visitor,
+ )
+ } else {
+ Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::ExpectedTuple(len),
+ ))
+ }
+ }
+ e => Err(Error::from_kind(
+ Some(self.value.start),
+ ErrorKind::Wanted {
+ expected: "table",
+ found: e.type_name(),
+ },
+ )),
+ }
+ }
+
+ fn struct_variant<V>(
+ self,
+ fields: &'static [&'static str],
+ visitor: V,
+ ) -> Result<V::Value, Self::Error>
+ where
+ V: de::Visitor<'de>,
+ {
+ de::Deserializer::deserialize_struct(
+ ValueDeserializer::new(self.value).with_struct_key_validation(),
+ "", // TODO: this should be the variant name
+ fields,
+ visitor,
+ )
+ }
+}
+
+impl<'a> Deserializer<'a> {
+ /// Creates a new deserializer which will be deserializing the string
+ /// provided.
+ pub fn new(input: &'a str) -> Deserializer<'a> {
+ Deserializer {
+ tokens: Tokenizer::new(input),
+ input,
+ require_newline_after_table: true,
+ allow_duplciate_after_longer_table: false,
+ }
+ }
+
+ #[doc(hidden)]
+ #[deprecated(since = "0.5.11")]
+ pub fn end(&mut self) -> Result<(), Error> {
+ Ok(())
+ }
+
+ #[doc(hidden)]
+ #[deprecated(since = "0.5.11")]
+ pub fn set_require_newline_after_table(&mut self, require: bool) {
+ self.require_newline_after_table = require;
+ }
+
+ #[doc(hidden)]
+ #[deprecated(since = "0.5.11")]
+ pub fn set_allow_duplicate_after_longer_table(&mut self, allow: bool) {
+ self.allow_duplciate_after_longer_table = allow;
+ }
+
+ fn tables(&mut self) -> Result<Vec<Table<'a>>, Error> {
+ let mut tables = Vec::new();
+ let mut cur_table = Table {
+ at: 0,
+ header: Vec::new(),
+ values: None,
+ array: false,
+ };
+
+ while let Some(line) = self.line()? {
+ match line {
+ Line::Table {
+ at,
+ mut header,
+ array,
+ } => {
+ if !cur_table.header.is_empty() || cur_table.values.is_some() {
+ tables.push(cur_table);
+ }
+ cur_table = Table {
+ at,
+ header: Vec::new(),
+ values: Some(Vec::new()),
+ array,
+ };
+ loop {
+ let part = header.next().map_err(|e| self.token_error(e));
+ match part? {
+ Some(part) => cur_table.header.push(part),
+ None => break,
+ }
+ }
+ }
+ Line::KeyValue(key, value) => {
+ if cur_table.values.is_none() {
+ cur_table.values = Some(Vec::new());
+ }
+ self.add_dotted_key(key, value, cur_table.values.as_mut().unwrap())?;
+ }
+ }
+ }
+ if !cur_table.header.is_empty() || cur_table.values.is_some() {
+ tables.push(cur_table);
+ }
+ Ok(tables)
+ }
+
+ fn line(&mut self) -> Result<Option<Line<'a>>, Error> {
+ loop {
+ self.eat_whitespace()?;
+ if self.eat_comment()? {
+ continue;
+ }
+ if self.eat(Token::Newline)? {
+ continue;
+ }
+ break;
+ }
+
+ match self.peek()? {
+ Some((_, Token::LeftBracket)) => self.table_header().map(Some),
+ Some(_) => self.key_value().map(Some),
+ None => Ok(None),
+ }
+ }
+
+ fn table_header(&mut self) -> Result<Line<'a>, Error> {
+ let start = self.tokens.current();
+ self.expect(Token::LeftBracket)?;
+ let array = self.eat(Token::LeftBracket)?;
+ let ret = Header::new(self.tokens.clone(), array, self.require_newline_after_table);
+ if self.require_newline_after_table {
+ self.tokens.skip_to_newline();
+ } else {
+ loop {
+ match self.next()? {
+ Some((_, Token::RightBracket)) => {
+ if array {
+ self.eat(Token::RightBracket)?;
+ }
+ break;
+ }
+ Some((_, Token::Newline)) | None => break,
+ _ => {}
+ }
+ }
+ self.eat_whitespace()?;
+ }
+ Ok(Line::Table {
+ at: start,
+ header: ret,
+ array,
+ })
+ }
+
+ fn key_value(&mut self) -> Result<Line<'a>, Error> {
+ let key = self.dotted_key()?;
+ self.eat_whitespace()?;
+ self.expect(Token::Equals)?;
+ self.eat_whitespace()?;
+
+ let value = self.value()?;
+ self.eat_whitespace()?;
+ if !self.eat_comment()? {
+ self.eat_newline_or_eof()?;
+ }
+
+ Ok(Line::KeyValue(key, value))
+ }
+
+ fn value(&mut self) -> Result<Value<'a>, Error> {
+ let at = self.tokens.current();
+ let value = match self.next()? {
+ Some((Span { start, end }, Token::String { val, .. })) => Value {
+ e: E::String(val),
+ start,
+ end,
+ },
+ Some((Span { start, end }, Token::Keylike("true"))) => Value {
+ e: E::Boolean(true),
+ start,
+ end,
+ },
+ Some((Span { start, end }, Token::Keylike("false"))) => Value {
+ e: E::Boolean(false),
+ start,
+ end,
+ },
+ Some((span, Token::Keylike(key))) => self.parse_keylike(at, span, key)?,
+ Some((span, Token::Plus)) => self.number_leading_plus(span)?,
+ Some((Span { start, .. }, Token::LeftBrace)) => {
+ self.inline_table().map(|(Span { end, .. }, table)| Value {
+ e: E::InlineTable(table),
+ start,
+ end,
+ })?
+ }
+ Some((Span { start, .. }, Token::LeftBracket)) => {
+ self.array().map(|(Span { end, .. }, array)| Value {
+ e: E::Array(array),
+ start,
+ end,
+ })?
+ }
+ Some(token) => {
+ return Err(self.error(
+ at,
+ ErrorKind::Wanted {
+ expected: "a value",
+ found: token.1.describe(),
+ },
+ ));
+ }
+ None => return Err(self.eof()),
+ };
+ Ok(value)
+ }
+
+ fn parse_keylike(&mut self, at: usize, span: Span, key: &'a str) -> Result<Value<'a>, Error> {
+ if key == "inf" || key == "nan" {
+ return self.number_or_date(span, key);
+ }
+
+ let first_char = key.chars().next().expect("key should not be empty here");
+ match first_char {
+ '-' | '0'..='9' => self.number_or_date(span, key),
+ _ => Err(self.error(at, ErrorKind::UnquotedString)),
+ }
+ }
+
+ fn number_or_date(&mut self, span: Span, s: &'a str) -> Result<Value<'a>, Error> {
+ if s.contains('T')
+ || s.contains('t')
+ || (s.len() > 1 && s[1..].contains('-') && !s.contains("e-") && !s.contains("E-"))
+ {
+ self.datetime(span, s, false)
+ .map(|(Span { start, end }, d)| Value {
+ e: E::Datetime(d),
+ start,
+ end,
+ })
+ } else if self.eat(Token::Colon)? {
+ self.datetime(span, s, true)
+ .map(|(Span { start, end }, d)| Value {
+ e: E::Datetime(d),
+ start,
+ end,
+ })
+ } else {
+ self.number(span, s)
+ }
+ }
+
+ /// Returns a string or table value type.
+ ///
+ /// Used to deserialize enums. Unit enums may be represented as a string or a table, all other
+ /// structures (tuple, newtype, struct) must be represented as a table.
+ fn string_or_table(&mut self) -> Result<(Value<'a>, Option<Cow<'a, str>>), Error> {
+ match self.peek()? {
+ Some((span, Token::LeftBracket)) => {
+ let tables = self.tables()?;
+ if tables.len() != 1 {
+ return Err(Error::from_kind(
+ Some(span.start),
+ ErrorKind::Wanted {
+ expected: "exactly 1 table",
+ found: if tables.is_empty() {
+ "zero tables"
+ } else {
+ "more than 1 table"
+ },
+ },
+ ));
+ }
+
+ let table = tables
+ .into_iter()
+ .next()
+ .expect("Expected exactly one table");
+ let header = table
+ .header
+ .last()
+ .expect("Expected at least one header value for table.");
+
+ let start = table.at;
+ let end = table
+ .values
+ .as_ref()
+ .and_then(|values| values.last())
+ .map(|&(_, ref val)| val.end)
+ .unwrap_or_else(|| header.1.len());
+ Ok((
+ Value {
+ e: E::DottedTable(table.values.unwrap_or_default()),
+ start,
+ end,
+ },
+ Some(header.1.clone()),
+ ))
+ }
+ Some(_) => self.value().map(|val| (val, None)),
+ None => Err(self.eof()),
+ }
+ }
+
+ fn number(&mut self, Span { start, end }: Span, s: &'a str) -> Result<Value<'a>, Error> {
+ let to_integer = |f| Value {
+ e: E::Integer(f),
+ start,
+ end,
+ };
+ if let Some(value) = s.strip_prefix("0x") {
+ self.integer(value, 16).map(to_integer)
+ } else if let Some(value) = s.strip_prefix("0o") {
+ self.integer(value, 8).map(to_integer)
+ } else if let Some(value) = s.strip_prefix("0b") {
+ self.integer(value, 2).map(to_integer)
+ } else if s.contains('e') || s.contains('E') {
+ self.float(s, None).map(|f| Value {
+ e: E::Float(f),
+ start,
+ end,
+ })
+ } else if self.eat(Token::Period)? {
+ let at = self.tokens.current();
+ match self.next()? {
+ Some((Span { start, end }, Token::Keylike(after))) => {
+ self.float(s, Some(after)).map(|f| Value {
+ e: E::Float(f),
+ start,
+ end,
+ })
+ }
+ _ => Err(self.error(at, ErrorKind::NumberInvalid)),
+ }
+ } else if s == "inf" {
+ Ok(Value {
+ e: E::Float(f64::INFINITY),
+ start,
+ end,
+ })
+ } else if s == "-inf" {
+ Ok(Value {
+ e: E::Float(f64::NEG_INFINITY),
+ start,
+ end,
+ })
+ } else if s == "nan" {
+ Ok(Value {
+ e: E::Float(f64::NAN),
+ start,
+ end,
+ })
+ } else if s == "-nan" {
+ Ok(Value {
+ e: E::Float(-f64::NAN),
+ start,
+ end,
+ })
+ } else {
+ self.integer(s, 10).map(to_integer)
+ }
+ }
+
+ fn number_leading_plus(&mut self, Span { start, .. }: Span) -> Result<Value<'a>, Error> {
+ let start_token = self.tokens.current();
+ match self.next()? {
+ Some((Span { end, .. }, Token::Keylike(s))) => self.number(Span { start, end }, s),
+ _ => Err(self.error(start_token, ErrorKind::NumberInvalid)),
+ }
+ }
+
+ fn integer(&self, s: &'a str, radix: u32) -> Result<i64, Error> {
+ let allow_sign = radix == 10;
+ let allow_leading_zeros = radix != 10;
+ let (prefix, suffix) = self.parse_integer(s, allow_sign, allow_leading_zeros, radix)?;
+ let start = self.tokens.substr_offset(s);
+ if !suffix.is_empty() {
+ return Err(self.error(start, ErrorKind::NumberInvalid));
+ }
+ i64::from_str_radix(prefix.replace('_', "").trim_start_matches('+'), radix)
+ .map_err(|_e| self.error(start, ErrorKind::NumberInvalid))
+ }
+
+ fn parse_integer(
+ &self,
+ s: &'a str,
+ allow_sign: bool,
+ allow_leading_zeros: bool,
+ radix: u32,
+ ) -> Result<(&'a str, &'a str), Error> {
+ let start = self.tokens.substr_offset(s);
+
+ let mut first = true;
+ let mut first_zero = false;
+ let mut underscore = false;
+ let mut end = s.len();
+ for (i, c) in s.char_indices() {
+ let at = i + start;
+ if i == 0 && (c == '+' || c == '-') && allow_sign {
+ continue;
+ }
+
+ if c == '0' && first {
+ first_zero = true;
+ } else if c.is_digit(radix) {
+ if !first && first_zero && !allow_leading_zeros {
+ return Err(self.error(at, ErrorKind::NumberInvalid));
+ }
+ underscore = false;
+ } else if c == '_' && first {
+ return Err(self.error(at, ErrorKind::NumberInvalid));
+ } else if c == '_' && !underscore {
+ underscore = true;
+ } else {
+ end = i;
+ break;
+ }
+ first = false;
+ }
+ if first || underscore {
+ return Err(self.error(start, ErrorKind::NumberInvalid));
+ }
+ Ok((&s[..end], &s[end..]))
+ }
+
+ fn float(&mut self, s: &'a str, after_decimal: Option<&'a str>) -> Result<f64, Error> {
+ let (integral, mut suffix) = self.parse_integer(s, true, false, 10)?;
+ let start = self.tokens.substr_offset(integral);
+
+ let mut fraction = None;
+ if let Some(after) = after_decimal {
+ if !suffix.is_empty() {
+ return Err(self.error(start, ErrorKind::NumberInvalid));
+ }
+ let (a, b) = self.parse_integer(after, false, true, 10)?;
+ fraction = Some(a);
+ suffix = b;
+ }
+
+ let mut exponent = None;
+ if suffix.starts_with('e') || suffix.starts_with('E') {
+ let (a, b) = if suffix.len() == 1 {
+ self.eat(Token::Plus)?;
+ match self.next()? {
+ Some((_, Token::Keylike(s))) => self.parse_integer(s, false, true, 10)?,
+ _ => return Err(self.error(start, ErrorKind::NumberInvalid)),
+ }
+ } else {
+ self.parse_integer(&suffix[1..], true, true, 10)?
+ };
+ if !b.is_empty() {
+ return Err(self.error(start, ErrorKind::NumberInvalid));
+ }
+ exponent = Some(a);
+ } else if !suffix.is_empty() {
+ return Err(self.error(start, ErrorKind::NumberInvalid));
+ }
+
+ let mut number = integral
+ .trim_start_matches('+')
+ .chars()
+ .filter(|c| *c != '_')
+ .collect::<String>();
+ if let Some(fraction) = fraction {
+ number.push('.');
+ number.extend(fraction.chars().filter(|c| *c != '_'));
+ }
+ if let Some(exponent) = exponent {
+ number.push('E');
+ number.extend(exponent.chars().filter(|c| *c != '_'));
+ }
+ number
+ .parse()
+ .map_err(|_e| self.error(start, ErrorKind::NumberInvalid))
+ .and_then(|n: f64| {
+ if n.is_finite() {
+ Ok(n)
+ } else {
+ Err(self.error(start, ErrorKind::NumberInvalid))
+ }
+ })
+ }
+
+ fn datetime(
+ &mut self,
+ mut span: Span,
+ date: &'a str,
+ colon_eaten: bool,
+ ) -> Result<(Span, &'a str), Error> {
+ let start = self.tokens.substr_offset(date);
+
+ // Check for space separated date and time.
+ let mut lookahead = self.tokens.clone();
+ if let Ok(Some((_, Token::Whitespace(" ")))) = lookahead.next() {
+ // Check if hour follows.
+ if let Ok(Some((_, Token::Keylike(_)))) = lookahead.next() {
+ self.next()?; // skip space
+ self.next()?; // skip keylike hour
+ }
+ }
+
+ if colon_eaten || self.eat(Token::Colon)? {
+ // minutes
+ match self.next()? {
+ Some((_, Token::Keylike(_))) => {}
+ _ => return Err(self.error(start, ErrorKind::DateInvalid)),
+ }
+ // Seconds
+ self.expect(Token::Colon)?;
+ match self.next()? {
+ Some((Span { end, .. }, Token::Keylike(_))) => {
+ span.end = end;
+ }
+ _ => return Err(self.error(start, ErrorKind::DateInvalid)),
+ }
+ // Fractional seconds
+ if self.eat(Token::Period)? {
+ match self.next()? {
+ Some((Span { end, .. }, Token::Keylike(_))) => {
+ span.end = end;
+ }
+ _ => return Err(self.error(start, ErrorKind::DateInvalid)),
+ }
+ }
+
+ // offset
+ if self.eat(Token::Plus)? {
+ match self.next()? {
+ Some((Span { end, .. }, Token::Keylike(_))) => {
+ span.end = end;
+ }
+ _ => return Err(self.error(start, ErrorKind::DateInvalid)),
+ }
+ }
+ if self.eat(Token::Colon)? {
+ match self.next()? {
+ Some((Span { end, .. }, Token::Keylike(_))) => {
+ span.end = end;
+ }
+ _ => return Err(self.error(start, ErrorKind::DateInvalid)),
+ }
+ }
+ }
+
+ let end = self.tokens.current();
+ Ok((span, &self.tokens.input()[start..end]))
+ }
+
+ // TODO(#140): shouldn't buffer up this entire table in memory, it'd be
+ // great to defer parsing everything until later.
+ fn inline_table(&mut self) -> Result<(Span, Vec<TablePair<'a>>), Error> {
+ let mut ret = Vec::new();
+ self.eat_whitespace()?;
+ if let Some(span) = self.eat_spanned(Token::RightBrace)? {
+ return Ok((span, ret));
+ }
+ loop {
+ let key = self.dotted_key()?;
+ self.eat_whitespace()?;
+ self.expect(Token::Equals)?;
+ self.eat_whitespace()?;
+ let value = self.value()?;
+ self.add_dotted_key(key, value, &mut ret)?;
+
+ self.eat_whitespace()?;
+ if let Some(span) = self.eat_spanned(Token::RightBrace)? {
+ return Ok((span, ret));
+ }
+ self.expect(Token::Comma)?;
+ self.eat_whitespace()?;
+ }
+ }
+
+ // TODO(#140): shouldn't buffer up this entire array in memory, it'd be
+ // great to defer parsing everything until later.
+ fn array(&mut self) -> Result<(Span, Vec<Value<'a>>), Error> {
+ let mut ret = Vec::new();
+
+ let intermediate = |me: &mut Deserializer<'_>| {
+ loop {
+ me.eat_whitespace()?;
+ if !me.eat(Token::Newline)? && !me.eat_comment()? {
+ break;
+ }
+ }
+ Ok(())
+ };
+
+ loop {
+ intermediate(self)?;
+ if let Some(span) = self.eat_spanned(Token::RightBracket)? {
+ return Ok((span, ret));
+ }
+ let value = self.value()?;
+ ret.push(value);
+ intermediate(self)?;
+ if !self.eat(Token::Comma)? {
+ break;
+ }
+ }
+ intermediate(self)?;
+ let span = self.expect_spanned(Token::RightBracket)?;
+ Ok((span, ret))
+ }
+
+ fn table_key(&mut self) -> Result<(Span, Cow<'a, str>), Error> {
+ self.tokens.table_key().map_err(|e| self.token_error(e))
+ }
+
+ fn dotted_key(&mut self) -> Result<Vec<(Span, Cow<'a, str>)>, Error> {
+ let mut result = vec![self.table_key()?];
+ self.eat_whitespace()?;
+ while self.eat(Token::Period)? {
+ self.eat_whitespace()?;
+ result.push(self.table_key()?);
+ self.eat_whitespace()?;
+ }
+ Ok(result)
+ }
+
+ /// Stores a value in the appropriate hierarchical structure positioned based on the dotted key.
+ ///
+ /// Given the following definition: `multi.part.key = "value"`, `multi` and `part` are
+ /// intermediate parts which are mapped to the relevant fields in the deserialized type's data
+ /// hierarchy.
+ ///
+ /// # Parameters
+ ///
+ /// * `key_parts`: Each segment of the dotted key, e.g. `part.one` maps to
+ /// `vec![Cow::Borrowed("part"), Cow::Borrowed("one")].`
+ /// * `value`: The parsed value.
+ /// * `values`: The `Vec` to store the value in.
+ fn add_dotted_key(
+ &self,
+ mut key_parts: Vec<(Span, Cow<'a, str>)>,
+ value: Value<'a>,
+ values: &mut Vec<TablePair<'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.1 == key.1) {
+ 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 table_values = Value {
+ e: E::DottedTable(Vec::new()),
+ start: value.start,
+ end: value.end,
+ };
+ values.push((key, table_values));
+ 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))
+ }
+
+ fn eat_comment(&mut self) -> Result<bool, Error> {
+ self.tokens.eat_comment().map_err(|e| self.token_error(e))
+ }
+
+ fn eat_newline_or_eof(&mut self) -> Result<(), Error> {
+ self.tokens
+ .eat_newline_or_eof()
+ .map_err(|e| self.token_error(e))
+ }
+
+ fn eat(&mut self, expected: Token<'a>) -> Result<bool, Error> {
+ self.tokens.eat(expected).map_err(|e| self.token_error(e))
+ }
+
+ fn eat_spanned(&mut self, expected: Token<'a>) -> Result<Option<Span>, Error> {
+ self.tokens
+ .eat_spanned(expected)
+ .map_err(|e| self.token_error(e))
+ }
+
+ fn expect(&mut self, expected: Token<'a>) -> Result<(), Error> {
+ self.tokens
+ .expect(expected)
+ .map_err(|e| self.token_error(e))
+ }
+
+ fn expect_spanned(&mut self, expected: Token<'a>) -> Result<Span, Error> {
+ self.tokens
+ .expect_spanned(expected)
+ .map_err(|e| self.token_error(e))
+ }
+
+ fn next(&mut self) -> Result<Option<(Span, Token<'a>)>, Error> {
+ self.tokens.next().map_err(|e| self.token_error(e))
+ }
+
+ fn peek(&mut self) -> Result<Option<(Span, Token<'a>)>, Error> {
+ self.tokens.peek().map_err(|e| self.token_error(e))
+ }
+
+ fn eof(&self) -> Error {
+ self.error(self.input.len(), ErrorKind::UnexpectedEof)
+ }
+
+ fn token_error(&self, error: TokenError) -> Error {
+ match error {
+ TokenError::InvalidCharInString(at, ch) => {
+ self.error(at, ErrorKind::InvalidCharInString(ch))
+ }
+ TokenError::InvalidEscape(at, ch) => self.error(at, ErrorKind::InvalidEscape(ch)),
+ TokenError::InvalidEscapeValue(at, v) => {
+ self.error(at, ErrorKind::InvalidEscapeValue(v))
+ }
+ TokenError::InvalidHexEscape(at, ch) => self.error(at, ErrorKind::InvalidHexEscape(ch)),
+ TokenError::NewlineInString(at) => self.error(at, ErrorKind::NewlineInString),
+ TokenError::Unexpected(at, ch) => self.error(at, ErrorKind::Unexpected(ch)),
+ TokenError::UnterminatedString(at) => self.error(at, ErrorKind::UnterminatedString),
+ TokenError::NewlineInTableKey(at) => self.error(at, ErrorKind::NewlineInTableKey),
+ TokenError::Wanted {
+ at,
+ expected,
+ found,
+ } => self.error(at, ErrorKind::Wanted { expected, found }),
+ TokenError::MultilineStringKey(at) => self.error(at, ErrorKind::MultilineStringKey),
+ }
+ }
+
+ fn error(&self, at: usize, kind: ErrorKind) -> Error {
+ let mut err = Error::from_kind(Some(at), kind);
+ err.fix_linecol(|at| self.to_linecol(at));
+ err
+ }
+
+ /// Converts a byte offset from an error message to a (line, column) pair
+ ///
+ /// All indexes are 0-based.
+ fn to_linecol(&self, offset: usize) -> (usize, usize) {
+ let mut cur = 0;
+ // Use split_terminator instead of lines so that if there is a `\r`,
+ // it is included in the offset calculation. The `+1` values below
+ // account for the `\n`.
+ for (i, line) in self.input.split_terminator('\n').enumerate() {
+ if cur + line.len() + 1 > offset {
+ return (i, offset - cur);
+ }
+ cur += line.len() + 1;
+ }
+ (self.input.lines().count(), 0)
+ }
+}
+
+impl Error {
+ /// Produces a (line, column) pair of the position of the error if available
+ ///
+ /// All indexes are 0-based.
+ pub fn line_col(&self) -> Option<(usize, usize)> {
+ self.inner.line.map(|line| (line, self.inner.col))
+ }
+
+ fn from_kind(at: Option<usize>, kind: ErrorKind) -> Error {
+ Error {
+ inner: Box::new(ErrorInner {
+ kind,
+ line: None,
+ col: 0,
+ at,
+ message: String::new(),
+ key: Vec::new(),
+ }),
+ }
+ }
+
+ fn custom(at: Option<usize>, s: String) -> Error {
+ Error {
+ inner: Box::new(ErrorInner {
+ kind: ErrorKind::Custom,
+ line: None,
+ col: 0,
+ at,
+ message: s,
+ key: Vec::new(),
+ }),
+ }
+ }
+
+ pub(crate) fn add_key_context(&mut self, key: &str) {
+ self.inner.key.insert(0, key.to_string());
+ }
+
+ fn fix_offset<F>(&mut self, f: F)
+ where
+ F: FnOnce() -> Option<usize>,
+ {
+ // An existing offset is always better positioned than anything we
+ // might want to add later.
+ if self.inner.at.is_none() {
+ self.inner.at = f();
+ }
+ }
+
+ fn fix_linecol<F>(&mut self, f: F)
+ where
+ F: FnOnce(usize) -> (usize, usize),
+ {
+ if let Some(at) = self.inner.at {
+ let (line, col) = f(at);
+ self.inner.line = Some(line);
+ self.inner.col = col;
+ }
+ }
+}
+
+impl std::convert::From<Error> for std::io::Error {
+ fn from(e: Error) -> Self {
+ std::io::Error::new(std::io::ErrorKind::InvalidData, e.to_string())
+ }
+}
+
+impl fmt::Display for Error {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match &self.inner.kind {
+ ErrorKind::UnexpectedEof => "unexpected eof encountered".fmt(f)?,
+ ErrorKind::InvalidCharInString(c) => write!(
+ f,
+ "invalid character in string: `{}`",
+ c.escape_default().collect::<String>()
+ )?,
+ ErrorKind::InvalidEscape(c) => write!(
+ f,
+ "invalid escape character in string: `{}`",
+ c.escape_default().collect::<String>()
+ )?,
+ ErrorKind::InvalidHexEscape(c) => write!(
+ f,
+ "invalid hex escape character in string: `{}`",
+ c.escape_default().collect::<String>()
+ )?,
+ ErrorKind::InvalidEscapeValue(c) => write!(f, "invalid escape value: `{}`", c)?,
+ ErrorKind::NewlineInString => "newline in string found".fmt(f)?,
+ ErrorKind::Unexpected(ch) => write!(
+ f,
+ "unexpected character found: `{}`",
+ ch.escape_default().collect::<String>()
+ )?,
+ ErrorKind::UnterminatedString => "unterminated string".fmt(f)?,
+ ErrorKind::NewlineInTableKey => "found newline in table key".fmt(f)?,
+ ErrorKind::Wanted { expected, found } => {
+ write!(f, "expected {}, found {}", expected, found)?
+ }
+ ErrorKind::NumberInvalid => "invalid number".fmt(f)?,
+ ErrorKind::DateInvalid => "invalid date".fmt(f)?,
+ ErrorKind::DuplicateTable(ref s) => {
+ write!(f, "redefinition of table `{}`", s)?;
+ }
+ ErrorKind::RedefineAsArray => "table redefined as array".fmt(f)?,
+ ErrorKind::EmptyTableKey => "empty table key found".fmt(f)?,
+ ErrorKind::MultilineStringKey => "multiline strings are not allowed for key".fmt(f)?,
+ ErrorKind::Custom => self.inner.message.fmt(f)?,
+ ErrorKind::ExpectedTuple(l) => write!(f, "expected table with length {}", l)?,
+ ErrorKind::ExpectedTupleIndex {
+ expected,
+ ref found,
+ } => write!(f, "expected table key `{}`, but was `{}`", expected, found)?,
+ ErrorKind::ExpectedEmptyTable => "expected empty table".fmt(f)?,
+ ErrorKind::DottedKeyInvalidType => {
+ "dotted key attempted to extend non-table type".fmt(f)?
+ }
+ ErrorKind::UnexpectedKeys {
+ ref keys,
+ available,
+ } => write!(
+ f,
+ "unexpected keys in table: `{:?}`, available keys: `{:?}`",
+ keys, available
+ )?,
+ ErrorKind::UnquotedString => write!(
+ f,
+ "invalid TOML value, did you mean to use a quoted string?"
+ )?,
+ }
+
+ if !self.inner.key.is_empty() {
+ write!(f, " for key `")?;
+ for (i, k) in self.inner.key.iter().enumerate() {
+ if i > 0 {
+ write!(f, ".")?;
+ }
+ write!(f, "{}", k)?;
+ }
+ write!(f, "`")?;
+ }
+
+ if let Some(line) = self.inner.line {
+ write!(f, " at line {} column {}", line + 1, self.inner.col + 1)?;
+ }
+
+ Ok(())
+ }
+}
+
+impl error::Error for Error {}
+
+impl de::Error for Error {
+ fn custom<T: fmt::Display>(msg: T) -> Error {
+ Error::custom(None, msg.to_string())
+ }
+}
+
+enum Line<'a> {
+ Table {
+ at: usize,
+ header: Header<'a>,
+ array: bool,
+ },
+ KeyValue(Vec<(Span, Cow<'a, str>)>, Value<'a>),
+}
+
+struct Header<'a> {
+ first: bool,
+ array: bool,
+ require_newline_after_table: bool,
+ tokens: Tokenizer<'a>,
+}
+
+impl<'a> Header<'a> {
+ fn new(tokens: Tokenizer<'a>, array: bool, require_newline_after_table: bool) -> Header<'a> {
+ Header {
+ first: true,
+ array,
+ tokens,
+ require_newline_after_table,
+ }
+ }
+
+ fn next(&mut self) -> Result<Option<(Span, Cow<'a, str>)>, TokenError> {
+ self.tokens.eat_whitespace()?;
+
+ if self.first || self.tokens.eat(Token::Period)? {
+ self.first = false;
+ self.tokens.eat_whitespace()?;
+ self.tokens.table_key().map(Some)
+ } else {
+ self.tokens.expect(Token::RightBracket)?;
+ if self.array {
+ self.tokens.expect(Token::RightBracket)?;
+ }
+
+ self.tokens.eat_whitespace()?;
+ if self.require_newline_after_table && !self.tokens.eat_comment()? {
+ self.tokens.eat_newline_or_eof()?;
+ }
+ Ok(None)
+ }
+ }
+}
+
+#[derive(Debug)]
+struct Value<'a> {
+ e: E<'a>,
+ start: usize,
+ end: usize,
+}
+
+#[derive(Debug)]
+enum E<'a> {
+ Integer(i64),
+ Float(f64),
+ Boolean(bool),
+ String(Cow<'a, str>),
+ Datetime(&'a str),
+ Array(Vec<Value<'a>>),
+ InlineTable(Vec<TablePair<'a>>),
+ DottedTable(Vec<TablePair<'a>>),
+}
+
+impl<'a> E<'a> {
+ fn type_name(&self) -> &'static str {
+ match *self {
+ E::String(..) => "string",
+ E::Integer(..) => "integer",
+ E::Float(..) => "float",
+ E::Boolean(..) => "boolean",
+ E::Datetime(..) => "datetime",
+ E::Array(..) => "array",
+ E::InlineTable(..) => "inline table",
+ E::DottedTable(..) => "dotted table",
+ }
+ }
+}