usecrate::tokens::{Error as TokenError, Span, Token, Tokenizer}; use serde::de; use serde::de::IntoDeserializer; use std::borrow::Cow; use std::collections::{HashMap, HashSet}; use std::error; use std::f64; use std::fmt::{self, Display}; use std::iter; use std::str; use std::vec;
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. pubfn from_slice<'de, T>(bytes: &'de [u8]) -> Result<T, crate::Error> where
T: de::Deserialize<'de>,
{ match str::from_utf8(bytes) {
Ok(s) => from_str(s),
Err(e) => Err(crate::Error::from(*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. pubfn from_str<'de, T>(s: &'de str) -> Result<T, crate::Error> where
T: de::Deserialize<'de>,
{ letmut d = Deserializer::new(s);
T::deserialize(&mut d).map_err(|e| crate::Error::from(*e))
}
/// Errors that can occur when deserializing a type. #[derive(Debug)] 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,
/// 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),
/// Duplicate key in table.
DuplicateKey(String),
/// A previously defined table was redefined as an array.
RedefineAsArray,
/// 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,
}
impl<'de, 'b> de::Deserializer<'de> for &'b mut Deserializer<'de> { type Error = Box<Error>;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Box<Error>> where
V: de::Visitor<'de>,
{ letmut 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,
keys: HashSet::new(),
});
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
})
}
// 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>> { letmut 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>> { letmut res = HashMap::new(); for (i, table) in tables.iter().enumerate() { let header = table.header.iter().map(|v| v.1.clone()).collect::<Vec<_>>(); for len in0..=header.len() {
res.entry(header[..len].to_owned())
.or_insert_with(Vec::new)
.push(i);
}
}
res
}
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 ifself.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.clone())
.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. 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 = &mutself.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. ifself.depth != table.header.len() { let (span, key) = &table.header[self.depth]; if !self.keys.insert(key.clone()) { return Err(Error::from_kind(
Some(span.start),
ErrorKind::DuplicateKey(key.clone().into_owned()),
));
} let key = seed.deserialize(StrDeserializer::new(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));
}
// `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, Box<Error>> where
V: de::Visitor<'de>,
{
visitor.visit_some(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, Box<Error>> where
V: de::Visitor<'de>,
{
visitor.visit_some(self)
}
let first_char = key.chars().next().expect("key should not be empty here"); match first_char { '-' | '0'..='9' => self.number(span, key),
_ => Err(self.error(at, ErrorKind::UnquotedString)),
}
}
letmut first = true; letmut first_zero = false; letmut underscore = false; letmut 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;
} elseif c.is_digit(radix) { if !first && first_zero && !allow_leading_zeros { return Err(self.error(at, ErrorKind::NumberInvalid));
}
underscore = false;
} elseif c == '_' && first { return Err(self.error(at, ErrorKind::NumberInvalid));
} elseif 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..]))
}
// TODO(#140): shouldn't buffer up this entire array in memory, it'd be // great to defer parsing everything until later. fn array(&mutself) -> Result<(Span, Vec<Value<'a>>), Box<Error>> { letmut ret = Vec::new();
/// 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<(), Box<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(refmut v),
..
},
)) => { returnself.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; iflet (
_,
Value {
e: E::DottedTable(refmut v),
..
},
) = values[last_i]
{ self.add_dotted_key(key_parts, value, v)?;
}
Ok(())
}
/// 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) { letmut 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) inself.input.split_terminator('\n').enumerate() { if cur + line.len() + 1 > offset { return (i, offset - cur);
}
cur += line.len() + 1;
}
(self.input.lines().count(), 0)
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.