diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-06-07 05:48:48 +0000 |
commit | ef24de24a82fe681581cc130f342363c47c0969a (patch) | |
tree | 0d494f7e1a38b95c92426f58fe6eaa877303a86c /vendor/toml_edit-0.19.11/src | |
parent | Releasing progress-linux version 1.74.1+dfsg1-1~progress7.99u1. (diff) | |
download | rustc-ef24de24a82fe681581cc130f342363c47c0969a.tar.xz rustc-ef24de24a82fe681581cc130f342363c47c0969a.zip |
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/toml_edit-0.19.11/src')
44 files changed, 10843 insertions, 0 deletions
diff --git a/vendor/toml_edit-0.19.11/src/array.rs b/vendor/toml_edit-0.19.11/src/array.rs new file mode 100644 index 000000000..68cb4467a --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/array.rs @@ -0,0 +1,389 @@ +use std::iter::FromIterator; +use std::mem; + +use crate::repr::Decor; +use crate::value::{DEFAULT_LEADING_VALUE_DECOR, DEFAULT_VALUE_DECOR}; +use crate::{Item, RawString, Value}; + +/// Type representing a TOML array, +/// payload of the `Value::Array` variant's value +#[derive(Debug, Default, Clone)] +pub struct Array { + // `trailing` represents whitespaces, newlines + // and comments in an empty array or after the trailing comma + trailing: RawString, + trailing_comma: bool, + // prefix before `[` and suffix after `]` + decor: Decor, + pub(crate) span: Option<std::ops::Range<usize>>, + // always Vec<Item::Value> + pub(crate) values: Vec<Item>, +} + +/// An owned iterator type over `Table`'s key/value pairs. +pub type ArrayIntoIter = Box<dyn Iterator<Item = Value>>; +/// An iterator type over `Array`'s values. +pub type ArrayIter<'a> = Box<dyn Iterator<Item = &'a Value> + 'a>; +/// An iterator type over `Array`'s values. +pub type ArrayIterMut<'a> = Box<dyn Iterator<Item = &'a mut Value> + 'a>; + +/// Constructors +/// +/// See also `FromIterator` +impl Array { + /// Create an empty `Array` + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// ``` + pub fn new() -> Self { + Default::default() + } + + pub(crate) fn with_vec(values: Vec<Item>) -> Self { + Self { + values, + ..Default::default() + } + } +} + +/// Formatting +impl Array { + /// Auto formats the array. + pub fn fmt(&mut self) { + decorate_array(self); + } + + /// Set whether the array will use a trailing comma + pub fn set_trailing_comma(&mut self, yes: bool) { + self.trailing_comma = yes; + } + + /// Whether the array will use a trailing comma + pub fn trailing_comma(&self) -> bool { + self.trailing_comma + } + + /// Set whitespace after last element + pub fn set_trailing(&mut self, trailing: impl Into<RawString>) { + self.trailing = trailing.into(); + } + + /// Whitespace after last element + pub fn trailing(&self) -> &RawString { + &self.trailing + } + + /// Returns the surrounding whitespace + pub fn decor_mut(&mut self) -> &mut Decor { + &mut self.decor + } + + /// Returns the surrounding whitespace + pub fn decor(&self) -> &Decor { + &self.decor + } + + /// Returns the location within the original document + pub(crate) fn span(&self) -> Option<std::ops::Range<usize>> { + self.span.clone() + } + + pub(crate) fn despan(&mut self, input: &str) { + self.span = None; + self.decor.despan(input); + self.trailing.despan(input); + for value in &mut self.values { + value.despan(input); + } + } +} + +impl Array { + /// Returns an iterator over all values. + pub fn iter(&self) -> ArrayIter<'_> { + Box::new(self.values.iter().filter_map(Item::as_value)) + } + + /// Returns an iterator over all values. + pub fn iter_mut(&mut self) -> ArrayIterMut<'_> { + Box::new(self.values.iter_mut().filter_map(Item::as_value_mut)) + } + + /// Returns the length of the underlying Vec. + /// + /// In some rare cases, placeholder elements will exist. For a more accurate count, call + /// `a.iter().count()` + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// assert_eq!(arr.len(), 2); + /// ``` + pub fn len(&self) -> usize { + self.values.len() + } + + /// Return true iff `self.len() == 0`. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// assert!(arr.is_empty()); + /// + /// arr.push(1); + /// arr.push("foo"); + /// assert!(! arr.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Clears the array, removing all values. Keeps the allocated memory for reuse. + pub fn clear(&mut self) { + self.values.clear() + } + + /// Returns a reference to the value at the given index, or `None` if the index is out of + /// bounds. + pub fn get(&self, index: usize) -> Option<&Value> { + self.values.get(index).and_then(Item::as_value) + } + + /// Returns a reference to the value at the given index, or `None` if the index is out of + /// bounds. + pub fn get_mut(&mut self, index: usize) -> Option<&mut Value> { + self.values.get_mut(index).and_then(Item::as_value_mut) + } + + /// Appends a new value to the end of the array, applying default formatting to it. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// ``` + pub fn push<V: Into<Value>>(&mut self, v: V) { + self.value_op(v.into(), true, |items, value| { + items.push(Item::Value(value)) + }) + } + + /// Appends a new, already formatted value to the end of the array. + /// + /// # Examples + /// + /// ```rust + /// let formatted_value = "'literal'".parse::<toml_edit::Value>().unwrap(); + /// let mut arr = toml_edit::Array::new(); + /// arr.push_formatted(formatted_value); + /// ``` + pub fn push_formatted(&mut self, v: Value) { + self.values.push(Item::Value(v)); + } + + /// Inserts an element at the given position within the array, applying default formatting to + /// it and shifting all values after it to the right. + /// + /// # Panics + /// + /// Panics if `index > len`. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// + /// arr.insert(0, "start"); + /// ``` + pub fn insert<V: Into<Value>>(&mut self, index: usize, v: V) { + self.value_op(v.into(), true, |items, value| { + items.insert(index, Item::Value(value)) + }) + } + + /// Inserts an already formatted value at the given position within the array, shifting all + /// values after it to the right. + /// + /// # Panics + /// + /// Panics if `index > len`. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// + /// let formatted_value = "'start'".parse::<toml_edit::Value>().unwrap(); + /// arr.insert_formatted(0, formatted_value); + /// ``` + pub fn insert_formatted(&mut self, index: usize, v: Value) { + self.values.insert(index, Item::Value(v)) + } + + /// Replaces the element at the given position within the array, preserving existing formatting. + /// + /// # Panics + /// + /// Panics if `index >= len`. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// + /// arr.replace(0, "start"); + /// ``` + pub fn replace<V: Into<Value>>(&mut self, index: usize, v: V) -> Value { + // Read the existing value's decor and preserve it. + let existing_decor = self + .get(index) + .unwrap_or_else(|| panic!("index {} out of bounds (len = {})", index, self.len())) + .decor(); + let mut value = v.into(); + *value.decor_mut() = existing_decor.clone(); + self.replace_formatted(index, value) + } + + /// Replaces the element at the given position within the array with an already formatted value. + /// + /// # Panics + /// + /// Panics if `index >= len`. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// + /// let formatted_value = "'start'".parse::<toml_edit::Value>().unwrap(); + /// arr.replace_formatted(0, formatted_value); + /// ``` + pub fn replace_formatted(&mut self, index: usize, v: Value) -> Value { + match mem::replace(&mut self.values[index], Item::Value(v)) { + Item::Value(old_value) => old_value, + x => panic!("non-value item {:?} in an array", x), + } + } + + /// Removes the value at the given index. + /// + /// # Examples + /// + /// ```rust + /// let mut arr = toml_edit::Array::new(); + /// arr.push(1); + /// arr.push("foo"); + /// + /// arr.remove(0); + /// assert_eq!(arr.len(), 1); + /// ``` + pub fn remove(&mut self, index: usize) -> Value { + let removed = self.values.remove(index); + match removed { + Item::Value(v) => v, + x => panic!("non-value item {:?} in an array", x), + } + } + + fn value_op<T>( + &mut self, + v: Value, + decorate: bool, + op: impl FnOnce(&mut Vec<Item>, Value) -> T, + ) -> T { + let mut value = v; + if !self.is_empty() && decorate { + value.decorate(" ", ""); + } else if decorate { + value.decorate("", ""); + } + op(&mut self.values, value) + } +} + +impl std::fmt::Display for Array { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + crate::encode::Encode::encode(self, f, None, ("", "")) + } +} + +impl<V: Into<Value>> Extend<V> for Array { + fn extend<T: IntoIterator<Item = V>>(&mut self, iter: T) { + for value in iter { + self.push_formatted(value.into()); + } + } +} + +impl<V: Into<Value>> FromIterator<V> for Array { + fn from_iter<I>(iter: I) -> Self + where + I: IntoIterator<Item = V>, + { + let v = iter.into_iter().map(|a| Item::Value(a.into())); + Array { + values: v.collect(), + ..Default::default() + } + } +} + +impl IntoIterator for Array { + type Item = Value; + type IntoIter = ArrayIntoIter; + + fn into_iter(self) -> Self::IntoIter { + Box::new( + self.values + .into_iter() + .filter(|v| v.is_value()) + .map(|v| v.into_value().unwrap()), + ) + } +} + +impl<'s> IntoIterator for &'s Array { + type Item = &'s Value; + type IntoIter = ArrayIter<'s>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +fn decorate_array(array: &mut Array) { + for (i, value) in array + .values + .iter_mut() + .filter_map(Item::as_value_mut) + .enumerate() + { + // [value1, value2, value3] + if i == 0 { + value.decorate(DEFAULT_LEADING_VALUE_DECOR.0, DEFAULT_LEADING_VALUE_DECOR.1); + } else { + value.decorate(DEFAULT_VALUE_DECOR.0, DEFAULT_VALUE_DECOR.1); + } + } + // Since everything is now on the same line, remove trailing commas and whitespace. + array.set_trailing_comma(false); + array.set_trailing(""); +} diff --git a/vendor/toml_edit-0.19.11/src/array_of_tables.rs b/vendor/toml_edit-0.19.11/src/array_of_tables.rs new file mode 100644 index 000000000..461a716c2 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/array_of_tables.rs @@ -0,0 +1,152 @@ +use std::iter::FromIterator; + +use crate::{Array, Item, Table}; + +/// Type representing a TOML array of tables +#[derive(Clone, Debug, Default)] +pub struct ArrayOfTables { + // Always Vec<Item::Table>, just `Item` to make `Index` work + pub(crate) span: Option<std::ops::Range<usize>>, + pub(crate) values: Vec<Item>, +} + +/// Constructors +/// +/// See also `FromIterator` +impl ArrayOfTables { + /// Creates an empty array of tables. + pub fn new() -> Self { + Default::default() + } +} + +/// Formatting +impl ArrayOfTables { + /// Convert to an inline array + pub fn into_array(mut self) -> Array { + for value in self.values.iter_mut() { + value.make_value(); + } + let mut a = Array::with_vec(self.values); + a.fmt(); + a + } + + /// Returns the location within the original document + pub(crate) fn span(&self) -> Option<std::ops::Range<usize>> { + self.span.clone() + } + + pub(crate) fn despan(&mut self, input: &str) { + self.span = None; + for value in &mut self.values { + value.despan(input); + } + } +} + +impl ArrayOfTables { + /// Returns an iterator over tables. + pub fn iter(&self) -> ArrayOfTablesIter<'_> { + Box::new(self.values.iter().filter_map(Item::as_table)) + } + + /// Returns an iterator over tables. + pub fn iter_mut(&mut self) -> ArrayOfTablesIterMut<'_> { + Box::new(self.values.iter_mut().filter_map(Item::as_table_mut)) + } + + /// Returns the length of the underlying Vec. + /// To get the actual number of items use `a.iter().count()`. + pub fn len(&self) -> usize { + self.values.len() + } + + /// Returns true iff `self.len() == 0`. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Removes all the tables. + pub fn clear(&mut self) { + self.values.clear() + } + + /// Returns an optional reference to the table. + pub fn get(&self, index: usize) -> Option<&Table> { + self.values.get(index).and_then(Item::as_table) + } + + /// Returns an optional mutable reference to the table. + pub fn get_mut(&mut self, index: usize) -> Option<&mut Table> { + self.values.get_mut(index).and_then(Item::as_table_mut) + } + + /// Appends a table to the array. + pub fn push(&mut self, table: Table) { + self.values.push(Item::Table(table)); + } + + /// Removes a table with the given index. + pub fn remove(&mut self, index: usize) { + self.values.remove(index); + } +} + +/// An iterator type over `ArrayOfTables`'s values. +pub type ArrayOfTablesIter<'a> = Box<dyn Iterator<Item = &'a Table> + 'a>; +/// An iterator type over `ArrayOfTables`'s values. +pub type ArrayOfTablesIterMut<'a> = Box<dyn Iterator<Item = &'a mut Table> + 'a>; +/// An iterator type over `ArrayOfTables`'s values. +pub type ArrayOfTablesIntoIter = Box<dyn Iterator<Item = Table>>; + +impl Extend<Table> for ArrayOfTables { + fn extend<T: IntoIterator<Item = Table>>(&mut self, iter: T) { + for value in iter { + self.push(value); + } + } +} + +impl FromIterator<Table> for ArrayOfTables { + fn from_iter<I>(iter: I) -> Self + where + I: IntoIterator<Item = Table>, + { + let v = iter.into_iter().map(Item::Table); + ArrayOfTables { + values: v.collect(), + span: None, + } + } +} + +impl IntoIterator for ArrayOfTables { + type Item = Table; + type IntoIter = ArrayOfTablesIntoIter; + + fn into_iter(self) -> Self::IntoIter { + Box::new( + self.values + .into_iter() + .filter(|v| v.is_table()) + .map(|v| v.into_table().unwrap()), + ) + } +} + +impl<'s> IntoIterator for &'s ArrayOfTables { + type Item = &'s Table; + type IntoIter = ArrayOfTablesIter<'s>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl std::fmt::Display for ArrayOfTables { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + // HACK: Without the header, we don't really have a proper way of printing this + self.clone().into_array().fmt(f) + } +} diff --git a/vendor/toml_edit-0.19.11/src/de/array.rs b/vendor/toml_edit-0.19.11/src/de/array.rs new file mode 100644 index 000000000..adc54016b --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/de/array.rs @@ -0,0 +1,97 @@ +use crate::de::Error; + +pub(crate) struct ArrayDeserializer { + input: Vec<crate::Item>, + span: Option<std::ops::Range<usize>>, +} + +impl ArrayDeserializer { + pub(crate) fn new(input: Vec<crate::Item>, span: Option<std::ops::Range<usize>>) -> Self { + Self { input, span } + } +} + +// Note: this is wrapped by `ValueDeserializer` and any trait methods +// implemented here need to be wrapped there +impl<'de> serde::Deserializer<'de> for ArrayDeserializer { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: serde::de::Visitor<'de>, + { + visitor.visit_seq(ArraySeqAccess::new(self.input)) + } + + fn deserialize_struct<V>( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Error> + where + V: serde::de::Visitor<'de>, + { + if serde_spanned::__unstable::is_spanned(name, fields) { + if let Some(span) = self.span.clone() { + return visitor.visit_map(super::SpannedDeserializer::new(self, span)); + } + } + + 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 + } +} + +impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for ArrayDeserializer { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl crate::Array { + pub(crate) fn into_deserializer(self) -> ArrayDeserializer { + ArrayDeserializer::new(self.values, self.span) + } +} + +impl crate::ArrayOfTables { + pub(crate) fn into_deserializer(self) -> ArrayDeserializer { + ArrayDeserializer::new(self.values, self.span) + } +} + +pub(crate) struct ArraySeqAccess { + iter: std::vec::IntoIter<crate::Item>, +} + +impl ArraySeqAccess { + pub(crate) fn new(input: Vec<crate::Item>) -> Self { + Self { + iter: input.into_iter(), + } + } +} + +impl<'de> serde::de::SeqAccess<'de> for ArraySeqAccess { + type Error = Error; + + fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error> + where + T: serde::de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some(v) => seed + .deserialize(crate::de::ValueDeserializer::new(v)) + .map(Some), + None => Ok(None), + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/de/datetime.rs b/vendor/toml_edit-0.19.11/src/de/datetime.rs new file mode 100644 index 000000000..14de28b3f --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/de/datetime.rs @@ -0,0 +1,43 @@ +use serde::de::value::BorrowedStrDeserializer; +use serde::de::IntoDeserializer; + +use crate::de::Error; + +pub(crate) struct DatetimeDeserializer { + date: Option<crate::Datetime>, +} + +impl DatetimeDeserializer { + pub(crate) fn new(date: crate::Datetime) -> Self { + Self { date: Some(date) } + } +} + +impl<'de> serde::de::MapAccess<'de> for DatetimeDeserializer { + type Error = Error; + + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error> + where + K: serde::de::DeserializeSeed<'de>, + { + if self.date.is_some() { + seed.deserialize(BorrowedStrDeserializer::new( + toml_datetime::__unstable::FIELD, + )) + .map(Some) + } else { + Ok(None) + } + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error> + where + V: serde::de::DeserializeSeed<'de>, + { + if let Some(date) = self.date.take() { + seed.deserialize(date.to_string().into_deserializer()) + } else { + panic!("next_value_seed called before next_key_seed") + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/de/key.rs b/vendor/toml_edit-0.19.11/src/de/key.rs new file mode 100644 index 000000000..3da41df41 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/de/key.rs @@ -0,0 +1,140 @@ +use serde::de::IntoDeserializer; + +use super::Error; + +pub(crate) struct KeyDeserializer { + span: Option<std::ops::Range<usize>>, + key: crate::InternalString, +} + +impl KeyDeserializer { + pub(crate) fn new(key: crate::InternalString, span: Option<std::ops::Range<usize>>) -> Self { + KeyDeserializer { span, key } + } +} + +impl<'de> serde::de::IntoDeserializer<'de, Error> for KeyDeserializer { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl<'de> serde::de::Deserializer<'de> for KeyDeserializer { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Error> + where + V: serde::de::Visitor<'de>, + { + self.key.into_deserializer().deserialize_any(visitor) + } + + fn deserialize_enum<V>( + self, + name: &str, + variants: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: serde::de::Visitor<'de>, + { + let _ = name; + let _ = variants; + visitor.visit_enum(self) + } + + fn deserialize_struct<V>( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Error> + where + V: serde::de::Visitor<'de>, + { + if serde_spanned::__unstable::is_spanned(name, fields) { + if let Some(span) = self.span.clone() { + return visitor.visit_map(super::SpannedDeserializer::new(self.key.as_str(), span)); + } + } + 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 identifier + } +} + +impl<'de> serde::de::EnumAccess<'de> for KeyDeserializer { + type Error = super::Error; + type Variant = UnitOnly<Self::Error>; + + fn variant_seed<T>(self, seed: T) -> Result<(T::Value, Self::Variant), Self::Error> + where + T: serde::de::DeserializeSeed<'de>, + { + seed.deserialize(self).map(unit_only) + } +} + +pub(crate) struct UnitOnly<E> { + marker: std::marker::PhantomData<E>, +} + +fn unit_only<T, E>(t: T) -> (T, UnitOnly<E>) { + ( + t, + UnitOnly { + marker: std::marker::PhantomData, + }, + ) +} + +impl<'de, E> serde::de::VariantAccess<'de> for UnitOnly<E> +where + E: serde::de::Error, +{ + type Error = E; + + fn unit_variant(self) -> Result<(), Self::Error> { + Ok(()) + } + + fn newtype_variant_seed<T>(self, _seed: T) -> Result<T::Value, Self::Error> + where + T: serde::de::DeserializeSeed<'de>, + { + Err(serde::de::Error::invalid_type( + serde::de::Unexpected::UnitVariant, + &"newtype variant", + )) + } + + fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error> + where + V: serde::de::Visitor<'de>, + { + Err(serde::de::Error::invalid_type( + serde::de::Unexpected::UnitVariant, + &"tuple variant", + )) + } + + fn struct_variant<V>( + self, + _fields: &'static [&'static str], + _visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: serde::de::Visitor<'de>, + { + Err(serde::de::Error::invalid_type( + serde::de::Unexpected::UnitVariant, + &"struct variant", + )) + } +} diff --git a/vendor/toml_edit-0.19.11/src/de/mod.rs b/vendor/toml_edit-0.19.11/src/de/mod.rs new file mode 100644 index 000000000..09ea12096 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/de/mod.rs @@ -0,0 +1,289 @@ +//! Deserializing TOML into Rust structures. +//! +//! This module contains all the Serde support for deserializing TOML documents into Rust structures. + +use serde::de::DeserializeOwned; + +mod array; +mod datetime; +mod key; +mod spanned; +mod table; +mod table_enum; +mod value; + +use array::ArrayDeserializer; +use datetime::DatetimeDeserializer; +use key::KeyDeserializer; +use spanned::SpannedDeserializer; +use table::TableMapAccess; +use table_enum::TableEnumDeserializer; + +pub use value::ValueDeserializer; + +/// Errors that can occur when deserializing a type. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Error { + inner: crate::TomlError, +} + +impl Error { + pub(crate) fn custom<T>(msg: T, span: Option<std::ops::Range<usize>>) -> Self + where + T: std::fmt::Display, + { + Error { + inner: crate::TomlError::custom(msg.to_string(), span), + } + } + + /// Add key while unwinding + pub fn add_key(&mut self, key: String) { + self.inner.add_key(key) + } + + /// What went wrong + pub fn message(&self) -> &str { + self.inner.message() + } + + /// The start/end index into the original document where the error occurred + pub fn span(&self) -> Option<std::ops::Range<usize>> { + self.inner.span() + } + + pub(crate) fn set_span(&mut self, span: Option<std::ops::Range<usize>>) { + self.inner.set_span(span); + } +} + +impl serde::de::Error for Error { + fn custom<T>(msg: T) -> Self + where + T: std::fmt::Display, + { + Error::custom(msg, None) + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + self.inner.fmt(f) + } +} + +impl From<crate::TomlError> for Error { + fn from(e: crate::TomlError) -> Error { + Self { inner: e } + } +} + +impl From<Error> for crate::TomlError { + fn from(e: Error) -> crate::TomlError { + e.inner + } +} + +impl std::error::Error for Error {} + +/// Convert a value into `T`. +pub fn from_str<T>(s: &'_ str) -> Result<T, Error> +where + T: DeserializeOwned, +{ + let de = s.parse::<Deserializer>()?; + T::deserialize(de) +} + +/// Convert a value into `T`. +pub fn from_slice<T>(s: &'_ [u8]) -> Result<T, Error> +where + T: DeserializeOwned, +{ + let s = std::str::from_utf8(s).map_err(|e| Error::custom(e, None))?; + from_str(s) +} + +/// Convert a document into `T`. +pub fn from_document<T>(d: crate::Document) -> Result<T, Error> +where + T: DeserializeOwned, +{ + let deserializer = Deserializer::new(d); + T::deserialize(deserializer) +} + +/// Deserialization for TOML [documents][crate::Document]. +pub struct Deserializer { + input: crate::Document, +} + +impl Deserializer { + /// Deserialization implementation for TOML. + pub fn new(input: crate::Document) -> Self { + Self { input } + } +} + +impl std::str::FromStr for Deserializer { + type Err = Error; + + /// Parses a document from a &str + fn from_str(s: &str) -> Result<Self, Self::Err> { + let d = crate::parser::parse_document(s).map_err(Error::from)?; + Ok(Self::new(d)) + } +} + +// Note: this is wrapped by `toml::de::Deserializer` and any trait methods +// implemented here need to be wrapped there +impl<'de> serde::Deserializer<'de> for Deserializer { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: serde::de::Visitor<'de>, + { + let original = self.input.original; + self.input + .root + .into_deserializer() + .deserialize_any(visitor) + .map_err(|mut e: Self::Error| { + e.inner.set_original(original); + e + }) + } + + // `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: serde::de::Visitor<'de>, + { + let original = self.input.original; + self.input + .root + .into_deserializer() + .deserialize_option(visitor) + .map_err(|mut e: Self::Error| { + e.inner.set_original(original); + e + }) + } + + fn deserialize_newtype_struct<V>( + self, + name: &'static str, + visitor: V, + ) -> Result<V::Value, Error> + where + V: serde::de::Visitor<'de>, + { + let original = self.input.original; + self.input + .root + .into_deserializer() + .deserialize_newtype_struct(name, visitor) + .map_err(|mut e: Self::Error| { + e.inner.set_original(original); + e + }) + } + + fn deserialize_struct<V>( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Error> + where + V: serde::de::Visitor<'de>, + { + let original = self.input.original; + self.input + .root + .into_deserializer() + .deserialize_struct(name, fields, visitor) + .map_err(|mut e: Self::Error| { + e.inner.set_original(original); + e + }) + } + + // 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: serde::de::Visitor<'de>, + { + let original = self.input.original; + self.input + .root + .into_deserializer() + .deserialize_enum(name, variants, visitor) + .map_err(|mut e: Self::Error| { + e.inner.set_original(original); + e + }) + } + + 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 + ignored_any unit_struct tuple_struct tuple identifier + } +} + +impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for Deserializer { + type Deserializer = Deserializer; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for crate::Document { + type Deserializer = Deserializer; + + fn into_deserializer(self) -> Self::Deserializer { + Deserializer::new(self) + } +} + +pub(crate) fn validate_struct_keys( + table: &crate::table::KeyValuePairs, + fields: &'static [&'static str], +) -> Result<(), Error> { + let extra_fields = table + .iter() + .filter_map(|(key, val)| { + if !fields.contains(&key.as_str()) { + Some(val.clone()) + } else { + None + } + }) + .collect::<Vec<_>>(); + + if extra_fields.is_empty() { + Ok(()) + } else { + Err(Error::custom( + format!( + "unexpected keys in table: {}, available keys: {}", + extra_fields + .iter() + .map(|k| k.key.get()) + .collect::<Vec<_>>() + .join(", "), + fields.join(", "), + ), + extra_fields[0].key.span(), + )) + } +} diff --git a/vendor/toml_edit-0.19.11/src/de/spanned.rs b/vendor/toml_edit-0.19.11/src/de/spanned.rs new file mode 100644 index 000000000..7ce58640a --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/de/spanned.rs @@ -0,0 +1,70 @@ +use serde::de::value::BorrowedStrDeserializer; +use serde::de::IntoDeserializer as _; + +use super::Error; + +pub(crate) struct SpannedDeserializer<'de, T: serde::de::IntoDeserializer<'de, Error>> { + phantom_data: std::marker::PhantomData<&'de ()>, + start: Option<usize>, + end: Option<usize>, + value: Option<T>, +} + +impl<'de, T> SpannedDeserializer<'de, T> +where + T: serde::de::IntoDeserializer<'de, Error>, +{ + pub(crate) fn new(value: T, span: std::ops::Range<usize>) -> Self { + Self { + phantom_data: Default::default(), + start: Some(span.start), + end: Some(span.end), + value: Some(value), + } + } +} + +impl<'de, T> serde::de::MapAccess<'de> for SpannedDeserializer<'de, T> +where + T: serde::de::IntoDeserializer<'de, Error>, +{ + type Error = Error; + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Error> + where + K: serde::de::DeserializeSeed<'de>, + { + if self.start.is_some() { + seed.deserialize(BorrowedStrDeserializer::new( + serde_spanned::__unstable::START_FIELD, + )) + .map(Some) + } else if self.end.is_some() { + seed.deserialize(BorrowedStrDeserializer::new( + serde_spanned::__unstable::END_FIELD, + )) + .map(Some) + } else if self.value.is_some() { + seed.deserialize(BorrowedStrDeserializer::new( + serde_spanned::__unstable::VALUE_FIELD, + )) + .map(Some) + } else { + Ok(None) + } + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Error> + where + V: serde::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") + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/de/table.rs b/vendor/toml_edit-0.19.11/src/de/table.rs new file mode 100644 index 000000000..0b6183e09 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/de/table.rs @@ -0,0 +1,213 @@ +use serde::de::IntoDeserializer; + +use crate::de::Error; + +pub(crate) struct TableDeserializer { + span: Option<std::ops::Range<usize>>, + items: crate::table::KeyValuePairs, +} + +// Note: this is wrapped by `Deserializer` and `ValueDeserializer` and any trait methods +// implemented here need to be wrapped there +impl<'de> serde::Deserializer<'de> for TableDeserializer { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: serde::de::Visitor<'de>, + { + visitor.visit_map(crate::de::TableMapAccess::new(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: serde::de::Visitor<'de>, + { + visitor.visit_some(self) + } + + fn deserialize_newtype_struct<V>( + self, + _name: &'static str, + visitor: V, + ) -> Result<V::Value, Error> + where + V: serde::de::Visitor<'de>, + { + visitor.visit_newtype_struct(self) + } + + fn deserialize_struct<V>( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Error> + where + V: serde::de::Visitor<'de>, + { + if serde_spanned::__unstable::is_spanned(name, fields) { + if let Some(span) = self.span.clone() { + return visitor.visit_map(super::SpannedDeserializer::new(self, span)); + } + } + + self.deserialize_any(visitor) + } + + // 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: serde::de::Visitor<'de>, + { + if self.items.is_empty() { + Err(crate::de::Error::custom( + "wanted exactly 1 element, found 0 elements", + self.span, + )) + } else if self.items.len() != 1 { + Err(crate::de::Error::custom( + "wanted exactly 1 element, more than 1 element", + self.span, + )) + } else { + visitor.visit_enum(crate::de::TableMapAccess::new(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 + ignored_any unit_struct tuple_struct tuple identifier + } +} + +impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for TableDeserializer { + type Deserializer = TableDeserializer; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl crate::Table { + pub(crate) fn into_deserializer(self) -> TableDeserializer { + TableDeserializer { + span: self.span(), + items: self.items, + } + } +} + +impl crate::InlineTable { + pub(crate) fn into_deserializer(self) -> TableDeserializer { + TableDeserializer { + span: self.span(), + items: self.items, + } + } +} + +pub(crate) struct TableMapAccess { + iter: indexmap::map::IntoIter<crate::InternalString, crate::table::TableKeyValue>, + span: Option<std::ops::Range<usize>>, + value: Option<(crate::InternalString, crate::Item)>, +} + +impl TableMapAccess { + pub(crate) fn new(input: TableDeserializer) -> Self { + Self { + iter: input.items.into_iter(), + span: input.span, + value: None, + } + } +} + +impl<'de> serde::de::MapAccess<'de> for TableMapAccess { + type Error = Error; + + fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error> + where + K: serde::de::DeserializeSeed<'de>, + { + match self.iter.next() { + Some((k, v)) => { + let ret = seed + .deserialize(super::KeyDeserializer::new(k, v.key.span())) + .map(Some) + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(v.key.span()); + } + e + }); + self.value = Some((v.key.into(), v.value)); + ret + } + None => Ok(None), + } + } + + fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error> + where + V: serde::de::DeserializeSeed<'de>, + { + match self.value.take() { + Some((k, v)) => { + let span = v.span(); + seed.deserialize(crate::de::ValueDeserializer::new(v)) + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e.add_key(k.as_str().to_owned()); + e + }) + } + None => { + panic!("no more values in next_value_seed, internal error in ValueDeserializer") + } + } + } +} + +impl<'de> serde::de::EnumAccess<'de> for TableMapAccess { + type Error = Error; + type Variant = super::TableEnumDeserializer; + + fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> + where + V: serde::de::DeserializeSeed<'de>, + { + let (key, value) = match self.iter.next() { + Some(pair) => pair, + None => { + return Err(Error::custom( + "expected table with exactly 1 entry, found empty table", + self.span, + )); + } + }; + + let val = seed + .deserialize(key.into_deserializer()) + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(value.key.span()); + } + e + })?; + + let variant = super::TableEnumDeserializer::new(value.value); + + Ok((val, variant)) + } +} diff --git a/vendor/toml_edit-0.19.11/src/de/table_enum.rs b/vendor/toml_edit-0.19.11/src/de/table_enum.rs new file mode 100644 index 000000000..197ad6ea7 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/de/table_enum.rs @@ -0,0 +1,160 @@ +use crate::de::Error; + +/// Deserializes table values into enum variants. +pub(crate) struct TableEnumDeserializer { + value: crate::Item, +} + +impl TableEnumDeserializer { + pub(crate) fn new(value: crate::Item) -> Self { + TableEnumDeserializer { value } + } +} + +impl<'de> serde::de::VariantAccess<'de> for TableEnumDeserializer { + type Error = Error; + + fn unit_variant(self) -> Result<(), Self::Error> { + match self.value { + crate::Item::Table(values) => { + if values.is_empty() { + Ok(()) + } else { + Err(Error::custom("expected empty table", values.span())) + } + } + crate::Item::Value(crate::Value::InlineTable(values)) => { + if values.is_empty() { + Ok(()) + } else { + Err(Error::custom("expected empty table", values.span())) + } + } + e => Err(Error::custom( + format!("expected table, found {}", e.type_name()), + e.span(), + )), + } + } + + fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error> + where + T: serde::de::DeserializeSeed<'de>, + { + seed.deserialize(super::ValueDeserializer::new(self.value)) + } + + fn tuple_variant<V>(self, len: usize, visitor: V) -> Result<V::Value, Self::Error> + where + V: serde::de::Visitor<'de>, + { + match self.value { + crate::Item::Table(values) => { + let values_span = values.span(); + let tuple_values = values + .items + .into_iter() + .enumerate() + .map( + |(index, (_, value))| match value.key.get().parse::<usize>() { + Ok(key_index) if key_index == index => Ok(value.value), + Ok(_) | Err(_) => Err(Error::custom( + format!( + "expected table key `{}`, but was `{}`", + index, + value.key.get() + ), + value.key.span(), + )), + }, + ) + // 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 { + serde::de::Deserializer::deserialize_seq( + super::ArrayDeserializer::new(tuple_values, values_span), + visitor, + ) + } else { + Err(Error::custom( + format!("expected tuple with length {}", len), + values_span, + )) + } + } + crate::Item::Value(crate::Value::InlineTable(values)) => { + let values_span = values.span(); + let tuple_values = values + .items + .into_iter() + .enumerate() + .map( + |(index, (_, value))| match value.key.get().parse::<usize>() { + Ok(key_index) if key_index == index => Ok(value.value), + Ok(_) | Err(_) => Err(Error::custom( + format!( + "expected table key `{}`, but was `{}`", + index, + value.key.get() + ), + value.key.span(), + )), + }, + ) + // 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 { + serde::de::Deserializer::deserialize_seq( + super::ArrayDeserializer::new(tuple_values, values_span), + visitor, + ) + } else { + Err(Error::custom( + format!("expected tuple with length {}", len), + values_span, + )) + } + } + e => Err(Error::custom( + format!("expected table, found {}", e.type_name()), + e.span(), + )), + } + } + + fn struct_variant<V>( + self, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Self::Error> + where + V: serde::de::Visitor<'de>, + { + serde::de::Deserializer::deserialize_struct( + super::ValueDeserializer::new(self.value).with_struct_key_validation(), + "", // TODO: this should be the variant name + fields, + visitor, + ) + } +} diff --git a/vendor/toml_edit-0.19.11/src/de/value.rs b/vendor/toml_edit-0.19.11/src/de/value.rs new file mode 100644 index 000000000..39842875a --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/de/value.rs @@ -0,0 +1,252 @@ +use serde::de::IntoDeserializer as _; + +use crate::de::DatetimeDeserializer; +use crate::de::Error; + +/// Deserialization implementation for TOML [values][crate::Value]. +/// +/// Can be creater either directly from TOML strings, using [`std::str::FromStr`], +/// or from parsed [values][crate::Value] using [`serde::de::IntoDeserializer::into_deserializer`]. +/// +/// # Example +/// +/// ``` +/// use serde::Deserialize; +/// +/// #[derive(Deserialize)] +/// struct Config { +/// title: String, +/// owner: Owner, +/// } +/// +/// #[derive(Deserialize)] +/// struct Owner { +/// name: String, +/// } +/// +/// let value = r#"{ title = 'TOML Example', owner = { name = 'Lisa' } }"#; +/// let deserializer = value.parse::<toml_edit::de::ValueDeserializer>().unwrap(); +/// let config = Config::deserialize(deserializer).unwrap(); +/// assert_eq!(config.title, "TOML Example"); +/// assert_eq!(config.owner.name, "Lisa"); +/// ``` +pub struct ValueDeserializer { + input: crate::Item, + validate_struct_keys: bool, +} + +impl ValueDeserializer { + pub(crate) fn new(input: crate::Item) -> Self { + Self { + input, + validate_struct_keys: false, + } + } + + pub(crate) fn with_struct_key_validation(mut self) -> Self { + self.validate_struct_keys = true; + self + } +} + +// Note: this is wrapped by `toml::de::ValueDeserializer` and any trait methods +// implemented here need to be wrapped there +impl<'de> serde::Deserializer<'de> for ValueDeserializer { + type Error = Error; + + fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error> + where + V: serde::de::Visitor<'de>, + { + let span = self.input.span(); + match self.input { + crate::Item::None => visitor.visit_none(), + crate::Item::Value(crate::Value::String(v)) => visitor.visit_string(v.into_value()), + crate::Item::Value(crate::Value::Integer(v)) => visitor.visit_i64(v.into_value()), + crate::Item::Value(crate::Value::Float(v)) => visitor.visit_f64(v.into_value()), + crate::Item::Value(crate::Value::Boolean(v)) => visitor.visit_bool(v.into_value()), + crate::Item::Value(crate::Value::Datetime(v)) => { + visitor.visit_map(DatetimeDeserializer::new(v.into_value())) + } + crate::Item::Value(crate::Value::Array(v)) => { + v.into_deserializer().deserialize_any(visitor) + } + crate::Item::Value(crate::Value::InlineTable(v)) => { + v.into_deserializer().deserialize_any(visitor) + } + crate::Item::Table(v) => v.into_deserializer().deserialize_any(visitor), + crate::Item::ArrayOfTables(v) => v.into_deserializer().deserialize_any(visitor), + } + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e + }) + } + + // `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: serde::de::Visitor<'de>, + { + let span = self.input.span(); + visitor.visit_some(self).map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e + }) + } + + fn deserialize_newtype_struct<V>( + self, + _name: &'static str, + visitor: V, + ) -> Result<V::Value, Error> + where + V: serde::de::Visitor<'de>, + { + let span = self.input.span(); + visitor + .visit_newtype_struct(self) + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e + }) + } + + fn deserialize_struct<V>( + self, + name: &'static str, + fields: &'static [&'static str], + visitor: V, + ) -> Result<V::Value, Error> + where + V: serde::de::Visitor<'de>, + { + if serde_spanned::__unstable::is_spanned(name, fields) { + if let Some(span) = self.input.span() { + return visitor.visit_map(super::SpannedDeserializer::new(self, span)); + } + } + + if name == toml_datetime::__unstable::NAME && fields == [toml_datetime::__unstable::FIELD] { + let span = self.input.span(); + if let crate::Item::Value(crate::Value::Datetime(d)) = self.input { + return visitor + .visit_map(DatetimeDeserializer::new(d.into_value())) + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e + }); + } + } + + if self.validate_struct_keys { + let span = self.input.span(); + match &self.input { + crate::Item::Table(values) => super::validate_struct_keys(&values.items, fields), + crate::Item::Value(crate::Value::InlineTable(values)) => { + super::validate_struct_keys(&values.items, fields) + } + _ => Ok(()), + } + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e + })? + } + + self.deserialize_any(visitor) + } + + // 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: serde::de::Visitor<'de>, + { + let span = self.input.span(); + match self.input { + crate::Item::Value(crate::Value::String(v)) => { + visitor.visit_enum(v.into_value().into_deserializer()) + } + crate::Item::Value(crate::Value::InlineTable(v)) => { + if v.is_empty() { + Err(crate::de::Error::custom( + "wanted exactly 1 element, found 0 elements", + v.span(), + )) + } else if v.len() != 1 { + Err(crate::de::Error::custom( + "wanted exactly 1 element, more than 1 element", + v.span(), + )) + } else { + v.into_deserializer() + .deserialize_enum(name, variants, visitor) + } + } + crate::Item::Table(v) => v + .into_deserializer() + .deserialize_enum(name, variants, visitor), + e => Err(crate::de::Error::custom("wanted string or table", e.span())), + } + .map_err(|mut e: Self::Error| { + if e.span().is_none() { + e.set_span(span); + } + e + }) + } + + 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 + ignored_any unit_struct tuple_struct tuple identifier + } +} + +impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for ValueDeserializer { + type Deserializer = Self; + + fn into_deserializer(self) -> Self::Deserializer { + self + } +} + +impl<'de> serde::de::IntoDeserializer<'de, crate::de::Error> for crate::Value { + type Deserializer = ValueDeserializer; + + fn into_deserializer(self) -> Self::Deserializer { + ValueDeserializer::new(crate::Item::Value(self)) + } +} + +impl crate::Item { + pub(crate) fn into_deserializer(self) -> ValueDeserializer { + ValueDeserializer::new(self) + } +} + +impl std::str::FromStr for ValueDeserializer { + type Err = Error; + + /// Parses a value from a &str + fn from_str(s: &str) -> Result<Self, Self::Err> { + let v = crate::parser::parse_value(s).map_err(Error::from)?; + Ok(v.into_deserializer()) + } +} diff --git a/vendor/toml_edit-0.19.11/src/document.rs b/vendor/toml_edit-0.19.11/src/document.rs new file mode 100644 index 000000000..67dd293dd --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/document.rs @@ -0,0 +1,113 @@ +use std::str::FromStr; + +use crate::parser; +use crate::table::Iter; +use crate::{Item, RawString, Table}; + +/// Type representing a TOML document +#[derive(Debug, Clone)] +pub struct Document { + pub(crate) root: Item, + // Trailing comments and whitespaces + pub(crate) trailing: RawString, + pub(crate) original: Option<String>, + pub(crate) span: Option<std::ops::Range<usize>>, +} + +impl Document { + /// Creates an empty document + pub fn new() -> Self { + Default::default() + } + + /// Returns a reference to the root item. + pub fn as_item(&self) -> &Item { + &self.root + } + + /// Returns a mutable reference to the root item. + pub fn as_item_mut(&mut self) -> &mut Item { + &mut self.root + } + + /// Returns a reference to the root table. + pub fn as_table(&self) -> &Table { + self.root.as_table().expect("root should always be a table") + } + + /// Returns a mutable reference to the root table. + pub fn as_table_mut(&mut self) -> &mut Table { + self.root + .as_table_mut() + .expect("root should always be a table") + } + + /// Returns an iterator over the root table. + pub fn iter(&self) -> Iter<'_> { + self.as_table().iter() + } + + /// Set whitespace after last element + pub fn set_trailing(&mut self, trailing: impl Into<RawString>) { + self.trailing = trailing.into(); + } + + /// Whitespace after last element + pub fn trailing(&self) -> &RawString { + &self.trailing + } + + /// # Panics + /// + /// If run on on a `Document` not generated by the parser + pub(crate) fn despan(&mut self) { + self.span = None; + self.root.despan(self.original.as_deref().unwrap()); + self.trailing.despan(self.original.as_deref().unwrap()); + } +} + +impl Default for Document { + fn default() -> Self { + Self { + root: Item::Table(Table::with_pos(Some(0))), + trailing: Default::default(), + original: Default::default(), + span: Default::default(), + } + } +} + +impl FromStr for Document { + type Err = crate::TomlError; + + /// Parses a document from a &str + fn from_str(s: &str) -> Result<Self, Self::Err> { + let mut d = parser::parse_document(s)?; + d.despan(); + Ok(d) + } +} + +impl std::ops::Deref for Document { + type Target = Table; + + fn deref(&self) -> &Self::Target { + self.as_table() + } +} + +impl std::ops::DerefMut for Document { + fn deref_mut(&mut self) -> &mut Self::Target { + self.as_table_mut() + } +} + +impl From<Table> for Document { + fn from(root: Table) -> Self { + Self { + root: Item::Table(root), + ..Default::default() + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/encode.rs b/vendor/toml_edit-0.19.11/src/encode.rs new file mode 100644 index 000000000..9940f282b --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/encode.rs @@ -0,0 +1,569 @@ +use std::borrow::Cow; +use std::fmt::{Display, Formatter, Result, Write}; + +use toml_datetime::*; + +use crate::document::Document; +use crate::inline_table::DEFAULT_INLINE_KEY_DECOR; +use crate::key::Key; +use crate::repr::{Formatted, Repr, ValueRepr}; +use crate::table::{DEFAULT_KEY_DECOR, DEFAULT_KEY_PATH_DECOR, DEFAULT_TABLE_DECOR}; +use crate::value::{ + DEFAULT_LEADING_VALUE_DECOR, DEFAULT_TRAILING_VALUE_DECOR, DEFAULT_VALUE_DECOR, +}; +use crate::{Array, InlineTable, Item, Table, Value}; + +pub(crate) trait Encode { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result; +} + +impl Encode for Key { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + let decor = self.decor(); + decor.prefix_encode(buf, input, default_decor.0)?; + + if let Some(input) = input { + let repr = self + .as_repr() + .map(Cow::Borrowed) + .unwrap_or_else(|| Cow::Owned(self.default_repr())); + repr.encode(buf, input)?; + } else { + let repr = self.display_repr(); + write!(buf, "{}", repr)?; + }; + + decor.suffix_encode(buf, input, default_decor.1)?; + Ok(()) + } +} + +impl<'k> Encode for &'k [Key] { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + for (i, key) in self.iter().enumerate() { + let first = i == 0; + let last = i + 1 == self.len(); + + let prefix = if first { + default_decor.0 + } else { + DEFAULT_KEY_PATH_DECOR.0 + }; + let suffix = if last { + default_decor.1 + } else { + DEFAULT_KEY_PATH_DECOR.1 + }; + + if !first { + write!(buf, ".")?; + } + key.encode(buf, input, (prefix, suffix))?; + } + Ok(()) + } +} + +impl<'k> Encode for &'k [&'k Key] { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + for (i, key) in self.iter().enumerate() { + let first = i == 0; + let last = i + 1 == self.len(); + + let prefix = if first { + default_decor.0 + } else { + DEFAULT_KEY_PATH_DECOR.0 + }; + let suffix = if last { + default_decor.1 + } else { + DEFAULT_KEY_PATH_DECOR.1 + }; + + if !first { + write!(buf, ".")?; + } + key.encode(buf, input, (prefix, suffix))?; + } + Ok(()) + } +} + +impl<T> Encode for Formatted<T> +where + T: ValueRepr, +{ + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + let decor = self.decor(); + decor.prefix_encode(buf, input, default_decor.0)?; + + if let Some(input) = input { + let repr = self + .as_repr() + .map(Cow::Borrowed) + .unwrap_or_else(|| Cow::Owned(self.default_repr())); + repr.encode(buf, input)?; + } else { + let repr = self.display_repr(); + write!(buf, "{}", repr)?; + }; + + decor.suffix_encode(buf, input, default_decor.1)?; + Ok(()) + } +} + +impl Encode for Array { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + let decor = self.decor(); + decor.prefix_encode(buf, input, default_decor.0)?; + write!(buf, "[")?; + + for (i, elem) in self.iter().enumerate() { + let inner_decor; + if i == 0 { + inner_decor = DEFAULT_LEADING_VALUE_DECOR; + } else { + inner_decor = DEFAULT_VALUE_DECOR; + write!(buf, ",")?; + } + elem.encode(buf, input, inner_decor)?; + } + if self.trailing_comma() && !self.is_empty() { + write!(buf, ",")?; + } + + self.trailing().encode_with_default(buf, input, "")?; + write!(buf, "]")?; + decor.suffix_encode(buf, input, default_decor.1)?; + + Ok(()) + } +} + +impl Encode for InlineTable { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + let decor = self.decor(); + decor.prefix_encode(buf, input, default_decor.0)?; + write!(buf, "{{")?; + self.preamble().encode_with_default(buf, input, "")?; + + let children = self.get_values(); + let len = children.len(); + for (i, (key_path, value)) in children.into_iter().enumerate() { + if i != 0 { + write!(buf, ",")?; + } + let inner_decor = if i == len - 1 { + DEFAULT_TRAILING_VALUE_DECOR + } else { + DEFAULT_VALUE_DECOR + }; + key_path + .as_slice() + .encode(buf, input, DEFAULT_INLINE_KEY_DECOR)?; + write!(buf, "=")?; + value.encode(buf, input, inner_decor)?; + } + + write!(buf, "}}")?; + decor.suffix_encode(buf, input, default_decor.1)?; + + Ok(()) + } +} + +impl Encode for Value { + fn encode( + &self, + buf: &mut dyn Write, + input: Option<&str>, + default_decor: (&str, &str), + ) -> Result { + match self { + Value::String(repr) => repr.encode(buf, input, default_decor), + Value::Integer(repr) => repr.encode(buf, input, default_decor), + Value::Float(repr) => repr.encode(buf, input, default_decor), + Value::Boolean(repr) => repr.encode(buf, input, default_decor), + Value::Datetime(repr) => repr.encode(buf, input, default_decor), + Value::Array(array) => array.encode(buf, input, default_decor), + Value::InlineTable(table) => table.encode(buf, input, default_decor), + } + } +} + +impl Display for Document { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + let mut path = Vec::new(); + let mut last_position = 0; + let mut tables = Vec::new(); + visit_nested_tables(self.as_table(), &mut path, false, &mut |t, p, is_array| { + if let Some(pos) = t.position() { + last_position = pos; + } + tables.push((last_position, t, p.clone(), is_array)); + Ok(()) + }) + .unwrap(); + + tables.sort_by_key(|&(id, _, _, _)| id); + let mut first_table = true; + for (_, table, path, is_array) in tables { + visit_table( + f, + self.original.as_deref(), + table, + &path, + is_array, + &mut first_table, + )?; + } + self.trailing() + .encode_with_default(f, self.original.as_deref(), "") + } +} + +fn visit_nested_tables<'t, F>( + table: &'t Table, + path: &mut Vec<Key>, + is_array_of_tables: bool, + callback: &mut F, +) -> Result +where + F: FnMut(&'t Table, &Vec<Key>, bool) -> Result, +{ + if !table.is_dotted() { + callback(table, path, is_array_of_tables)?; + } + + for kv in table.items.values() { + match kv.value { + Item::Table(ref t) => { + let mut key = kv.key.clone(); + if t.is_dotted() { + // May have newlines and generally isn't written for standard tables + key.decor_mut().clear(); + } + path.push(key); + visit_nested_tables(t, path, false, callback)?; + path.pop(); + } + Item::ArrayOfTables(ref a) => { + for t in a.iter() { + let key = kv.key.clone(); + path.push(key); + visit_nested_tables(t, path, true, callback)?; + path.pop(); + } + } + _ => {} + } + } + Ok(()) +} + +fn visit_table( + buf: &mut dyn Write, + input: Option<&str>, + table: &Table, + path: &[Key], + is_array_of_tables: bool, + first_table: &mut bool, +) -> Result { + let children = table.get_values(); + // We are intentionally hiding implicit tables without any tables nested under them (ie + // `table.is_empty()` which is in contrast to `table.get_values().is_empty()`). We are + // trusting the user that an empty implicit table is not semantically meaningful + // + // This allows a user to delete all tables under this implicit table and the implicit table + // will disappear. + // + // However, this means that users need to take care in deciding what tables get marked as + // implicit. + let is_visible_std_table = !(table.implicit && children.is_empty()); + + if path.is_empty() { + // don't print header for the root node + if !children.is_empty() { + *first_table = false; + } + } else if is_array_of_tables { + let default_decor = if *first_table { + *first_table = false; + ("", DEFAULT_TABLE_DECOR.1) + } else { + DEFAULT_TABLE_DECOR + }; + table.decor.prefix_encode(buf, input, default_decor.0)?; + write!(buf, "[[")?; + path.encode(buf, input, DEFAULT_KEY_PATH_DECOR)?; + write!(buf, "]]")?; + table.decor.suffix_encode(buf, input, default_decor.1)?; + writeln!(buf)?; + } else if is_visible_std_table { + let default_decor = if *first_table { + *first_table = false; + ("", DEFAULT_TABLE_DECOR.1) + } else { + DEFAULT_TABLE_DECOR + }; + table.decor.prefix_encode(buf, input, default_decor.0)?; + write!(buf, "[")?; + path.encode(buf, input, DEFAULT_KEY_PATH_DECOR)?; + write!(buf, "]")?; + table.decor.suffix_encode(buf, input, default_decor.1)?; + writeln!(buf)?; + } + // print table body + for (key_path, value) in children { + key_path.as_slice().encode(buf, input, DEFAULT_KEY_DECOR)?; + write!(buf, "=")?; + value.encode(buf, input, DEFAULT_VALUE_DECOR)?; + writeln!(buf)?; + } + Ok(()) +} + +impl ValueRepr for String { + fn to_repr(&self) -> Repr { + to_string_repr(self, None, None) + } +} + +pub(crate) fn to_string_repr( + value: &str, + style: Option<StringStyle>, + literal: Option<bool>, +) -> Repr { + let (style, literal) = match (style, literal) { + (Some(style), Some(literal)) => (style, literal), + (_, Some(literal)) => (infer_style(value).0, literal), + (Some(style), _) => (style, infer_style(value).1), + (_, _) => infer_style(value), + }; + + let mut output = String::with_capacity(value.len() * 2); + if literal { + output.push_str(style.literal_start()); + output.push_str(value); + output.push_str(style.literal_end()); + } else { + output.push_str(style.standard_start()); + for ch in value.chars() { + match ch { + '\u{8}' => output.push_str("\\b"), + '\u{9}' => output.push_str("\\t"), + '\u{a}' => match style { + StringStyle::NewlineTripple => output.push('\n'), + StringStyle::OnelineSingle => output.push_str("\\n"), + _ => unreachable!(), + }, + '\u{c}' => output.push_str("\\f"), + '\u{d}' => output.push_str("\\r"), + '\u{22}' => output.push_str("\\\""), + '\u{5c}' => output.push_str("\\\\"), + c if c <= '\u{1f}' || c == '\u{7f}' => { + write!(output, "\\u{:04X}", ch as u32).unwrap(); + } + ch => output.push(ch), + } + } + output.push_str(style.standard_end()); + } + + Repr::new_unchecked(output) +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub(crate) enum StringStyle { + NewlineTripple, + OnelineTripple, + OnelineSingle, +} + +impl StringStyle { + fn literal_start(self) -> &'static str { + match self { + Self::NewlineTripple => "'''\n", + Self::OnelineTripple => "'''", + Self::OnelineSingle => "'", + } + } + fn literal_end(self) -> &'static str { + match self { + Self::NewlineTripple => "'''", + Self::OnelineTripple => "'''", + Self::OnelineSingle => "'", + } + } + + fn standard_start(self) -> &'static str { + match self { + Self::NewlineTripple => "\"\"\"\n", + // note: OnelineTripple can happen if do_pretty wants to do + // '''it's one line''' + // but literal == false + Self::OnelineTripple | Self::OnelineSingle => "\"", + } + } + + fn standard_end(self) -> &'static str { + match self { + Self::NewlineTripple => "\"\"\"", + // note: OnelineTripple can happen if do_pretty wants to do + // '''it's one line''' + // but literal == false + Self::OnelineTripple | Self::OnelineSingle => "\"", + } + } +} + +fn infer_style(value: &str) -> (StringStyle, bool) { + // For doing pretty prints we store in a new String + // because there are too many cases where pretty cannot + // work. We need to determine: + // - if we are a "multi-line" pretty (if there are \n) + // - if ['''] appears if multi or ['] if single + // - if there are any invalid control characters + // + // Doing it any other way would require multiple passes + // to determine if a pretty string works or not. + let mut out = String::with_capacity(value.len() * 2); + let mut ty = StringStyle::OnelineSingle; + // found consecutive single quotes + let mut max_found_singles = 0; + let mut found_singles = 0; + let mut prefer_literal = false; + let mut can_be_pretty = true; + + for ch in value.chars() { + if can_be_pretty { + if ch == '\'' { + found_singles += 1; + if found_singles >= 3 { + can_be_pretty = false; + } + } else { + if found_singles > max_found_singles { + max_found_singles = found_singles; + } + found_singles = 0 + } + match ch { + '\t' => {} + '\\' => { + prefer_literal = true; + } + '\n' => ty = StringStyle::NewlineTripple, + // Escape codes are needed if any ascii control + // characters are present, including \b \f \r. + c if c <= '\u{1f}' || c == '\u{7f}' => can_be_pretty = false, + _ => {} + } + out.push(ch); + } else { + // the string cannot be represented as pretty, + // still check if it should be multiline + if ch == '\n' { + ty = StringStyle::NewlineTripple; + } + } + } + if found_singles > 0 && value.ends_with('\'') { + // We cannot escape the ending quote so we must use """ + can_be_pretty = false; + } + if !prefer_literal { + can_be_pretty = false; + } + if !can_be_pretty { + debug_assert!(ty != StringStyle::OnelineTripple); + return (ty, false); + } + if found_singles > max_found_singles { + max_found_singles = found_singles; + } + debug_assert!(max_found_singles < 3); + if ty == StringStyle::OnelineSingle && max_found_singles >= 1 { + // no newlines, but must use ''' because it has ' in it + ty = StringStyle::OnelineTripple; + } + (ty, true) +} + +impl ValueRepr for i64 { + fn to_repr(&self) -> Repr { + Repr::new_unchecked(self.to_string()) + } +} + +impl ValueRepr for f64 { + fn to_repr(&self) -> Repr { + to_f64_repr(*self) + } +} + +fn to_f64_repr(f: f64) -> Repr { + let repr = match (f.is_sign_negative(), f.is_nan(), f == 0.0) { + (true, true, _) => "-nan".to_owned(), + (false, true, _) => "nan".to_owned(), + (true, false, true) => "-0.0".to_owned(), + (false, false, true) => "0.0".to_owned(), + (_, false, false) => { + if f % 1.0 == 0.0 { + format!("{}.0", f) + } else { + format!("{}", f) + } + } + }; + Repr::new_unchecked(repr) +} + +impl ValueRepr for bool { + fn to_repr(&self) -> Repr { + Repr::new_unchecked(self.to_string()) + } +} + +impl ValueRepr for Datetime { + fn to_repr(&self) -> Repr { + Repr::new_unchecked(self.to_string()) + } +} diff --git a/vendor/toml_edit-0.19.11/src/index.rs b/vendor/toml_edit-0.19.11/src/index.rs new file mode 100644 index 000000000..276db7957 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/index.rs @@ -0,0 +1,156 @@ +use std::ops; + +use crate::document::Document; +use crate::key::Key; +use crate::table::TableKeyValue; +use crate::{value, InlineTable, InternalString, Item, Table, Value}; + +// copied from +// https://github.com/serde-rs/json/blob/master/src/value/index.rs + +pub trait Index: crate::private::Sealed { + #[doc(hidden)] + fn index<'v>(&self, val: &'v Item) -> Option<&'v Item>; + #[doc(hidden)] + fn index_mut<'v>(&self, val: &'v mut Item) -> Option<&'v mut Item>; +} + +impl Index for usize { + fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> { + match *v { + Item::ArrayOfTables(ref aot) => aot.values.get(*self), + Item::Value(ref a) if a.is_array() => a.as_array().and_then(|a| a.values.get(*self)), + _ => None, + } + } + fn index_mut<'v>(&self, v: &'v mut Item) -> Option<&'v mut Item> { + match *v { + Item::ArrayOfTables(ref mut vec) => vec.values.get_mut(*self), + Item::Value(ref mut a) => a.as_array_mut().and_then(|a| a.values.get_mut(*self)), + _ => None, + } + } +} + +impl Index for str { + fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> { + match *v { + Item::Table(ref t) => t.get(self), + Item::Value(ref v) => v + .as_inline_table() + .and_then(|t| t.items.get(self)) + .and_then(|kv| { + if !kv.value.is_none() { + Some(&kv.value) + } else { + None + } + }), + _ => None, + } + } + fn index_mut<'v>(&self, v: &'v mut Item) -> Option<&'v mut Item> { + if let Item::None = *v { + let mut t = InlineTable::default(); + t.items.insert( + InternalString::from(self), + TableKeyValue::new(Key::new(self), Item::None), + ); + *v = value(Value::InlineTable(t)); + } + match *v { + Item::Table(ref mut t) => Some(t.entry(self).or_insert(Item::None)), + Item::Value(ref mut v) => v.as_inline_table_mut().map(|t| { + &mut t + .items + .entry(InternalString::from(self)) + .or_insert_with(|| TableKeyValue::new(Key::new(self), Item::None)) + .value + }), + _ => None, + } + } +} + +impl Index for String { + fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> { + self[..].index(v) + } + fn index_mut<'v>(&self, v: &'v mut Item) -> Option<&'v mut Item> { + self[..].index_mut(v) + } +} + +impl<'a, T: ?Sized> Index for &'a T +where + T: Index, +{ + fn index<'v>(&self, v: &'v Item) -> Option<&'v Item> { + (**self).index(v) + } + fn index_mut<'v>(&self, v: &'v mut Item) -> Option<&'v mut Item> { + (**self).index_mut(v) + } +} + +impl<I> ops::Index<I> for Item +where + I: Index, +{ + type Output = Item; + + fn index(&self, index: I) -> &Item { + index.index(self).expect("index not found") + } +} + +impl<I> ops::IndexMut<I> for Item +where + I: Index, +{ + fn index_mut(&mut self, index: I) -> &mut Item { + index.index_mut(self).expect("index not found") + } +} + +impl<'s> ops::Index<&'s str> for Table { + type Output = Item; + + fn index(&self, key: &'s str) -> &Item { + self.get(key).expect("index not found") + } +} + +impl<'s> ops::IndexMut<&'s str> for Table { + fn index_mut(&mut self, key: &'s str) -> &mut Item { + self.entry(key).or_insert(Item::None) + } +} + +impl<'s> ops::Index<&'s str> for InlineTable { + type Output = Value; + + fn index(&self, key: &'s str) -> &Value { + self.get(key).expect("index not found") + } +} + +impl<'s> ops::IndexMut<&'s str> for InlineTable { + fn index_mut(&mut self, key: &'s str) -> &mut Value { + self.get_mut(key).expect("index not found") + } +} + +impl<'s> ops::Index<&'s str> for Document { + type Output = Item; + + fn index(&self, key: &'s str) -> &Item { + self.root.index(key) + } +} + +impl<'s> ops::IndexMut<&'s str> for Document { + fn index_mut(&mut self, key: &'s str) -> &mut Item { + self.root.index_mut(key) + } +} diff --git a/vendor/toml_edit-0.19.11/src/inline_table.rs b/vendor/toml_edit-0.19.11/src/inline_table.rs new file mode 100644 index 000000000..9327818e6 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/inline_table.rs @@ -0,0 +1,661 @@ +use std::iter::FromIterator; + +use crate::key::Key; +use crate::repr::Decor; +use crate::table::{Iter, IterMut, KeyValuePairs, TableKeyValue, TableLike}; +use crate::{InternalString, Item, KeyMut, RawString, Table, Value}; + +/// Type representing a TOML inline table, +/// payload of the `Value::InlineTable` variant +#[derive(Debug, Default, Clone)] +pub struct InlineTable { + // `preamble` represents whitespaces in an empty table + preamble: RawString, + // prefix before `{` and suffix after `}` + decor: Decor, + pub(crate) span: Option<std::ops::Range<usize>>, + // whether this is a proxy for dotted keys + dotted: bool, + pub(crate) items: KeyValuePairs, +} + +/// Constructors +/// +/// See also `FromIterator` +impl InlineTable { + /// Creates an empty table. + pub fn new() -> Self { + Default::default() + } + + pub(crate) fn with_pairs(items: KeyValuePairs) -> Self { + Self { + items, + ..Default::default() + } + } + + /// Convert to a table + pub fn into_table(self) -> Table { + let mut t = Table::with_pairs(self.items); + t.fmt(); + t + } +} + +/// Formatting +impl InlineTable { + /// Get key/values for values that are visually children of this table + /// + /// For example, this will return dotted keys + pub fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> { + let mut values = Vec::new(); + let root = Vec::new(); + self.append_values(&root, &mut values); + values + } + + pub(crate) fn append_values<'s, 'c>( + &'s self, + parent: &[&'s Key], + values: &'c mut Vec<(Vec<&'s Key>, &'s Value)>, + ) { + for value in self.items.values() { + let mut path = parent.to_vec(); + path.push(&value.key); + match &value.value { + Item::Value(Value::InlineTable(table)) if table.is_dotted() => { + table.append_values(&path, values); + } + Item::Value(value) => { + values.push((path, value)); + } + _ => {} + } + } + } + + /// Auto formats the table. + pub fn fmt(&mut self) { + decorate_inline_table(self); + } + + /// Sorts the key/value pairs by key. + pub fn sort_values(&mut self) { + // Assuming standard tables have their position set and this won't negatively impact them + self.items.sort_keys(); + for kv in self.items.values_mut() { + match &mut kv.value { + Item::Value(Value::InlineTable(table)) if table.is_dotted() => { + table.sort_values(); + } + _ => {} + } + } + } + + /// Sort Key/Value Pairs of the table using the using the comparison function `compare`. + /// + /// The comparison function receives two key and value pairs to compare (you can sort by keys or + /// values or their combination as needed). + pub fn sort_values_by<F>(&mut self, mut compare: F) + where + F: FnMut(&Key, &Value, &Key, &Value) -> std::cmp::Ordering, + { + self.sort_values_by_internal(&mut compare); + } + + fn sort_values_by_internal<F>(&mut self, compare: &mut F) + where + F: FnMut(&Key, &Value, &Key, &Value) -> std::cmp::Ordering, + { + let modified_cmp = |_: &InternalString, + val1: &TableKeyValue, + _: &InternalString, + val2: &TableKeyValue| + -> std::cmp::Ordering { + match (val1.value.as_value(), val2.value.as_value()) { + (Some(v1), Some(v2)) => compare(&val1.key, v1, &val2.key, v2), + (Some(_), None) => std::cmp::Ordering::Greater, + (None, Some(_)) => std::cmp::Ordering::Less, + (None, None) => std::cmp::Ordering::Equal, + } + }; + + self.items.sort_by(modified_cmp); + for kv in self.items.values_mut() { + match &mut kv.value { + Item::Value(Value::InlineTable(table)) if table.is_dotted() => { + table.sort_values_by_internal(compare); + } + _ => {} + } + } + } + + /// Change this table's dotted status + pub fn set_dotted(&mut self, yes: bool) { + self.dotted = yes; + } + + /// Check if this is a wrapper for dotted keys, rather than a standard table + pub fn is_dotted(&self) -> bool { + self.dotted + } + + /// Returns the surrounding whitespace + pub fn decor_mut(&mut self) -> &mut Decor { + &mut self.decor + } + + /// Returns the surrounding whitespace + pub fn decor(&self) -> &Decor { + &self.decor + } + + /// Returns the decor associated with a given key of the table. + pub fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> { + self.items.get_mut(key).map(|kv| &mut kv.key.decor) + } + + /// Returns the decor associated with a given key of the table. + pub fn key_decor(&self, key: &str) -> Option<&Decor> { + self.items.get(key).map(|kv| &kv.key.decor) + } + + /// Set whitespace after before element + pub fn set_preamble(&mut self, preamble: impl Into<RawString>) { + self.preamble = preamble.into(); + } + + /// Whitespace after before element + pub fn preamble(&self) -> &RawString { + &self.preamble + } + + /// Returns the location within the original document + pub(crate) fn span(&self) -> Option<std::ops::Range<usize>> { + self.span.clone() + } + + pub(crate) fn despan(&mut self, input: &str) { + self.span = None; + self.decor.despan(input); + self.preamble.despan(input); + for kv in self.items.values_mut() { + kv.key.despan(input); + kv.value.despan(input); + } + } +} + +impl InlineTable { + /// Returns an iterator over key/value pairs. + pub fn iter(&self) -> InlineTableIter<'_> { + Box::new( + self.items + .iter() + .filter(|&(_, kv)| kv.value.is_value()) + .map(|(k, kv)| (&k[..], kv.value.as_value().unwrap())), + ) + } + + /// Returns an iterator over key/value pairs. + pub fn iter_mut(&mut self) -> InlineTableIterMut<'_> { + Box::new( + self.items + .iter_mut() + .filter(|(_, kv)| kv.value.is_value()) + .map(|(_, kv)| (kv.key.as_mut(), kv.value.as_value_mut().unwrap())), + ) + } + + /// Returns the number of key/value pairs. + pub fn len(&self) -> usize { + self.iter().count() + } + + /// Returns true iff the table is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Clears the table, removing all key-value pairs. Keeps the allocated memory for reuse. + pub fn clear(&mut self) { + self.items.clear() + } + + /// Gets the given key's corresponding entry in the Table for in-place manipulation. + pub fn entry(&'_ mut self, key: impl Into<InternalString>) -> InlineEntry<'_> { + match self.items.entry(key.into()) { + indexmap::map::Entry::Occupied(mut entry) => { + // Ensure it is a `Value` to simplify `InlineOccupiedEntry`'s code. + let scratch = std::mem::take(&mut entry.get_mut().value); + let scratch = Item::Value( + scratch + .into_value() + // HACK: `Item::None` is a corner case of a corner case, let's just pick a + // "safe" value + .unwrap_or_else(|_| Value::InlineTable(Default::default())), + ); + entry.get_mut().value = scratch; + + InlineEntry::Occupied(InlineOccupiedEntry { entry }) + } + indexmap::map::Entry::Vacant(entry) => { + InlineEntry::Vacant(InlineVacantEntry { entry, key: None }) + } + } + } + + /// Gets the given key's corresponding entry in the Table for in-place manipulation. + pub fn entry_format<'a>(&'a mut self, key: &Key) -> InlineEntry<'a> { + // Accept a `&Key` to be consistent with `entry` + match self.items.entry(key.get().into()) { + indexmap::map::Entry::Occupied(mut entry) => { + // Ensure it is a `Value` to simplify `InlineOccupiedEntry`'s code. + let scratch = std::mem::take(&mut entry.get_mut().value); + let scratch = Item::Value( + scratch + .into_value() + // HACK: `Item::None` is a corner case of a corner case, let's just pick a + // "safe" value + .unwrap_or_else(|_| Value::InlineTable(Default::default())), + ); + entry.get_mut().value = scratch; + + InlineEntry::Occupied(InlineOccupiedEntry { entry }) + } + indexmap::map::Entry::Vacant(entry) => InlineEntry::Vacant(InlineVacantEntry { + entry, + key: Some(key.clone()), + }), + } + } + /// Return an optional reference to the value at the given the key. + pub fn get(&self, key: &str) -> Option<&Value> { + self.items.get(key).and_then(|kv| kv.value.as_value()) + } + + /// Return an optional mutable reference to the value at the given the key. + pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> { + self.items + .get_mut(key) + .and_then(|kv| kv.value.as_value_mut()) + } + + /// Return references to the key-value pair stored for key, if it is present, else None. + pub fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> { + self.items.get(key).and_then(|kv| { + if !kv.value.is_none() { + Some((&kv.key, &kv.value)) + } else { + None + } + }) + } + + /// Return mutable references to the key-value pair stored for key, if it is present, else None. + pub fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> { + self.items.get_mut(key).and_then(|kv| { + if !kv.value.is_none() { + Some((kv.key.as_mut(), &mut kv.value)) + } else { + None + } + }) + } + + /// Returns true iff the table contains given key. + pub fn contains_key(&self, key: &str) -> bool { + if let Some(kv) = self.items.get(key) { + kv.value.is_value() + } else { + false + } + } + + /// Inserts a key/value pair if the table does not contain the key. + /// Returns a mutable reference to the corresponding value. + pub fn get_or_insert<V: Into<Value>>( + &mut self, + key: impl Into<InternalString>, + value: V, + ) -> &mut Value { + let key = key.into(); + self.items + .entry(key.clone()) + .or_insert(TableKeyValue::new(Key::new(key), Item::Value(value.into()))) + .value + .as_value_mut() + .expect("non-value type in inline table") + } + + /// Inserts a key-value pair into the map. + pub fn insert(&mut self, key: impl Into<InternalString>, value: Value) -> Option<Value> { + let key = key.into(); + let kv = TableKeyValue::new(Key::new(key.clone()), Item::Value(value)); + self.items + .insert(key, kv) + .and_then(|kv| kv.value.into_value().ok()) + } + + /// Inserts a key-value pair into the map. + pub fn insert_formatted(&mut self, key: &Key, value: Value) -> Option<Value> { + let kv = TableKeyValue::new(key.to_owned(), Item::Value(value)); + self.items + .insert(InternalString::from(key.get()), kv) + .filter(|kv| kv.value.is_value()) + .map(|kv| kv.value.into_value().unwrap()) + } + + /// Removes an item given the key. + pub fn remove(&mut self, key: &str) -> Option<Value> { + self.items + .shift_remove(key) + .and_then(|kv| kv.value.into_value().ok()) + } + + /// Removes a key from the map, returning the stored key and value if the key was previously in the map. + pub fn remove_entry(&mut self, key: &str) -> Option<(Key, Value)> { + self.items.shift_remove(key).and_then(|kv| { + let key = kv.key; + kv.value.into_value().ok().map(|value| (key, value)) + }) + } +} + +impl std::fmt::Display for InlineTable { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + crate::encode::Encode::encode(self, f, None, ("", "")) + } +} + +impl<K: Into<Key>, V: Into<Value>> Extend<(K, V)> for InlineTable { + fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) { + for (key, value) in iter { + let key = key.into(); + let value = Item::Value(value.into()); + let value = TableKeyValue::new(key, value); + self.items + .insert(InternalString::from(value.key.get()), value); + } + } +} + +impl<K: Into<Key>, V: Into<Value>> FromIterator<(K, V)> for InlineTable { + fn from_iter<I>(iter: I) -> Self + where + I: IntoIterator<Item = (K, V)>, + { + let mut table = InlineTable::new(); + table.extend(iter); + table + } +} + +impl IntoIterator for InlineTable { + type Item = (InternalString, Value); + type IntoIter = InlineTableIntoIter; + + fn into_iter(self) -> Self::IntoIter { + Box::new( + self.items + .into_iter() + .filter(|(_, kv)| kv.value.is_value()) + .map(|(k, kv)| (k, kv.value.into_value().unwrap())), + ) + } +} + +impl<'s> IntoIterator for &'s InlineTable { + type Item = (&'s str, &'s Value); + type IntoIter = InlineTableIter<'s>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +fn decorate_inline_table(table: &mut InlineTable) { + for (key_decor, value) in table + .items + .iter_mut() + .filter(|&(_, ref kv)| kv.value.is_value()) + .map(|(_, kv)| (&mut kv.key.decor, kv.value.as_value_mut().unwrap())) + { + key_decor.clear(); + value.decor_mut().clear(); + } +} + +/// An owned iterator type over key/value pairs of an inline table. +pub type InlineTableIntoIter = Box<dyn Iterator<Item = (InternalString, Value)>>; +/// An iterator type over key/value pairs of an inline table. +pub type InlineTableIter<'a> = Box<dyn Iterator<Item = (&'a str, &'a Value)> + 'a>; +/// A mutable iterator type over key/value pairs of an inline table. +pub type InlineTableIterMut<'a> = Box<dyn Iterator<Item = (KeyMut<'a>, &'a mut Value)> + 'a>; + +impl TableLike for InlineTable { + fn iter(&self) -> Iter<'_> { + Box::new(self.items.iter().map(|(key, kv)| (&key[..], &kv.value))) + } + fn iter_mut(&mut self) -> IterMut<'_> { + Box::new( + self.items + .iter_mut() + .map(|(_, kv)| (kv.key.as_mut(), &mut kv.value)), + ) + } + fn clear(&mut self) { + self.clear(); + } + fn entry<'a>(&'a mut self, key: &str) -> crate::Entry<'a> { + // Accept a `&str` rather than an owned type to keep `InternalString`, well, internal + match self.items.entry(key.into()) { + indexmap::map::Entry::Occupied(entry) => { + crate::Entry::Occupied(crate::OccupiedEntry { entry }) + } + indexmap::map::Entry::Vacant(entry) => { + crate::Entry::Vacant(crate::VacantEntry { entry, key: None }) + } + } + } + fn entry_format<'a>(&'a mut self, key: &Key) -> crate::Entry<'a> { + // Accept a `&Key` to be consistent with `entry` + match self.items.entry(key.get().into()) { + indexmap::map::Entry::Occupied(entry) => { + crate::Entry::Occupied(crate::OccupiedEntry { entry }) + } + indexmap::map::Entry::Vacant(entry) => crate::Entry::Vacant(crate::VacantEntry { + entry, + key: Some(key.to_owned()), + }), + } + } + fn get<'s>(&'s self, key: &str) -> Option<&'s Item> { + self.items.get(key).map(|kv| &kv.value) + } + fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item> { + self.items.get_mut(key).map(|kv| &mut kv.value) + } + fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> { + self.get_key_value(key) + } + fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> { + self.get_key_value_mut(key) + } + fn contains_key(&self, key: &str) -> bool { + self.contains_key(key) + } + fn insert(&mut self, key: &str, value: Item) -> Option<Item> { + self.insert(key, value.into_value().unwrap()) + .map(Item::Value) + } + fn remove(&mut self, key: &str) -> Option<Item> { + self.remove(key).map(Item::Value) + } + + fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> { + self.get_values() + } + fn fmt(&mut self) { + self.fmt() + } + fn sort_values(&mut self) { + self.sort_values() + } + fn set_dotted(&mut self, yes: bool) { + self.set_dotted(yes) + } + fn is_dotted(&self) -> bool { + self.is_dotted() + } + + fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> { + self.key_decor_mut(key) + } + fn key_decor(&self, key: &str) -> Option<&Decor> { + self.key_decor(key) + } +} + +// `{ key1 = value1, ... }` +pub(crate) const DEFAULT_INLINE_KEY_DECOR: (&str, &str) = (" ", " "); + +/// A view into a single location in a map, which may be vacant or occupied. +pub enum InlineEntry<'a> { + /// An occupied Entry. + Occupied(InlineOccupiedEntry<'a>), + /// A vacant Entry. + Vacant(InlineVacantEntry<'a>), +} + +impl<'a> InlineEntry<'a> { + /// Returns the entry key + /// + /// # Examples + /// + /// ``` + /// use toml_edit::Table; + /// + /// let mut map = Table::new(); + /// + /// assert_eq!("hello", map.entry("hello").key()); + /// ``` + pub fn key(&self) -> &str { + match self { + InlineEntry::Occupied(e) => e.key(), + InlineEntry::Vacant(e) => e.key(), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + pub fn or_insert(self, default: Value) -> &'a mut Value { + match self { + InlineEntry::Occupied(entry) => entry.into_mut(), + InlineEntry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + pub fn or_insert_with<F: FnOnce() -> Value>(self, default: F) -> &'a mut Value { + match self { + InlineEntry::Occupied(entry) => entry.into_mut(), + InlineEntry::Vacant(entry) => entry.insert(default()), + } + } +} + +/// A view into a single occupied location in a `IndexMap`. +pub struct InlineOccupiedEntry<'a> { + entry: indexmap::map::OccupiedEntry<'a, InternalString, TableKeyValue>, +} + +impl<'a> InlineOccupiedEntry<'a> { + /// Gets a reference to the entry key + /// + /// # Examples + /// + /// ``` + /// use toml_edit::Table; + /// + /// let mut map = Table::new(); + /// + /// assert_eq!("foo", map.entry("foo").key()); + /// ``` + pub fn key(&self) -> &str { + self.entry.key().as_str() + } + + /// Gets a mutable reference to the entry key + pub fn key_mut(&mut self) -> KeyMut<'_> { + self.entry.get_mut().key.as_mut() + } + + /// Gets a reference to the value in the entry. + pub fn get(&self) -> &Value { + self.entry.get().value.as_value().unwrap() + } + + /// Gets a mutable reference to the value in the entry. + pub fn get_mut(&mut self) -> &mut Value { + self.entry.get_mut().value.as_value_mut().unwrap() + } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself + pub fn into_mut(self) -> &'a mut Value { + self.entry.into_mut().value.as_value_mut().unwrap() + } + + /// Sets the value of the entry, and returns the entry's old value + pub fn insert(&mut self, value: Value) -> Value { + let mut value = Item::Value(value); + std::mem::swap(&mut value, &mut self.entry.get_mut().value); + value.into_value().unwrap() + } + + /// Takes the value out of the entry, and returns it + pub fn remove(self) -> Value { + self.entry.shift_remove().value.into_value().unwrap() + } +} + +/// A view into a single empty location in a `IndexMap`. +pub struct InlineVacantEntry<'a> { + entry: indexmap::map::VacantEntry<'a, InternalString, TableKeyValue>, + key: Option<Key>, +} + +impl<'a> InlineVacantEntry<'a> { + /// Gets a reference to the entry key + /// + /// # Examples + /// + /// ``` + /// use toml_edit::Table; + /// + /// let mut map = Table::new(); + /// + /// assert_eq!("foo", map.entry("foo").key()); + /// ``` + pub fn key(&self) -> &str { + self.entry.key().as_str() + } + + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it + pub fn insert(self, value: Value) -> &'a mut Value { + let entry = self.entry; + let key = self.key.unwrap_or_else(|| Key::new(entry.key().as_str())); + let value = Item::Value(value); + entry + .insert(TableKeyValue::new(key, value)) + .value + .as_value_mut() + .unwrap() + } +} diff --git a/vendor/toml_edit-0.19.11/src/internal_string.rs b/vendor/toml_edit-0.19.11/src/internal_string.rs new file mode 100644 index 000000000..d4347d25b --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/internal_string.rs @@ -0,0 +1,183 @@ +use std::borrow::Borrow; +use std::str::FromStr; + +/// Opaque string storage internal to `toml_edit` +#[derive(Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct InternalString(Inner); + +#[cfg(feature = "kstring")] +type Inner = kstring::KString; +#[cfg(not(feature = "kstring"))] +type Inner = String; + +impl InternalString { + /// Create an empty string + pub fn new() -> Self { + InternalString(Inner::new()) + } + + /// Access the underlying string + #[inline] + pub fn as_str(&self) -> &str { + self.0.as_str() + } +} + +impl std::fmt::Debug for InternalString { + #[inline] + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + self.0.fmt(formatter) + } +} + +impl std::ops::Deref for InternalString { + type Target = str; + + #[inline] + fn deref(&self) -> &str { + self.as_str() + } +} + +impl Borrow<str> for InternalString { + #[inline] + fn borrow(&self) -> &str { + self.as_str() + } +} + +impl AsRef<str> for InternalString { + #[inline] + fn as_ref(&self) -> &str { + self.as_str() + } +} + +impl From<&str> for InternalString { + #[inline] + fn from(s: &str) -> Self { + #[cfg(feature = "kstring")] + let inner = kstring::KString::from_ref(s); + #[cfg(not(feature = "kstring"))] + let inner = String::from(s); + + InternalString(inner) + } +} + +impl From<String> for InternalString { + #[inline] + fn from(s: String) -> Self { + #[allow(clippy::useless_conversion)] // handle any string type + InternalString(s.into()) + } +} + +impl From<&String> for InternalString { + #[inline] + fn from(s: &String) -> Self { + InternalString(s.into()) + } +} + +impl From<&InternalString> for InternalString { + #[inline] + fn from(s: &InternalString) -> Self { + s.clone() + } +} + +impl From<Box<str>> for InternalString { + #[inline] + fn from(s: Box<str>) -> Self { + InternalString(s.into()) + } +} + +impl FromStr for InternalString { + type Err = core::convert::Infallible; + #[inline] + fn from_str(s: &str) -> Result<Self, Self::Err> { + Ok(Self::from(s)) + } +} + +impl std::fmt::Display for InternalString { + #[inline] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.as_str().fmt(f) + } +} + +#[cfg(feature = "serde")] +impl serde::Serialize for InternalString { + #[inline] + fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error> + where + S: serde::Serializer, + { + serializer.serialize_str(self.as_str()) + } +} + +#[cfg(feature = "serde")] +impl<'de> serde::Deserialize<'de> for InternalString { + fn deserialize<D>(deserializer: D) -> Result<Self, D::Error> + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_string(StringVisitor) + } +} + +#[cfg(feature = "serde")] +struct StringVisitor; + +#[cfg(feature = "serde")] +impl<'de> serde::de::Visitor<'de> for StringVisitor { + type Value = InternalString; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + formatter.write_str("a string") + } + + fn visit_str<E>(self, v: &str) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + Ok(InternalString::from(v)) + } + + fn visit_string<E>(self, v: String) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + Ok(InternalString::from(v)) + } + + fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + match std::str::from_utf8(v) { + Ok(s) => Ok(InternalString::from(s)), + Err(_) => Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Bytes(v), + &self, + )), + } + } + + fn visit_byte_buf<E>(self, v: Vec<u8>) -> Result<Self::Value, E> + where + E: serde::de::Error, + { + match String::from_utf8(v) { + Ok(s) => Ok(InternalString::from(s)), + Err(e) => Err(serde::de::Error::invalid_value( + serde::de::Unexpected::Bytes(&e.into_bytes()), + &self, + )), + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/item.rs b/vendor/toml_edit-0.19.11/src/item.rs new file mode 100644 index 000000000..48a1a3566 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/item.rs @@ -0,0 +1,381 @@ +use std::str::FromStr; + +use toml_datetime::*; + +use crate::array_of_tables::ArrayOfTables; +use crate::table::TableLike; +use crate::{Array, InlineTable, Table, Value}; + +/// Type representing either a value, a table, an array of tables, or none. +#[derive(Debug, Clone)] +pub enum Item { + /// Type representing none. + None, + /// Type representing value. + Value(Value), + /// Type representing table. + Table(Table), + /// Type representing array of tables. + ArrayOfTables(ArrayOfTables), +} + +impl Item { + /// Sets `self` to the given item iff `self` is none and + /// returns a mutable reference to `self`. + pub fn or_insert(&mut self, item: Item) -> &mut Item { + if self.is_none() { + *self = item + } + self + } +} + +// TODO: This should be generated by macro or derive +/// Downcasting +impl Item { + /// Text description of value type + pub fn type_name(&self) -> &'static str { + match self { + Item::None => "none", + Item::Value(v) => v.type_name(), + Item::Table(..) => "table", + Item::ArrayOfTables(..) => "array of tables", + } + } + + /// Index into a TOML array or map. A string index can be used to access a + /// value in a map, and a usize index can be used to access an element of an + /// array. + /// + /// Returns `None` if: + /// - The type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is an array or a + /// number. + /// - The given key does not exist in the map + /// or the given index is not within the bounds of the array. + pub fn get<I: crate::index::Index>(&self, index: I) -> Option<&Item> { + index.index(self) + } + + /// Mutably index into a TOML array or map. A string index can be used to + /// access a value in a map, and a usize index can be used to access an + /// element of an array. + /// + /// Returns `None` if: + /// - The type of `self` does not match the type of the + /// index, for example if the index is a string and `self` is an array or a + /// number. + /// - The given key does not exist in the map + /// or the given index is not within the bounds of the array. + pub fn get_mut<I: crate::index::Index>(&mut self, index: I) -> Option<&mut Item> { + index.index_mut(self) + } + + /// Casts `self` to value. + pub fn as_value(&self) -> Option<&Value> { + match *self { + Item::Value(ref v) => Some(v), + _ => None, + } + } + /// Casts `self` to table. + pub fn as_table(&self) -> Option<&Table> { + match *self { + Item::Table(ref t) => Some(t), + _ => None, + } + } + /// Casts `self` to array of tables. + pub fn as_array_of_tables(&self) -> Option<&ArrayOfTables> { + match *self { + Item::ArrayOfTables(ref a) => Some(a), + _ => None, + } + } + /// Casts `self` to mutable value. + pub fn as_value_mut(&mut self) -> Option<&mut Value> { + match *self { + Item::Value(ref mut v) => Some(v), + _ => None, + } + } + /// Casts `self` to mutable table. + pub fn as_table_mut(&mut self) -> Option<&mut Table> { + match *self { + Item::Table(ref mut t) => Some(t), + _ => None, + } + } + /// Casts `self` to mutable array of tables. + pub fn as_array_of_tables_mut(&mut self) -> Option<&mut ArrayOfTables> { + match *self { + Item::ArrayOfTables(ref mut a) => Some(a), + _ => None, + } + } + /// Casts `self` to value. + pub fn into_value(self) -> Result<Value, Self> { + match self { + Item::None => Err(self), + Item::Value(v) => Ok(v), + Item::Table(v) => { + let v = v.into_inline_table(); + Ok(Value::InlineTable(v)) + } + Item::ArrayOfTables(v) => { + let v = v.into_array(); + Ok(Value::Array(v)) + } + } + } + /// In-place convert to a value + pub fn make_value(&mut self) { + let other = std::mem::take(self); + let other = other.into_value().map(Item::Value).unwrap_or(Item::None); + *self = other; + } + /// Casts `self` to table. + pub fn into_table(self) -> Result<Table, Self> { + match self { + Item::Table(t) => Ok(t), + Item::Value(Value::InlineTable(t)) => Ok(t.into_table()), + _ => Err(self), + } + } + /// Casts `self` to array of tables. + pub fn into_array_of_tables(self) -> Result<ArrayOfTables, Self> { + match self { + Item::ArrayOfTables(a) => Ok(a), + Item::Value(Value::Array(a)) => { + if a.is_empty() { + Err(Item::Value(Value::Array(a))) + } else if a.iter().all(|v| v.is_inline_table()) { + let mut aot = ArrayOfTables::new(); + aot.values = a.values; + for value in aot.values.iter_mut() { + value.make_item(); + } + Ok(aot) + } else { + Err(Item::Value(Value::Array(a))) + } + } + _ => Err(self), + } + } + // Starting private because the name is unclear + pub(crate) fn make_item(&mut self) { + let other = std::mem::take(self); + let other = match other.into_table().map(crate::Item::Table) { + Ok(i) => i, + Err(i) => i, + }; + let other = match other.into_array_of_tables().map(crate::Item::ArrayOfTables) { + Ok(i) => i, + Err(i) => i, + }; + *self = other; + } + /// Returns true iff `self` is a value. + pub fn is_value(&self) -> bool { + self.as_value().is_some() + } + /// Returns true iff `self` is a table. + pub fn is_table(&self) -> bool { + self.as_table().is_some() + } + /// Returns true iff `self` is an array of tables. + pub fn is_array_of_tables(&self) -> bool { + self.as_array_of_tables().is_some() + } + /// Returns true iff `self` is `None`. + pub fn is_none(&self) -> bool { + matches!(*self, Item::None) + } + + // Duplicate Value downcasting API + + /// Casts `self` to integer. + pub fn as_integer(&self) -> Option<i64> { + self.as_value().and_then(Value::as_integer) + } + + /// Returns true iff `self` is an integer. + pub fn is_integer(&self) -> bool { + self.as_integer().is_some() + } + + /// Casts `self` to float. + pub fn as_float(&self) -> Option<f64> { + self.as_value().and_then(Value::as_float) + } + + /// Returns true iff `self` is a float. + pub fn is_float(&self) -> bool { + self.as_float().is_some() + } + + /// Casts `self` to boolean. + pub fn as_bool(&self) -> Option<bool> { + self.as_value().and_then(Value::as_bool) + } + + /// Returns true iff `self` is a boolean. + pub fn is_bool(&self) -> bool { + self.as_bool().is_some() + } + + /// Casts `self` to str. + pub fn as_str(&self) -> Option<&str> { + self.as_value().and_then(Value::as_str) + } + + /// Returns true iff `self` is a string. + pub fn is_str(&self) -> bool { + self.as_str().is_some() + } + + /// Casts `self` to date-time. + pub fn as_datetime(&self) -> Option<&Datetime> { + self.as_value().and_then(Value::as_datetime) + } + + /// Returns true iff `self` is a date-time. + pub fn is_datetime(&self) -> bool { + self.as_datetime().is_some() + } + + /// Casts `self` to array. + pub fn as_array(&self) -> Option<&Array> { + self.as_value().and_then(Value::as_array) + } + + /// Casts `self` to mutable array. + pub fn as_array_mut(&mut self) -> Option<&mut Array> { + self.as_value_mut().and_then(Value::as_array_mut) + } + + /// Returns true iff `self` is an array. + pub fn is_array(&self) -> bool { + self.as_array().is_some() + } + + /// Casts `self` to inline table. + pub fn as_inline_table(&self) -> Option<&InlineTable> { + self.as_value().and_then(Value::as_inline_table) + } + + /// Casts `self` to mutable inline table. + pub fn as_inline_table_mut(&mut self) -> Option<&mut InlineTable> { + self.as_value_mut().and_then(Value::as_inline_table_mut) + } + + /// Returns true iff `self` is an inline table. + pub fn is_inline_table(&self) -> bool { + self.as_inline_table().is_some() + } + + /// Casts `self` to either a table or an inline table. + pub fn as_table_like(&self) -> Option<&dyn TableLike> { + self.as_table() + .map(|t| t as &dyn TableLike) + .or_else(|| self.as_inline_table().map(|t| t as &dyn TableLike)) + } + + /// Casts `self` to either a table or an inline table. + pub fn as_table_like_mut(&mut self) -> Option<&mut dyn TableLike> { + match self { + Item::Table(t) => Some(t as &mut dyn TableLike), + Item::Value(Value::InlineTable(t)) => Some(t as &mut dyn TableLike), + _ => None, + } + } + + /// Returns true iff `self` is either a table, or an inline table. + pub fn is_table_like(&self) -> bool { + self.as_table_like().is_some() + } + + /// Returns the location within the original document + pub(crate) fn span(&self) -> Option<std::ops::Range<usize>> { + match self { + Item::None => None, + Item::Value(v) => v.span(), + Item::Table(v) => v.span(), + Item::ArrayOfTables(v) => v.span(), + } + } + + pub(crate) fn despan(&mut self, input: &str) { + match self { + Item::None => {} + Item::Value(v) => v.despan(input), + Item::Table(v) => v.despan(input), + Item::ArrayOfTables(v) => v.despan(input), + } + } +} + +impl Default for Item { + fn default() -> Self { + Item::None + } +} + +impl FromStr for Item { + type Err = crate::TomlError; + + /// Parses a value from a &str + fn from_str(s: &str) -> Result<Self, Self::Err> { + let value = s.parse::<Value>()?; + Ok(Item::Value(value)) + } +} + +impl std::fmt::Display for Item { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match &self { + Item::None => Ok(()), + Item::Value(v) => v.fmt(f), + Item::Table(v) => v.fmt(f), + Item::ArrayOfTables(v) => v.fmt(f), + } + } +} + +/// Returns a formatted value. +/// +/// Since formatting is part of a `Value`, the right hand side of the +/// assignment needs to be decorated with a space before the value. +/// The `value` function does just that. +/// +/// # Examples +/// ```rust +/// # use snapbox::assert_eq; +/// # use toml_edit::*; +/// let mut table = Table::default(); +/// let mut array = Array::default(); +/// array.push("hello"); +/// array.push("\\, world"); // \ is only allowed in a literal string +/// table["key1"] = value("value1"); +/// table["key2"] = value(42); +/// table["key3"] = value(array); +/// assert_eq(table.to_string(), +/// r#"key1 = "value1" +/// key2 = 42 +/// key3 = ["hello", '\, world'] +/// "#); +/// ``` +pub fn value<V: Into<Value>>(v: V) -> Item { + Item::Value(v.into()) +} + +/// Returns an empty table. +pub fn table() -> Item { + Item::Table(Table::new()) +} + +/// Returns an empty array of tables. +pub fn array() -> Item { + Item::ArrayOfTables(ArrayOfTables::new()) +} diff --git a/vendor/toml_edit-0.19.11/src/key.rs b/vendor/toml_edit-0.19.11/src/key.rs new file mode 100644 index 000000000..b7038c36d --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/key.rs @@ -0,0 +1,333 @@ +use std::borrow::Cow; +use std::str::FromStr; + +use crate::encode::{to_string_repr, StringStyle}; +use crate::parser; +use crate::parser::key::is_unquoted_char; +use crate::repr::{Decor, Repr}; +use crate::InternalString; + +/// Key as part of a Key/Value Pair or a table header. +/// +/// # Examples +/// +/// ```notrust +/// [dependencies."nom"] +/// version = "5.0" +/// 'literal key' = "nonsense" +/// "basic string key" = 42 +/// ``` +/// +/// There are 3 types of keys: +/// +/// 1. Bare keys (`version` and `dependencies`) +/// +/// 2. Basic quoted keys (`"basic string key"` and `"nom"`) +/// +/// 3. Literal quoted keys (`'literal key'`) +/// +/// For details see [toml spec](https://github.com/toml-lang/toml/#keyvalue-pair). +/// +/// To parse a key use `FromStr` trait implementation: `"string".parse::<Key>()`. +#[derive(Debug, Clone)] +pub struct Key { + key: InternalString, + pub(crate) repr: Option<Repr>, + pub(crate) decor: Decor, +} + +impl Key { + /// Create a new table key + pub fn new(key: impl Into<InternalString>) -> Self { + Self { + key: key.into(), + repr: None, + decor: Default::default(), + } + } + + /// Parse a TOML key expression + /// + /// Unlike `"".parse<Key>()`, this supports dotted keys. + pub fn parse(repr: &str) -> Result<Vec<Self>, crate::TomlError> { + Self::try_parse_path(repr) + } + + pub(crate) fn with_repr_unchecked(mut self, repr: Repr) -> Self { + self.repr = Some(repr); + self + } + + /// While creating the `Key`, add `Decor` to it + pub fn with_decor(mut self, decor: Decor) -> Self { + self.decor = decor; + self + } + + /// Access a mutable proxy for the `Key`. + pub fn as_mut(&mut self) -> KeyMut<'_> { + KeyMut { key: self } + } + + /// Returns the parsed key value. + pub fn get(&self) -> &str { + &self.key + } + + pub(crate) fn get_internal(&self) -> &InternalString { + &self.key + } + + /// Returns key raw representation, if available. + pub fn as_repr(&self) -> Option<&Repr> { + self.repr.as_ref() + } + + /// Returns the default raw representation. + pub fn default_repr(&self) -> Repr { + to_key_repr(&self.key) + } + + /// Returns a raw representation. + pub fn display_repr(&self) -> Cow<'_, str> { + self.as_repr() + .and_then(|r| r.as_raw().as_str()) + .map(Cow::Borrowed) + .unwrap_or_else(|| { + Cow::Owned(self.default_repr().as_raw().as_str().unwrap().to_owned()) + }) + } + + /// Returns the surrounding whitespace + pub fn decor_mut(&mut self) -> &mut Decor { + &mut self.decor + } + + /// Returns the surrounding whitespace + pub fn decor(&self) -> &Decor { + &self.decor + } + + /// Returns the location within the original document + #[cfg(feature = "serde")] + pub(crate) fn span(&self) -> Option<std::ops::Range<usize>> { + self.repr.as_ref().and_then(|r| r.span()) + } + + pub(crate) fn despan(&mut self, input: &str) { + self.decor.despan(input); + if let Some(repr) = &mut self.repr { + repr.despan(input) + } + } + + /// Auto formats the key. + pub fn fmt(&mut self) { + self.repr = Some(to_key_repr(&self.key)); + self.decor.clear(); + } + + fn try_parse_simple(s: &str) -> Result<Key, crate::TomlError> { + let mut key = parser::parse_key(s)?; + key.despan(s); + Ok(key) + } + + fn try_parse_path(s: &str) -> Result<Vec<Key>, crate::TomlError> { + let mut keys = parser::parse_key_path(s)?; + for key in &mut keys { + key.despan(s); + } + Ok(keys) + } +} + +impl std::ops::Deref for Key { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.get() + } +} + +impl std::hash::Hash for Key { + fn hash<H: std::hash::Hasher>(&self, state: &mut H) { + self.get().hash(state); + } +} + +impl Ord for Key { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.get().cmp(other.get()) + } +} + +impl PartialOrd for Key { + fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { + Some(self.cmp(other)) + } +} + +impl Eq for Key {} + +impl PartialEq for Key { + #[inline] + fn eq(&self, other: &Key) -> bool { + PartialEq::eq(self.get(), other.get()) + } +} + +impl PartialEq<str> for Key { + #[inline] + fn eq(&self, other: &str) -> bool { + PartialEq::eq(self.get(), other) + } +} + +impl<'s> PartialEq<&'s str> for Key { + #[inline] + fn eq(&self, other: &&str) -> bool { + PartialEq::eq(self.get(), *other) + } +} + +impl PartialEq<String> for Key { + #[inline] + fn eq(&self, other: &String) -> bool { + PartialEq::eq(self.get(), other.as_str()) + } +} + +impl std::fmt::Display for Key { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + crate::encode::Encode::encode(self, f, None, ("", "")) + } +} + +impl FromStr for Key { + type Err = crate::TomlError; + + /// Tries to parse a key from a &str, + /// if fails, tries as basic quoted key (surrounds with "") + /// and then literal quoted key (surrounds with '') + fn from_str(s: &str) -> Result<Self, Self::Err> { + Key::try_parse_simple(s) + } +} + +fn to_key_repr(key: &str) -> Repr { + if key.as_bytes().iter().copied().all(is_unquoted_char) && !key.is_empty() { + Repr::new_unchecked(key) + } else { + to_string_repr(key, Some(StringStyle::OnelineSingle), Some(false)) + } +} + +impl<'b> From<&'b str> for Key { + fn from(s: &'b str) -> Self { + Key::new(s) + } +} + +impl<'b> From<&'b String> for Key { + fn from(s: &'b String) -> Self { + Key::new(s) + } +} + +impl From<String> for Key { + fn from(s: String) -> Self { + Key::new(s) + } +} + +impl From<InternalString> for Key { + fn from(s: InternalString) -> Self { + Key::new(s) + } +} + +#[doc(hidden)] +impl From<Key> for InternalString { + fn from(key: Key) -> InternalString { + key.key + } +} + +/// A mutable reference to a `Key` +#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash)] +pub struct KeyMut<'k> { + key: &'k mut Key, +} + +impl<'k> KeyMut<'k> { + /// Returns the parsed key value. + pub fn get(&self) -> &str { + self.key.get() + } + + /// Returns the raw representation, if available. + pub fn as_repr(&self) -> Option<&Repr> { + self.key.as_repr() + } + + /// Returns the default raw representation. + pub fn default_repr(&self) -> Repr { + self.key.default_repr() + } + + /// Returns a raw representation. + pub fn display_repr(&self) -> Cow<str> { + self.key.display_repr() + } + + /// Returns the surrounding whitespace + pub fn decor_mut(&mut self) -> &mut Decor { + self.key.decor_mut() + } + + /// Returns the surrounding whitespace + pub fn decor(&self) -> &Decor { + self.key.decor() + } + + /// Auto formats the key. + pub fn fmt(&mut self) { + self.key.fmt() + } +} + +impl<'k> std::ops::Deref for KeyMut<'k> { + type Target = str; + + fn deref(&self) -> &Self::Target { + self.get() + } +} + +impl<'s> PartialEq<str> for KeyMut<'s> { + #[inline] + fn eq(&self, other: &str) -> bool { + PartialEq::eq(self.get(), other) + } +} + +impl<'s> PartialEq<&'s str> for KeyMut<'s> { + #[inline] + fn eq(&self, other: &&str) -> bool { + PartialEq::eq(self.get(), *other) + } +} + +impl<'s> PartialEq<String> for KeyMut<'s> { + #[inline] + fn eq(&self, other: &String) -> bool { + PartialEq::eq(self.get(), other.as_str()) + } +} + +impl<'k> std::fmt::Display for KeyMut<'k> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(&self.key, f) + } +} diff --git a/vendor/toml_edit-0.19.11/src/lib.rs b/vendor/toml_edit-0.19.11/src/lib.rs new file mode 100644 index 000000000..80c0ddda2 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/lib.rs @@ -0,0 +1,124 @@ +#![deny(missing_docs)] +// https://github.com/Marwes/combine/issues/172 +#![recursion_limit = "256"] +#![cfg_attr(docsrs, feature(doc_auto_cfg))] + +//! # `toml_edit` +//! +//! This crate allows you to parse and modify toml +//! documents, while preserving comments, spaces *and +//! relative order* or items. +//! +//! If you also need the ease of a more traditional API, see the [`toml`] crate. +//! +//! # Example +//! +//! ```rust +//! use toml_edit::{Document, value}; +//! +//! let toml = r#" +//! "hello" = 'toml!' # comment +//! ['a'.b] +//! "#; +//! let mut doc = toml.parse::<Document>().expect("invalid doc"); +//! assert_eq!(doc.to_string(), toml); +//! // let's add a new key/value pair inside a.b: c = {d = "hello"} +//! doc["a"]["b"]["c"]["d"] = value("hello"); +//! // autoformat inline table a.b.c: { d = "hello" } +//! doc["a"]["b"]["c"].as_inline_table_mut().map(|t| t.fmt()); +//! let expected = r#" +//! "hello" = 'toml!' # comment +//! ['a'.b] +//! c = { d = "hello" } +//! "#; +//! assert_eq!(doc.to_string(), expected); +//! ``` +//! +//! ## Controlling formatting +//! +//! By default, values are created with default formatting +//! ```rust +//! let mut doc = toml_edit::Document::new(); +//! doc["foo"] = toml_edit::value("bar"); +//! let expected = r#"foo = "bar" +//! "#; +//! assert_eq!(doc.to_string(), expected); +//! ``` +//! +//! You can choose a custom TOML representation by parsing the value. +//! ```rust +//! let mut doc = toml_edit::Document::new(); +//! doc["foo"] = "'bar'".parse::<toml_edit::Item>().unwrap(); +//! let expected = r#"foo = 'bar' +//! "#; +//! assert_eq!(doc.to_string(), expected); +//! ``` +//! +//! ## Limitations +//! +//! Things it does not preserve: +//! +//! * Scattered array of tables (tables are reordered by default, see [test]). +//! * Order of dotted keys, see [issue](https://github.com/ordian/toml_edit/issues/163). +//! +//! [`toml`]: https://docs.rs/toml/latest/toml/ +//! [test]: https://github.com/ordian/toml_edit/blob/f09bd5d075fdb7d2ef8d9bb3270a34506c276753/tests/test_valid.rs#L84 + +mod array; +mod array_of_tables; +mod document; +mod encode; +mod index; +mod inline_table; +mod internal_string; +mod item; +mod key; +mod parser; +mod raw_string; +mod repr; +mod table; +mod value; + +#[cfg(feature = "serde")] +pub mod de; +#[cfg(feature = "serde")] +pub mod ser; + +pub mod visit; +pub mod visit_mut; + +pub use crate::array::{Array, ArrayIntoIter, ArrayIter, ArrayIterMut}; +pub use crate::array_of_tables::{ + ArrayOfTables, ArrayOfTablesIntoIter, ArrayOfTablesIter, ArrayOfTablesIterMut, +}; +pub use crate::document::Document; +pub use crate::inline_table::{ + InlineEntry, InlineOccupiedEntry, InlineTable, InlineTableIntoIter, InlineTableIter, + InlineTableIterMut, InlineVacantEntry, +}; +pub use crate::internal_string::InternalString; +pub use crate::item::{array, table, value, Item}; +pub use crate::key::{Key, KeyMut}; +pub use crate::parser::TomlError; +pub use crate::raw_string::RawString; +pub use crate::repr::{Decor, Formatted, Repr}; +pub use crate::table::{ + Entry, IntoIter, Iter, IterMut, OccupiedEntry, Table, TableLike, VacantEntry, +}; +pub use crate::value::Value; +pub use toml_datetime::*; + +// Prevent users from some traits. +pub(crate) mod private { + pub trait Sealed {} + impl Sealed for usize {} + impl Sealed for str {} + impl Sealed for String {} + impl Sealed for i64 {} + impl Sealed for f64 {} + impl Sealed for bool {} + impl Sealed for crate::Datetime {} + impl<'a, T: ?Sized> Sealed for &'a T where T: Sealed {} + impl Sealed for crate::Table {} + impl Sealed for crate::InlineTable {} +} diff --git a/vendor/toml_edit-0.19.11/src/parser/array.rs b/vendor/toml_edit-0.19.11/src/parser/array.rs new file mode 100644 index 000000000..a99bb8241 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/array.rs @@ -0,0 +1,147 @@ +use winnow::combinator::cut_err; +use winnow::combinator::delimited; +use winnow::combinator::opt; +use winnow::combinator::separated1; + +use crate::parser::trivia::ws_comment_newline; +use crate::parser::value::value; +use crate::{Array, Item, RawString, Value}; + +use crate::parser::prelude::*; + +// ;; Array + +// array = array-open array-values array-close +pub(crate) fn array( + check: RecursionCheck, +) -> impl FnMut(Input<'_>) -> IResult<Input<'_>, Array, ParserError<'_>> { + move |input| { + delimited( + ARRAY_OPEN, + cut_err(array_values(check)), + cut_err(ARRAY_CLOSE) + .context(Context::Expression("array")) + .context(Context::Expected(ParserValue::CharLiteral(']'))), + ) + .parse_next(input) + } +} + +// note: we're omitting ws and newlines here, because +// they should be part of the formatted values +// array-open = %x5B ws-newline ; [ +pub(crate) const ARRAY_OPEN: u8 = b'['; +// array-close = ws-newline %x5D ; ] +const ARRAY_CLOSE: u8 = b']'; +// array-sep = ws %x2C ws ; , Comma +const ARRAY_SEP: u8 = b','; + +// note: this rule is modified +// array-values = [ ( array-value array-sep array-values ) / +// array-value / ws-comment-newline ] +pub(crate) fn array_values( + check: RecursionCheck, +) -> impl FnMut(Input<'_>) -> IResult<Input<'_>, Array, ParserError<'_>> { + move |input| { + let check = check.recursing(input)?; + ( + opt( + (separated1(array_value(check), ARRAY_SEP), opt(ARRAY_SEP)).map( + |(v, trailing): (Vec<Value>, Option<u8>)| { + ( + Array::with_vec(v.into_iter().map(Item::Value).collect()), + trailing.is_some(), + ) + }, + ), + ), + ws_comment_newline.span(), + ) + .try_map::<_, _, std::str::Utf8Error>(|(array, trailing)| { + let (mut array, comma) = array.unwrap_or_default(); + array.set_trailing_comma(comma); + array.set_trailing(RawString::with_span(trailing)); + Ok(array) + }) + .parse_next(input) + } +} + +pub(crate) fn array_value( + check: RecursionCheck, +) -> impl FnMut(Input<'_>) -> IResult<Input<'_>, Value, ParserError<'_>> { + move |input| { + ( + ws_comment_newline.span(), + value(check), + ws_comment_newline.span(), + ) + .map(|(ws1, v, ws2)| v.decorated(RawString::with_span(ws1), RawString::with_span(ws2))) + .parse_next(input) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn arrays() { + let inputs = [ + r#"[]"#, + r#"[ ]"#, + r#"[ + 1, 2, 3 +]"#, + r#"[ + 1, + 2, # this is ok +]"#, + r#"[# comment +# comment2 + + + ]"#, + r#"[# comment +# comment2 + 1 + +#sd +, +# comment3 + + ]"#, + r#"[1]"#, + r#"[1,]"#, + r#"[ "all", 'strings', """are the same""", '''type''']"#, + r#"[ 100, -2,]"#, + r#"[1, 2, 3]"#, + r#"[1.1, 2.1, 3.1]"#, + r#"["a", "b", "c"]"#, + r#"[ [ 1, 2 ], [3, 4, 5] ]"#, + r#"[ [ 1, 2 ], ["a", "b", "c"] ]"#, + r#"[ { x = 1, a = "2" }, {a = "a",b = "b", c = "c"} ]"#, + ]; + for input in inputs { + dbg!(input); + let mut parsed = array(Default::default()).parse(new_input(input)); + if let Ok(parsed) = &mut parsed { + parsed.despan(input); + } + assert_eq!(parsed.map(|a| a.to_string()), Ok(input.to_owned())); + } + } + + #[test] + fn invalid_arrays() { + let invalid_inputs = [r#"["#, r#"[,]"#, r#"[,2]"#, r#"[1e165,,]"#]; + for input in invalid_inputs { + dbg!(input); + let mut parsed = array(Default::default()).parse(new_input(input)); + if let Ok(parsed) = &mut parsed { + parsed.despan(input); + } + assert!(parsed.is_err()); + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/parser/datetime.rs b/vendor/toml_edit-0.19.11/src/parser/datetime.rs new file mode 100644 index 000000000..122a00f5a --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/datetime.rs @@ -0,0 +1,433 @@ +use std::ops::RangeInclusive; + +use crate::parser::errors::CustomError; +use crate::parser::prelude::*; +use crate::parser::trivia::from_utf8_unchecked; + +use toml_datetime::*; +use winnow::combinator::alt; +use winnow::combinator::cut_err; +use winnow::combinator::opt; +use winnow::combinator::preceded; +use winnow::token::one_of; +use winnow::token::take_while; + +// ;; Date and Time (as defined in RFC 3339) + +// date-time = offset-date-time / local-date-time / local-date / local-time +// offset-date-time = full-date time-delim full-time +// local-date-time = full-date time-delim partial-time +// local-date = full-date +// local-time = partial-time +// full-time = partial-time time-offset +pub(crate) fn date_time(input: Input<'_>) -> IResult<Input<'_>, Datetime, ParserError<'_>> { + alt(( + (full_date, opt((time_delim, partial_time, opt(time_offset)))) + .map(|(date, opt)| { + match opt { + // Offset Date-Time + Some((_, time, offset)) => Datetime { + date: Some(date), + time: Some(time), + offset, + }, + // Local Date + None => Datetime { + date: Some(date), + time: None, + offset: None, + }, + } + }) + .context(Context::Expression("date-time")), + partial_time + .map(|t| t.into()) + .context(Context::Expression("time")), + )) + .parse_next(input) +} + +// full-date = date-fullyear "-" date-month "-" date-mday +pub(crate) fn full_date(input: Input<'_>) -> IResult<Input<'_>, Date, ParserError<'_>> { + (date_fullyear, b'-', cut_err((date_month, b'-', date_mday))) + .map(|(year, _, (month, _, day))| Date { year, month, day }) + .parse_next(input) +} + +// partial-time = time-hour ":" time-minute ":" time-second [time-secfrac] +pub(crate) fn partial_time(input: Input<'_>) -> IResult<Input<'_>, Time, ParserError<'_>> { + ( + time_hour, + b':', + cut_err((time_minute, b':', time_second, opt(time_secfrac))), + ) + .map(|(hour, _, (minute, _, second, nanosecond))| Time { + hour, + minute, + second, + nanosecond: nanosecond.unwrap_or_default(), + }) + .parse_next(input) +} + +// time-offset = "Z" / time-numoffset +// time-numoffset = ( "+" / "-" ) time-hour ":" time-minute +pub(crate) fn time_offset(input: Input<'_>) -> IResult<Input<'_>, Offset, ParserError<'_>> { + alt(( + one_of((b'Z', b'z')).value(Offset::Z), + ( + one_of((b'+', b'-')), + cut_err((time_hour, b':', time_minute)), + ) + .map(|(sign, (hours, _, minutes))| { + let sign = match sign { + b'+' => 1, + b'-' => -1, + _ => unreachable!("Parser prevents this"), + }; + sign * (hours as i16 * 60 + minutes as i16) + }) + .verify(|minutes| ((-24 * 60)..=(24 * 60)).contains(minutes)) + .map(|minutes| Offset::Custom { minutes }), + )) + .context(Context::Expression("time offset")) + .parse_next(input) +} + +// date-fullyear = 4DIGIT +pub(crate) fn date_fullyear(input: Input<'_>) -> IResult<Input<'_>, u16, ParserError<'_>> { + unsigned_digits::<4, 4> + .map(|s: &str| s.parse::<u16>().expect("4DIGIT should match u8")) + .parse_next(input) +} + +// date-month = 2DIGIT ; 01-12 +pub(crate) fn date_month(input: Input<'_>) -> IResult<Input<'_>, u8, ParserError<'_>> { + unsigned_digits::<2, 2> + .try_map(|s: &str| { + let d = s.parse::<u8>().expect("2DIGIT should match u8"); + if (1..=12).contains(&d) { + Ok(d) + } else { + Err(CustomError::OutOfRange) + } + }) + .parse_next(input) +} + +// date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year +pub(crate) fn date_mday(input: Input<'_>) -> IResult<Input<'_>, u8, ParserError<'_>> { + unsigned_digits::<2, 2> + .try_map(|s: &str| { + let d = s.parse::<u8>().expect("2DIGIT should match u8"); + if (1..=31).contains(&d) { + Ok(d) + } else { + Err(CustomError::OutOfRange) + } + }) + .parse_next(input) +} + +// time-delim = "T" / %x20 ; T, t, or space +pub(crate) fn time_delim(input: Input<'_>) -> IResult<Input<'_>, u8, ParserError<'_>> { + one_of(TIME_DELIM).parse_next(input) +} + +const TIME_DELIM: (u8, u8, u8) = (b'T', b't', b' '); + +// time-hour = 2DIGIT ; 00-23 +pub(crate) fn time_hour(input: Input<'_>) -> IResult<Input<'_>, u8, ParserError<'_>> { + unsigned_digits::<2, 2> + .try_map(|s: &str| { + let d = s.parse::<u8>().expect("2DIGIT should match u8"); + if (0..=23).contains(&d) { + Ok(d) + } else { + Err(CustomError::OutOfRange) + } + }) + .parse_next(input) +} + +// time-minute = 2DIGIT ; 00-59 +pub(crate) fn time_minute(input: Input<'_>) -> IResult<Input<'_>, u8, ParserError<'_>> { + unsigned_digits::<2, 2> + .try_map(|s: &str| { + let d = s.parse::<u8>().expect("2DIGIT should match u8"); + if (0..=59).contains(&d) { + Ok(d) + } else { + Err(CustomError::OutOfRange) + } + }) + .parse_next(input) +} + +// time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second rules +pub(crate) fn time_second(input: Input<'_>) -> IResult<Input<'_>, u8, ParserError<'_>> { + unsigned_digits::<2, 2> + .try_map(|s: &str| { + let d = s.parse::<u8>().expect("2DIGIT should match u8"); + if (0..=60).contains(&d) { + Ok(d) + } else { + Err(CustomError::OutOfRange) + } + }) + .parse_next(input) +} + +// time-secfrac = "." 1*DIGIT +pub(crate) fn time_secfrac(input: Input<'_>) -> IResult<Input<'_>, u32, ParserError<'_>> { + static SCALE: [u32; 10] = [ + 0, + 100_000_000, + 10_000_000, + 1_000_000, + 100_000, + 10_000, + 1_000, + 100, + 10, + 1, + ]; + const INF: usize = usize::MAX; + preceded(b'.', unsigned_digits::<1, INF>) + .try_map(|mut repr: &str| -> Result<u32, CustomError> { + let max_digits = SCALE.len() - 1; + if max_digits < repr.len() { + // Millisecond precision is required. Further precision of fractional seconds is + // implementation-specific. If the value contains greater precision than the + // implementation can support, the additional precision must be truncated, not rounded. + repr = &repr[0..max_digits]; + } + + let v = repr.parse::<u32>().map_err(|_| CustomError::OutOfRange)?; + let num_digits = repr.len(); + + // scale the number accordingly. + let scale = SCALE.get(num_digits).ok_or(CustomError::OutOfRange)?; + let v = v.checked_mul(*scale).ok_or(CustomError::OutOfRange)?; + Ok(v) + }) + .parse_next(input) +} + +pub(crate) fn unsigned_digits<const MIN: usize, const MAX: usize>( + input: Input<'_>, +) -> IResult<Input<'_>, &str, ParserError<'_>> { + take_while(MIN..=MAX, DIGIT) + .map(|b: &[u8]| unsafe { from_utf8_unchecked(b, "`is_ascii_digit` filters out on-ASCII") }) + .parse_next(input) +} + +// DIGIT = %x30-39 ; 0-9 +const DIGIT: RangeInclusive<u8> = b'0'..=b'9'; + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn offset_date_time() { + let inputs = [ + ( + "1979-05-27T07:32:00Z", + Datetime { + date: Some(Date { + year: 1979, + month: 5, + day: 27, + }), + time: Some(Time { + hour: 7, + minute: 32, + second: 0, + nanosecond: 0, + }), + offset: Some(Offset::Z), + }, + ), + ( + "1979-05-27T00:32:00-07:00", + Datetime { + date: Some(Date { + year: 1979, + month: 5, + day: 27, + }), + time: Some(Time { + hour: 0, + minute: 32, + second: 0, + nanosecond: 0, + }), + offset: Some(Offset::Custom { minutes: -7 * 60 }), + }, + ), + ( + "1979-05-27T00:32:00-00:36", + Datetime { + date: Some(Date { + year: 1979, + month: 5, + day: 27, + }), + time: Some(Time { + hour: 0, + minute: 32, + second: 0, + nanosecond: 0, + }), + offset: Some(Offset::Custom { minutes: -36 }), + }, + ), + ( + "1979-05-27T00:32:00.999999", + Datetime { + date: Some(Date { + year: 1979, + month: 5, + day: 27, + }), + time: Some(Time { + hour: 0, + minute: 32, + second: 0, + nanosecond: 999999000, + }), + offset: None, + }, + ), + ]; + for (input, expected) in inputs { + dbg!(input); + let actual = date_time.parse(new_input(input)).unwrap(); + assert_eq!(expected, actual); + } + } + + #[test] + fn local_date_time() { + let inputs = [ + ( + "1979-05-27T07:32:00", + Datetime { + date: Some(Date { + year: 1979, + month: 5, + day: 27, + }), + time: Some(Time { + hour: 7, + minute: 32, + second: 0, + nanosecond: 0, + }), + offset: None, + }, + ), + ( + "1979-05-27T00:32:00.999999", + Datetime { + date: Some(Date { + year: 1979, + month: 5, + day: 27, + }), + time: Some(Time { + hour: 0, + minute: 32, + second: 0, + nanosecond: 999999000, + }), + offset: None, + }, + ), + ]; + for (input, expected) in inputs { + dbg!(input); + let actual = date_time.parse(new_input(input)).unwrap(); + assert_eq!(expected, actual); + } + } + + #[test] + fn local_date() { + let inputs = [ + ( + "1979-05-27", + Datetime { + date: Some(Date { + year: 1979, + month: 5, + day: 27, + }), + time: None, + offset: None, + }, + ), + ( + "2017-07-20", + Datetime { + date: Some(Date { + year: 2017, + month: 7, + day: 20, + }), + time: None, + offset: None, + }, + ), + ]; + for (input, expected) in inputs { + dbg!(input); + let actual = date_time.parse(new_input(input)).unwrap(); + assert_eq!(expected, actual); + } + } + + #[test] + fn local_time() { + let inputs = [ + ( + "07:32:00", + Datetime { + date: None, + time: Some(Time { + hour: 7, + minute: 32, + second: 0, + nanosecond: 0, + }), + offset: None, + }, + ), + ( + "00:32:00.999999", + Datetime { + date: None, + time: Some(Time { + hour: 0, + minute: 32, + second: 0, + nanosecond: 999999000, + }), + offset: None, + }, + ), + ]; + for (input, expected) in inputs { + dbg!(input); + let actual = date_time.parse(new_input(input)).unwrap(); + assert_eq!(expected, actual); + } + } + + #[test] + fn time_fraction_truncated() { + let input = "1987-07-05T17:45:00.123456789012345Z"; + date_time.parse(new_input(input)).unwrap(); + } +} diff --git a/vendor/toml_edit-0.19.11/src/parser/document.rs b/vendor/toml_edit-0.19.11/src/parser/document.rs new file mode 100644 index 000000000..791185b68 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/document.rs @@ -0,0 +1,148 @@ +use std::cell::RefCell; + +use winnow::combinator::cut_err; +use winnow::combinator::eof; +use winnow::combinator::opt; +use winnow::combinator::peek; +use winnow::combinator::repeat; +use winnow::error::FromExternalError; +use winnow::token::any; +use winnow::token::one_of; + +use crate::document::Document; +use crate::key::Key; +use crate::parser::inline_table::KEYVAL_SEP; +use crate::parser::key::key; +use crate::parser::prelude::*; +use crate::parser::state::ParseState; +use crate::parser::table::table; +use crate::parser::trivia::{comment, line_ending, line_trailing, newline, ws}; +use crate::parser::value::value; +use crate::table::TableKeyValue; +use crate::Item; +use crate::RawString; + +// ;; TOML + +// toml = expression *( newline expression ) + +// expression = ( ( ws comment ) / +// ( ws keyval ws [ comment ] ) / +// ( ws table ws [ comment ] ) / +// ws ) +pub(crate) fn document(input: Input<'_>) -> IResult<Input<'_>, Document, ParserError<'_>> { + let state = RefCell::new(ParseState::default()); + let state_ref = &state; + + let (i, _o) = ( + // Remove BOM if present + opt(b"\xEF\xBB\xBF"), + parse_ws(state_ref), + repeat(0.., ( + dispatch! {peek(any); + crate::parser::trivia::COMMENT_START_SYMBOL => cut_err(parse_comment(state_ref)), + crate::parser::table::STD_TABLE_OPEN => cut_err(table(state_ref)), + crate::parser::trivia::LF | + crate::parser::trivia::CR => parse_newline(state_ref), + _ => cut_err(keyval(state_ref)), + }, + parse_ws(state_ref), + )) + .map(|()| ()), + eof, + ) + .parse_next(input)?; + state + .into_inner() + .into_document() + .map(|document| (i, document)) + .map_err(|err| { + winnow::error::ErrMode::Backtrack(ParserError::from_external_error( + i, + winnow::error::ErrorKind::Verify, + err, + )) + }) +} + +pub(crate) fn parse_comment<'s, 'i>( + state: &'s RefCell<ParseState>, +) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'_>> + 's { + move |i| { + (comment, line_ending) + .span() + .map(|span| { + state.borrow_mut().on_comment(span); + }) + .parse_next(i) + } +} + +pub(crate) fn parse_ws<'s, 'i>( + state: &'s RefCell<ParseState>, +) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'i>> + 's { + move |i| { + ws.span() + .map(|span| state.borrow_mut().on_ws(span)) + .parse_next(i) + } +} + +pub(crate) fn parse_newline<'s, 'i>( + state: &'s RefCell<ParseState>, +) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'i>> + 's { + move |i| { + newline + .span() + .map(|span| state.borrow_mut().on_ws(span)) + .parse_next(i) + } +} + +pub(crate) fn keyval<'s, 'i>( + state: &'s RefCell<ParseState>, +) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'i>> + 's { + move |i| { + parse_keyval + .try_map(|(p, kv)| state.borrow_mut().on_keyval(p, kv)) + .parse_next(i) + } +} + +// keyval = key keyval-sep val +pub(crate) fn parse_keyval( + input: Input<'_>, +) -> IResult<Input<'_>, (Vec<Key>, TableKeyValue), ParserError<'_>> { + ( + key, + cut_err(( + one_of(KEYVAL_SEP) + .context(Context::Expected(ParserValue::CharLiteral('.'))) + .context(Context::Expected(ParserValue::CharLiteral('='))), + ( + ws.span(), + value(RecursionCheck::default()), + line_trailing + .context(Context::Expected(ParserValue::CharLiteral('\n'))) + .context(Context::Expected(ParserValue::CharLiteral('#'))), + ), + )), + ) + .try_map::<_, _, std::str::Utf8Error>(|(key, (_, v))| { + let mut path = key; + let key = path.pop().expect("grammar ensures at least 1"); + + let (pre, v, suf) = v; + let pre = RawString::with_span(pre); + let suf = RawString::with_span(suf); + let v = v.decorated(pre, suf); + Ok(( + path, + TableKeyValue { + key, + value: Item::Value(v), + }, + )) + }) + .parse_next(input) +} diff --git a/vendor/toml_edit-0.19.11/src/parser/errors.rs b/vendor/toml_edit-0.19.11/src/parser/errors.rs new file mode 100644 index 000000000..4e3825f99 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/errors.rs @@ -0,0 +1,476 @@ +use std::error::Error as StdError; +use std::fmt::{Display, Formatter, Result}; + +use crate::parser::prelude::*; +use crate::Key; + +use winnow::BStr; + +/// Type representing a TOML parse error +#[derive(Debug, Clone, Eq, PartialEq, Hash)] +pub struct TomlError { + message: String, + original: Option<String>, + keys: Vec<String>, + span: Option<std::ops::Range<usize>>, +} + +impl TomlError { + pub(crate) fn new(error: ParserError<'_>, original: Input<'_>) -> Self { + use winnow::stream::Offset; + use winnow::stream::Stream; + + let offset = original.offset_to(&error.input); + let span = if offset == original.len() { + offset..offset + } else { + offset..(offset + 1) + }; + + let message = error.to_string(); + let original = original.next_slice(original.eof_offset()).1; + + Self { + message, + original: Some( + String::from_utf8(original.to_owned()).expect("original document was utf8"), + ), + keys: Vec::new(), + span: Some(span), + } + } + + #[cfg(feature = "serde")] + pub(crate) fn custom(message: String, span: Option<std::ops::Range<usize>>) -> Self { + Self { + message, + original: None, + keys: Vec::new(), + span, + } + } + + #[cfg(feature = "serde")] + pub(crate) fn add_key(&mut self, key: String) { + self.keys.insert(0, key); + } + + /// What went wrong + pub fn message(&self) -> &str { + &self.message + } + + /// The start/end index into the original document where the error occurred + pub fn span(&self) -> Option<std::ops::Range<usize>> { + self.span.clone() + } + + #[cfg(feature = "serde")] + pub(crate) fn set_span(&mut self, span: Option<std::ops::Range<usize>>) { + self.span = span; + } + + #[cfg(feature = "serde")] + pub(crate) fn set_original(&mut self, original: Option<String>) { + self.original = original; + } +} + +/// Displays a TOML parse error +/// +/// # Example +/// +/// TOML parse error at line 1, column 10 +/// | +/// 1 | 00:32:00.a999999 +/// | ^ +/// Unexpected `a` +/// Expected `digit` +/// While parsing a Time +/// While parsing a Date-Time +impl Display for TomlError { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + let mut context = false; + if let (Some(original), Some(span)) = (&self.original, self.span()) { + context = true; + + let (line, column) = translate_position(original.as_bytes(), span.start); + let line_num = line + 1; + let col_num = column + 1; + let gutter = line_num.to_string().len(); + let content = original.split('\n').nth(line).expect("valid line number"); + + writeln!( + f, + "TOML parse error at line {}, column {}", + line_num, col_num + )?; + // | + for _ in 0..=gutter { + write!(f, " ")?; + } + writeln!(f, "|")?; + + // 1 | 00:32:00.a999999 + write!(f, "{} | ", line_num)?; + writeln!(f, "{}", content)?; + + // | ^ + for _ in 0..=gutter { + write!(f, " ")?; + } + write!(f, "|")?; + for _ in 0..=column { + write!(f, " ")?; + } + // The span will be empty at eof, so we need to make sure we always print at least + // one `^` + write!(f, "^")?; + for _ in (span.start + 1)..(span.end.min(span.start + content.len())) { + write!(f, "^")?; + } + writeln!(f)?; + } + writeln!(f, "{}", self.message)?; + if !context && !self.keys.is_empty() { + writeln!(f, "in `{}`", self.keys.join("."))?; + } + + Ok(()) + } +} + +impl StdError for TomlError { + fn description(&self) -> &'static str { + "TOML parse error" + } +} + +#[derive(Debug)] +pub(crate) struct ParserError<'b> { + input: Input<'b>, + context: Vec<Context>, + cause: Option<Box<dyn std::error::Error + Send + Sync + 'static>>, +} + +impl<'b> winnow::error::ParseError<Input<'b>> for ParserError<'b> { + fn from_error_kind(input: Input<'b>, _kind: winnow::error::ErrorKind) -> Self { + Self { + input, + context: Default::default(), + cause: Default::default(), + } + } + + fn append(self, _input: Input<'b>, _kind: winnow::error::ErrorKind) -> Self { + self + } + + fn or(self, other: Self) -> Self { + other + } +} + +impl<'b> winnow::error::ParseError<&'b str> for ParserError<'b> { + fn from_error_kind(input: &'b str, _kind: winnow::error::ErrorKind) -> Self { + Self { + input: Input::new(BStr::new(input)), + context: Default::default(), + cause: Default::default(), + } + } + + fn append(self, _input: &'b str, _kind: winnow::error::ErrorKind) -> Self { + self + } + + fn or(self, other: Self) -> Self { + other + } +} + +impl<'b> winnow::error::ContextError<Input<'b>, Context> for ParserError<'b> { + fn add_context(mut self, _input: Input<'b>, ctx: Context) -> Self { + self.context.push(ctx); + self + } +} + +impl<'b, E: std::error::Error + Send + Sync + 'static> + winnow::error::FromExternalError<Input<'b>, E> for ParserError<'b> +{ + fn from_external_error(input: Input<'b>, _kind: winnow::error::ErrorKind, e: E) -> Self { + Self { + input, + context: Default::default(), + cause: Some(Box::new(e)), + } + } +} + +impl<'b, E: std::error::Error + Send + Sync + 'static> winnow::error::FromExternalError<&'b str, E> + for ParserError<'b> +{ + fn from_external_error(input: &'b str, _kind: winnow::error::ErrorKind, e: E) -> Self { + Self { + input: Input::new(BStr::new(input)), + context: Default::default(), + cause: Some(Box::new(e)), + } + } +} + +// For tests +impl<'b> std::cmp::PartialEq for ParserError<'b> { + fn eq(&self, other: &Self) -> bool { + self.input == other.input + && self.context == other.context + && self.cause.as_ref().map(ToString::to_string) + == other.cause.as_ref().map(ToString::to_string) + } +} + +impl<'a> std::fmt::Display for ParserError<'a> { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let expression = self.context.iter().find_map(|c| match c { + Context::Expression(c) => Some(c), + _ => None, + }); + let expected = self + .context + .iter() + .filter_map(|c| match c { + Context::Expected(c) => Some(c), + _ => None, + }) + .collect::<Vec<_>>(); + + let mut newline = false; + + if let Some(expression) = expression { + newline = true; + + write!(f, "invalid {}", expression)?; + } + + if !expected.is_empty() { + if newline { + writeln!(f)?; + } + newline = true; + + write!(f, "expected ")?; + for (i, expected) in expected.iter().enumerate() { + if i != 0 { + write!(f, ", ")?; + } + write!(f, "{}", expected)?; + } + } + if let Some(cause) = &self.cause { + if newline { + writeln!(f)?; + } + write!(f, "{}", cause)?; + } + + Ok(()) + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub(crate) enum Context { + Expression(&'static str), + Expected(ParserValue), +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub(crate) enum ParserValue { + CharLiteral(char), + StringLiteral(&'static str), + Description(&'static str), +} + +impl std::fmt::Display for ParserValue { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ParserValue::CharLiteral('\n') => "newline".fmt(f), + ParserValue::CharLiteral('`') => "'`'".fmt(f), + ParserValue::CharLiteral(c) if c.is_ascii_control() => { + write!(f, "`{}`", c.escape_debug()) + } + ParserValue::CharLiteral(c) => write!(f, "`{}`", c), + ParserValue::StringLiteral(c) => write!(f, "`{}`", c), + ParserValue::Description(c) => write!(f, "{}", c), + } + } +} + +fn translate_position(input: &[u8], index: usize) -> (usize, usize) { + if input.is_empty() { + return (0, index); + } + + let safe_index = index.min(input.len() - 1); + let column_offset = index - safe_index; + let index = safe_index; + + let nl = input[0..index] + .iter() + .rev() + .enumerate() + .find(|(_, b)| **b == b'\n') + .map(|(nl, _)| index - nl - 1); + let line_start = match nl { + Some(nl) => nl + 1, + None => 0, + }; + let line = input[0..line_start].iter().filter(|b| **b == b'\n').count(); + let line = line; + + let column = std::str::from_utf8(&input[line_start..=index]) + .map(|s| s.chars().count() - 1) + .unwrap_or_else(|_| index - line_start); + let column = column + column_offset; + + (line, column) +} + +#[cfg(test)] +mod test_translate_position { + use super::*; + + #[test] + fn empty() { + let input = b""; + let index = 0; + let position = translate_position(&input[..], index); + assert_eq!(position, (0, 0)); + } + + #[test] + fn start() { + let input = b"Hello"; + let index = 0; + let position = translate_position(&input[..], index); + assert_eq!(position, (0, 0)); + } + + #[test] + fn end() { + let input = b"Hello"; + let index = input.len() - 1; + let position = translate_position(&input[..], index); + assert_eq!(position, (0, input.len() - 1)); + } + + #[test] + fn after() { + let input = b"Hello"; + let index = input.len(); + let position = translate_position(&input[..], index); + assert_eq!(position, (0, input.len())); + } + + #[test] + fn first_line() { + let input = b"Hello\nWorld\n"; + let index = 2; + let position = translate_position(&input[..], index); + assert_eq!(position, (0, 2)); + } + + #[test] + fn end_of_line() { + let input = b"Hello\nWorld\n"; + let index = 5; + let position = translate_position(&input[..], index); + assert_eq!(position, (0, 5)); + } + + #[test] + fn start_of_second_line() { + let input = b"Hello\nWorld\n"; + let index = 6; + let position = translate_position(&input[..], index); + assert_eq!(position, (1, 0)); + } + + #[test] + fn second_line() { + let input = b"Hello\nWorld\n"; + let index = 8; + let position = translate_position(&input[..], index); + assert_eq!(position, (1, 2)); + } +} + +#[derive(Debug, Clone)] +pub(crate) enum CustomError { + DuplicateKey { + key: String, + table: Option<Vec<Key>>, + }, + DottedKeyExtendWrongType { + key: Vec<Key>, + actual: &'static str, + }, + OutOfRange, + #[cfg_attr(feature = "unbounded", allow(dead_code))] + RecursionLimitExceeded, +} + +impl CustomError { + pub(crate) fn duplicate_key(path: &[Key], i: usize) -> Self { + assert!(i < path.len()); + let key = &path[i]; + let repr = key.display_repr(); + Self::DuplicateKey { + key: repr.into(), + table: Some(path[..i].to_vec()), + } + } + + pub(crate) fn extend_wrong_type(path: &[Key], i: usize, actual: &'static str) -> Self { + assert!(i < path.len()); + Self::DottedKeyExtendWrongType { + key: path[..=i].to_vec(), + actual, + } + } +} + +impl StdError for CustomError { + fn description(&self) -> &'static str { + "TOML parse error" + } +} + +impl Display for CustomError { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + match self { + CustomError::DuplicateKey { key, table } => { + if let Some(table) = table { + if table.is_empty() { + write!(f, "duplicate key `{}` in document root", key) + } else { + let path = table.iter().map(|k| k.get()).collect::<Vec<_>>().join("."); + write!(f, "duplicate key `{}` in table `{}`", key, path) + } + } else { + write!(f, "duplicate key `{}`", key) + } + } + CustomError::DottedKeyExtendWrongType { key, actual } => { + let path = key.iter().map(|k| k.get()).collect::<Vec<_>>().join("."); + write!( + f, + "dotted key `{}` attempted to extend non-table type ({})", + path, actual + ) + } + CustomError::OutOfRange => write!(f, "value is out of range"), + CustomError::RecursionLimitExceeded => write!(f, "recursion limit exceded"), + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/parser/inline_table.rs b/vendor/toml_edit-0.19.11/src/parser/inline_table.rs new file mode 100644 index 000000000..0a75c2104 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/inline_table.rs @@ -0,0 +1,182 @@ +use winnow::combinator::cut_err; +use winnow::combinator::delimited; +use winnow::combinator::separated0; +use winnow::token::one_of; + +use crate::key::Key; +use crate::parser::errors::CustomError; +use crate::parser::key::key; +use crate::parser::prelude::*; +use crate::parser::trivia::ws; +use crate::parser::value::value; +use crate::table::TableKeyValue; +use crate::{InlineTable, InternalString, Item, RawString, Value}; + +use indexmap::map::Entry; + +// ;; Inline Table + +// inline-table = inline-table-open inline-table-keyvals inline-table-close +pub(crate) fn inline_table( + check: RecursionCheck, +) -> impl FnMut(Input<'_>) -> IResult<Input<'_>, InlineTable, ParserError<'_>> { + move |input| { + delimited( + INLINE_TABLE_OPEN, + cut_err(inline_table_keyvals(check).try_map(|(kv, p)| table_from_pairs(kv, p))), + cut_err(INLINE_TABLE_CLOSE) + .context(Context::Expression("inline table")) + .context(Context::Expected(ParserValue::CharLiteral('}'))), + ) + .parse_next(input) + } +} + +fn table_from_pairs( + v: Vec<(Vec<Key>, TableKeyValue)>, + preamble: RawString, +) -> Result<InlineTable, CustomError> { + let mut root = InlineTable::new(); + root.set_preamble(preamble); + // Assuming almost all pairs will be directly in `root` + root.items.reserve(v.len()); + + for (path, kv) in v { + let table = descend_path(&mut root, &path)?; + let key: InternalString = kv.key.get_internal().into(); + match table.items.entry(key) { + Entry::Vacant(o) => { + o.insert(kv); + } + Entry::Occupied(o) => { + return Err(CustomError::DuplicateKey { + key: o.key().as_str().into(), + table: None, + }); + } + } + } + Ok(root) +} + +fn descend_path<'a>( + mut table: &'a mut InlineTable, + path: &'a [Key], +) -> Result<&'a mut InlineTable, CustomError> { + for (i, key) in path.iter().enumerate() { + let entry = table.entry_format(key).or_insert_with(|| { + let mut new_table = InlineTable::new(); + new_table.set_dotted(true); + + Value::InlineTable(new_table) + }); + match *entry { + Value::InlineTable(ref mut sweet_child_of_mine) => { + table = sweet_child_of_mine; + } + ref v => { + return Err(CustomError::extend_wrong_type(path, i, v.type_name())); + } + } + } + Ok(table) +} + +// inline-table-open = %x7B ws ; { +pub(crate) const INLINE_TABLE_OPEN: u8 = b'{'; +// inline-table-close = ws %x7D ; } +const INLINE_TABLE_CLOSE: u8 = b'}'; +// inline-table-sep = ws %x2C ws ; , Comma +const INLINE_TABLE_SEP: u8 = b','; +// keyval-sep = ws %x3D ws ; = +pub(crate) const KEYVAL_SEP: u8 = b'='; + +// inline-table-keyvals = [ inline-table-keyvals-non-empty ] +// inline-table-keyvals-non-empty = +// ( key keyval-sep val inline-table-sep inline-table-keyvals-non-empty ) / +// ( key keyval-sep val ) + +fn inline_table_keyvals( + check: RecursionCheck, +) -> impl FnMut( + Input<'_>, +) -> IResult<Input<'_>, (Vec<(Vec<Key>, TableKeyValue)>, RawString), ParserError<'_>> { + move |input| { + let check = check.recursing(input)?; + ( + separated0(keyval(check), INLINE_TABLE_SEP), + ws.span().map(RawString::with_span), + ) + .parse_next(input) + } +} + +fn keyval( + check: RecursionCheck, +) -> impl FnMut(Input<'_>) -> IResult<Input<'_>, (Vec<Key>, TableKeyValue), ParserError<'_>> { + move |input| { + ( + key, + cut_err(( + one_of(KEYVAL_SEP) + .context(Context::Expected(ParserValue::CharLiteral('.'))) + .context(Context::Expected(ParserValue::CharLiteral('='))), + (ws.span(), value(check), ws.span()), + )), + ) + .map(|(key, (_, v))| { + let mut path = key; + let key = path.pop().expect("grammar ensures at least 1"); + + let (pre, v, suf) = v; + let pre = RawString::with_span(pre); + let suf = RawString::with_span(suf); + let v = v.decorated(pre, suf); + ( + path, + TableKeyValue { + key, + value: Item::Value(v), + }, + ) + }) + .parse_next(input) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn inline_tables() { + let inputs = [ + r#"{}"#, + r#"{ }"#, + r#"{a = 1e165}"#, + r#"{ hello = "world", a = 1}"#, + r#"{ hello.world = "a" }"#, + ]; + for input in inputs { + dbg!(input); + let mut parsed = inline_table(Default::default()).parse(new_input(input)); + if let Ok(parsed) = &mut parsed { + parsed.despan(input); + } + assert_eq!(parsed.map(|a| a.to_string()), Ok(input.to_owned())); + } + } + + #[test] + fn invalid_inline_tables() { + let invalid_inputs = [r#"{a = 1e165"#, r#"{ hello = "world", a = 2, hello = 1}"#]; + for input in invalid_inputs { + dbg!(input); + let mut parsed = inline_table(Default::default()).parse(new_input(input)); + if let Ok(parsed) = &mut parsed { + parsed.despan(input); + } + assert!(parsed.is_err()); + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/parser/key.rs b/vendor/toml_edit-0.19.11/src/parser/key.rs new file mode 100644 index 000000000..eda319307 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/key.rs @@ -0,0 +1,104 @@ +use std::ops::RangeInclusive; + +use winnow::combinator::peek; +use winnow::combinator::separated1; +use winnow::token::any; +use winnow::token::take_while; + +use crate::key::Key; +use crate::parser::errors::CustomError; +use crate::parser::prelude::*; +use crate::parser::strings::{basic_string, literal_string}; +use crate::parser::trivia::{from_utf8_unchecked, ws}; +use crate::repr::{Decor, Repr}; +use crate::InternalString; +use crate::RawString; + +// key = simple-key / dotted-key +// dotted-key = simple-key 1*( dot-sep simple-key ) +pub(crate) fn key(input: Input<'_>) -> IResult<Input<'_>, Vec<Key>, ParserError<'_>> { + separated1( + (ws.span(), simple_key, ws.span()).map(|(pre, (raw, key), suffix)| { + Key::new(key) + .with_repr_unchecked(Repr::new_unchecked(raw)) + .with_decor(Decor::new( + RawString::with_span(pre), + RawString::with_span(suffix), + )) + }), + DOT_SEP, + ) + .context(Context::Expression("key")) + .try_map(|k: Vec<_>| { + // Inserting the key will require recursion down the line + RecursionCheck::check_depth(k.len())?; + Ok::<_, CustomError>(k) + }) + .parse_next(input) +} + +// simple-key = quoted-key / unquoted-key +// quoted-key = basic-string / literal-string +pub(crate) fn simple_key( + input: Input<'_>, +) -> IResult<Input<'_>, (RawString, InternalString), ParserError<'_>> { + dispatch! {peek(any); + crate::parser::strings::QUOTATION_MARK => basic_string + .map(|s: std::borrow::Cow<'_, str>| s.as_ref().into()), + crate::parser::strings::APOSTROPHE => literal_string.map(|s: &str| s.into()), + _ => unquoted_key.map(|s: &str| s.into()), + } + .with_span() + .map(|(k, span)| { + let raw = RawString::with_span(span); + (raw, k) + }) + .parse_next(input) +} + +// unquoted-key = 1*( ALPHA / DIGIT / %x2D / %x5F ) ; A-Z / a-z / 0-9 / - / _ +fn unquoted_key(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + take_while(1.., UNQUOTED_CHAR) + .map(|b| unsafe { from_utf8_unchecked(b, "`is_unquoted_char` filters out on-ASCII") }) + .parse_next(input) +} + +pub(crate) fn is_unquoted_char(c: u8) -> bool { + use winnow::stream::ContainsToken; + UNQUOTED_CHAR.contains_token(c) +} + +const UNQUOTED_CHAR: ( + RangeInclusive<u8>, + RangeInclusive<u8>, + RangeInclusive<u8>, + u8, + u8, +) = (b'A'..=b'Z', b'a'..=b'z', b'0'..=b'9', b'-', b'_'); + +// dot-sep = ws %x2E ws ; . Period +const DOT_SEP: u8 = b'.'; + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn keys() { + let cases = [ + ("a", "a"), + (r#""hello\n ""#, "hello\n "), + (r#"'hello\n '"#, "hello\\n "), + ]; + + for (input, expected) in cases { + dbg!(input); + let parsed = simple_key.parse(new_input(input)); + assert_eq!( + parsed, + Ok((RawString::with_span(0..(input.len())), expected.into())), + "Parsing {input:?}" + ); + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/parser/macros.rs b/vendor/toml_edit-0.19.11/src/parser/macros.rs new file mode 100644 index 000000000..93050f5ad --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/macros.rs @@ -0,0 +1,13 @@ +macro_rules! dispatch { + ($match_parser: expr; $( $pat:pat $(if $pred:expr)? => $expr: expr ),+ $(,)? ) => { + move |i| + { + let (i, initial) = $match_parser.parse_next(i)?; + match initial { + $( + $pat $(if $pred)? => $expr.parse_next(i), + )* + } + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/parser/mod.rs b/vendor/toml_edit-0.19.11/src/parser/mod.rs new file mode 100644 index 000000000..b2ce4bc5e --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/mod.rs @@ -0,0 +1,302 @@ +#![allow(clippy::type_complexity)] + +#[macro_use] +pub(crate) mod macros; + +pub(crate) mod array; +pub(crate) mod datetime; +pub(crate) mod document; +pub(crate) mod errors; +pub(crate) mod inline_table; +pub(crate) mod key; +pub(crate) mod numbers; +pub(crate) mod state; +pub(crate) mod strings; +pub(crate) mod table; +pub(crate) mod trivia; +pub(crate) mod value; + +pub use errors::TomlError; + +pub(crate) fn parse_document(raw: &str) -> Result<crate::Document, TomlError> { + use prelude::*; + + let b = new_input(raw); + let mut doc = document::document + .parse(b) + .map_err(|e| TomlError::new(e, b))?; + doc.span = Some(0..(raw.len())); + doc.original = Some(raw.to_owned()); + Ok(doc) +} + +pub(crate) fn parse_key(raw: &str) -> Result<crate::Key, TomlError> { + use prelude::*; + + let b = new_input(raw); + let result = key::simple_key.parse(b); + match result { + Ok((raw, key)) => { + Ok(crate::Key::new(key).with_repr_unchecked(crate::Repr::new_unchecked(raw))) + } + Err(e) => Err(TomlError::new(e, b)), + } +} + +pub(crate) fn parse_key_path(raw: &str) -> Result<Vec<crate::Key>, TomlError> { + use prelude::*; + + let b = new_input(raw); + let result = key::key.parse(b); + match result { + Ok(mut keys) => { + for key in &mut keys { + key.despan(raw); + } + Ok(keys) + } + Err(e) => Err(TomlError::new(e, b)), + } +} + +pub(crate) fn parse_value(raw: &str) -> Result<crate::Value, TomlError> { + use prelude::*; + + let b = new_input(raw); + let parsed = value::value(RecursionCheck::default()).parse(b); + match parsed { + Ok(mut value) => { + // Only take the repr and not decor, as its probably not intended + value.decor_mut().clear(); + value.despan(raw); + Ok(value) + } + Err(e) => Err(TomlError::new(e, b)), + } +} + +pub(crate) mod prelude { + pub(crate) use super::errors::Context; + pub(crate) use super::errors::ParserError; + pub(crate) use super::errors::ParserValue; + pub(crate) use winnow::IResult; + pub(crate) use winnow::Parser as _; + + pub(crate) type Input<'b> = winnow::Located<&'b winnow::BStr>; + + pub(crate) fn new_input(s: &str) -> Input<'_> { + winnow::Located::new(winnow::BStr::new(s)) + } + + pub(crate) fn ok_error<I, O, E>( + res: IResult<I, O, E>, + ) -> Result<Option<(I, O)>, winnow::error::ErrMode<E>> { + match res { + Ok(ok) => Ok(Some(ok)), + Err(winnow::error::ErrMode::Backtrack(_)) => Ok(None), + Err(err) => Err(err), + } + } + + #[allow(dead_code)] + pub(crate) fn trace<I: std::fmt::Debug, O: std::fmt::Debug, E: std::fmt::Debug>( + context: impl std::fmt::Display, + mut parser: impl winnow::Parser<I, O, E>, + ) -> impl FnMut(I) -> IResult<I, O, E> { + static DEPTH: std::sync::atomic::AtomicUsize = std::sync::atomic::AtomicUsize::new(0); + move |input: I| { + let depth = DEPTH.fetch_add(1, std::sync::atomic::Ordering::SeqCst) * 2; + eprintln!("{:depth$}--> {} {:?}", "", context, input); + match parser.parse_next(input) { + Ok((i, o)) => { + DEPTH.fetch_sub(1, std::sync::atomic::Ordering::SeqCst); + eprintln!("{:depth$}<-- {} {:?}", "", context, i); + Ok((i, o)) + } + Err(err) => { + DEPTH.fetch_sub(1, std::sync::atomic::Ordering::SeqCst); + eprintln!("{:depth$}<-- {} {:?}", "", context, err); + Err(err) + } + } + } + } + + #[cfg(not(feature = "unbounded"))] + #[derive(Copy, Clone, Debug, Default)] + pub(crate) struct RecursionCheck { + current: usize, + } + + #[cfg(not(feature = "unbounded"))] + impl RecursionCheck { + pub(crate) fn check_depth(depth: usize) -> Result<(), super::errors::CustomError> { + if depth < 128 { + Ok(()) + } else { + Err(super::errors::CustomError::RecursionLimitExceeded) + } + } + + pub(crate) fn recursing( + mut self, + input: Input<'_>, + ) -> Result<Self, winnow::error::ErrMode<ParserError<'_>>> { + self.current += 1; + if self.current < 128 { + Ok(self) + } else { + Err(winnow::error::ErrMode::Backtrack( + winnow::error::FromExternalError::from_external_error( + input, + winnow::error::ErrorKind::Eof, + super::errors::CustomError::RecursionLimitExceeded, + ), + )) + } + } + } + + #[cfg(feature = "unbounded")] + #[derive(Copy, Clone, Debug, Default)] + pub(crate) struct RecursionCheck {} + + #[cfg(feature = "unbounded")] + impl RecursionCheck { + pub(crate) fn check_depth(_depth: usize) -> Result<(), super::errors::CustomError> { + Ok(()) + } + + pub(crate) fn recursing( + self, + _input: Input<'_>, + ) -> Result<Self, winnow::error::ErrMode<ParserError<'_>>> { + Ok(self) + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn documents() { + let documents = [ + "", + r#" +# This is a TOML document. + +title = "TOML Example" + + [owner] + name = "Tom Preston-Werner" + dob = 1979-05-27T07:32:00-08:00 # First class dates + + [database] + server = "192.168.1.1" + ports = [ 8001, 8001, 8002 ] + connection_max = 5000 + enabled = true + + [servers] + + # Indentation (tabs and/or spaces) is allowed but not required +[servers.alpha] + ip = "10.0.0.1" + dc = "eqdc10" + + [servers.beta] + ip = "10.0.0.2" + dc = "eqdc10" + + [clients] + data = [ ["gamma", "delta"], [1, 2] ] + + # Line breaks are OK when inside arrays +hosts = [ + "alpha", + "omega" +] + + 'some.wierd .stuff' = """ + like + that + # """ # this broke my sintax highlighting + " also. like " = ''' +that +''' + double = 2e39 # this number looks familiar +# trailing comment"#, + r#""#, + r#" "#, + r#" hello = 'darkness' # my old friend +"#, + r#"[parent . child] +key = "value" +"#, + r#"hello.world = "a" +"#, + r#"foo = 1979-05-27 # Comment +"#, + ]; + for input in documents { + dbg!(input); + let mut parsed = parse_document(input); + if let Ok(parsed) = &mut parsed { + parsed.despan(); + } + let doc = match parsed { + Ok(doc) => doc, + Err(err) => { + panic!( + "Parse error: {:?}\nFailed to parse:\n```\n{}\n```", + err, input + ) + } + }; + + snapbox::assert_eq(input, doc.to_string()); + } + } + + #[test] + fn documents_parse_only() { + let parse_only = ["\u{FEFF} +[package] +name = \"foo\" +version = \"0.0.1\" +authors = [] +"]; + for input in parse_only { + dbg!(input); + let mut parsed = parse_document(input); + if let Ok(parsed) = &mut parsed { + parsed.despan(); + } + match parsed { + Ok(_) => (), + Err(err) => { + panic!( + "Parse error: {:?}\nFailed to parse:\n```\n{}\n```", + err, input + ) + } + } + } + } + + #[test] + fn invalid_documents() { + let invalid_inputs = [r#" hello = 'darkness' # my old friend +$"#]; + for input in invalid_inputs { + dbg!(input); + let mut parsed = parse_document(input); + if let Ok(parsed) = &mut parsed { + parsed.despan(); + } + assert!(parsed.is_err(), "Input: {:?}", input); + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/parser/numbers.rs b/vendor/toml_edit-0.19.11/src/parser/numbers.rs new file mode 100644 index 000000000..803cc9d57 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/numbers.rs @@ -0,0 +1,369 @@ +use std::ops::RangeInclusive; + +use winnow::combinator::alt; +use winnow::combinator::cut_err; +use winnow::combinator::opt; +use winnow::combinator::peek; +use winnow::combinator::preceded; +use winnow::combinator::repeat; +use winnow::combinator::rest; +use winnow::token::one_of; +use winnow::token::tag; +use winnow::token::take; + +use crate::parser::prelude::*; +use crate::parser::trivia::from_utf8_unchecked; + +// ;; Boolean + +// boolean = true / false +#[allow(dead_code)] // directly define in `fn value` +pub(crate) fn boolean(input: Input<'_>) -> IResult<Input<'_>, bool, ParserError<'_>> { + alt((true_, false_)).parse_next(input) +} + +pub(crate) fn true_(input: Input<'_>) -> IResult<Input<'_>, bool, ParserError<'_>> { + (peek(TRUE[0]), cut_err(TRUE)).value(true).parse_next(input) +} +const TRUE: &[u8] = b"true"; + +pub(crate) fn false_(input: Input<'_>) -> IResult<Input<'_>, bool, ParserError<'_>> { + (peek(FALSE[0]), cut_err(FALSE)) + .value(false) + .parse_next(input) +} +const FALSE: &[u8] = b"false"; + +// ;; Integer + +// integer = dec-int / hex-int / oct-int / bin-int +pub(crate) fn integer(input: Input<'_>) -> IResult<Input<'_>, i64, ParserError<'_>> { + dispatch! {peek(opt::<_, &[u8], _, _>(take(2usize))); + Some(b"0x") => cut_err(hex_int.try_map(|s| i64::from_str_radix(&s.replace('_', ""), 16))), + Some(b"0o") => cut_err(oct_int.try_map(|s| i64::from_str_radix(&s.replace('_', ""), 8))), + Some(b"0b") => cut_err(bin_int.try_map(|s| i64::from_str_radix(&s.replace('_', ""), 2))), + _ => dec_int.and_then(cut_err(rest + .try_map(|s: &str| s.replace('_', "").parse()))) + } + .parse_next(input) +} + +// dec-int = [ minus / plus ] unsigned-dec-int +// unsigned-dec-int = DIGIT / digit1-9 1*( DIGIT / underscore DIGIT ) +pub(crate) fn dec_int(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + ( + opt(one_of((b'+', b'-'))), + alt(( + ( + one_of(DIGIT1_9), + repeat( + 0.., + alt(( + digit.value(()), + ( + one_of(b'_'), + cut_err(digit) + .context(Context::Expected(ParserValue::Description("digit"))), + ) + .value(()), + )), + ) + .map(|()| ()), + ) + .value(()), + digit.value(()), + )), + ) + .recognize() + .map(|b: &[u8]| unsafe { from_utf8_unchecked(b, "`digit` and `_` filter out non-ASCII") }) + .context(Context::Expression("integer")) + .parse_next(input) +} +const DIGIT1_9: RangeInclusive<u8> = b'1'..=b'9'; + +// hex-prefix = %x30.78 ; 0x +// hex-int = hex-prefix HEXDIG *( HEXDIG / underscore HEXDIG ) +pub(crate) fn hex_int(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + preceded( + HEX_PREFIX, + cut_err(( + hexdig, + repeat( + 0.., + alt(( + hexdig.value(()), + ( + one_of(b'_'), + cut_err(hexdig) + .context(Context::Expected(ParserValue::Description("digit"))), + ) + .value(()), + )), + ) + .map(|()| ()), + )) + .recognize(), + ) + .map(|b| unsafe { from_utf8_unchecked(b, "`hexdig` and `_` filter out non-ASCII") }) + .context(Context::Expression("hexadecimal integer")) + .parse_next(input) +} +const HEX_PREFIX: &[u8] = b"0x"; + +// oct-prefix = %x30.6F ; 0o +// oct-int = oct-prefix digit0-7 *( digit0-7 / underscore digit0-7 ) +pub(crate) fn oct_int(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + preceded( + OCT_PREFIX, + cut_err(( + one_of(DIGIT0_7), + repeat( + 0.., + alt(( + one_of(DIGIT0_7).value(()), + ( + one_of(b'_'), + cut_err(one_of(DIGIT0_7)) + .context(Context::Expected(ParserValue::Description("digit"))), + ) + .value(()), + )), + ) + .map(|()| ()), + )) + .recognize(), + ) + .map(|b| unsafe { from_utf8_unchecked(b, "`DIGIT0_7` and `_` filter out non-ASCII") }) + .context(Context::Expression("octal integer")) + .parse_next(input) +} +const OCT_PREFIX: &[u8] = b"0o"; +const DIGIT0_7: RangeInclusive<u8> = b'0'..=b'7'; + +// bin-prefix = %x30.62 ; 0b +// bin-int = bin-prefix digit0-1 *( digit0-1 / underscore digit0-1 ) +pub(crate) fn bin_int(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + preceded( + BIN_PREFIX, + cut_err(( + one_of(DIGIT0_1), + repeat( + 0.., + alt(( + one_of(DIGIT0_1).value(()), + ( + one_of(b'_'), + cut_err(one_of(DIGIT0_1)) + .context(Context::Expected(ParserValue::Description("digit"))), + ) + .value(()), + )), + ) + .map(|()| ()), + )) + .recognize(), + ) + .map(|b| unsafe { from_utf8_unchecked(b, "`DIGIT0_1` and `_` filter out non-ASCII") }) + .context(Context::Expression("binary integer")) + .parse_next(input) +} +const BIN_PREFIX: &[u8] = b"0b"; +const DIGIT0_1: RangeInclusive<u8> = b'0'..=b'1'; + +// ;; Float + +// float = float-int-part ( exp / frac [ exp ] ) +// float =/ special-float +// float-int-part = dec-int +pub(crate) fn float(input: Input<'_>) -> IResult<Input<'_>, f64, ParserError<'_>> { + alt(( + float_.and_then(cut_err( + rest.try_map(|s: &str| s.replace('_', "").parse()) + .verify(|f: &f64| *f != f64::INFINITY), + )), + special_float, + )) + .context(Context::Expression("floating-point number")) + .parse_next(input) +} + +pub(crate) fn float_(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + (dec_int, alt((exp, (frac, opt(exp)).map(|_| "")))) + .recognize() + .map(|b: &[u8]| unsafe { + from_utf8_unchecked( + b, + "`dec_int`, `one_of`, `exp`, and `frac` filter out non-ASCII", + ) + }) + .parse_next(input) +} + +// frac = decimal-point zero-prefixable-int +// decimal-point = %x2E ; . +pub(crate) fn frac(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + ( + b'.', + cut_err(zero_prefixable_int).context(Context::Expected(ParserValue::Description("digit"))), + ) + .recognize() + .map(|b: &[u8]| unsafe { + from_utf8_unchecked( + b, + "`.` and `parse_zero_prefixable_int` filter out non-ASCII", + ) + }) + .parse_next(input) +} + +// zero-prefixable-int = DIGIT *( DIGIT / underscore DIGIT ) +pub(crate) fn zero_prefixable_int(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + ( + digit, + repeat( + 0.., + alt(( + digit.value(()), + ( + one_of(b'_'), + cut_err(digit).context(Context::Expected(ParserValue::Description("digit"))), + ) + .value(()), + )), + ) + .map(|()| ()), + ) + .recognize() + .map(|b: &[u8]| unsafe { from_utf8_unchecked(b, "`digit` and `_` filter out non-ASCII") }) + .parse_next(input) +} + +// exp = "e" float-exp-part +// float-exp-part = [ minus / plus ] zero-prefixable-int +pub(crate) fn exp(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + ( + one_of((b'e', b'E')), + opt(one_of([b'+', b'-'])), + cut_err(zero_prefixable_int), + ) + .recognize() + .map(|b: &[u8]| unsafe { + from_utf8_unchecked( + b, + "`one_of` and `parse_zero_prefixable_int` filter out non-ASCII", + ) + }) + .parse_next(input) +} + +// special-float = [ minus / plus ] ( inf / nan ) +pub(crate) fn special_float(input: Input<'_>) -> IResult<Input<'_>, f64, ParserError<'_>> { + (opt(one_of((b'+', b'-'))), alt((inf, nan))) + .map(|(s, f)| match s { + Some(b'+') | None => f, + Some(b'-') => -f, + _ => unreachable!("one_of should prevent this"), + }) + .parse_next(input) +} +// inf = %x69.6e.66 ; inf +pub(crate) fn inf(input: Input<'_>) -> IResult<Input<'_>, f64, ParserError<'_>> { + tag(INF).value(f64::INFINITY).parse_next(input) +} +const INF: &[u8] = b"inf"; +// nan = %x6e.61.6e ; nan +pub(crate) fn nan(input: Input<'_>) -> IResult<Input<'_>, f64, ParserError<'_>> { + tag(NAN).value(f64::NAN).parse_next(input) +} +const NAN: &[u8] = b"nan"; + +// DIGIT = %x30-39 ; 0-9 +pub(crate) fn digit(input: Input<'_>) -> IResult<Input<'_>, u8, ParserError<'_>> { + one_of(DIGIT).parse_next(input) +} +const DIGIT: RangeInclusive<u8> = b'0'..=b'9'; + +// HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F" +pub(crate) fn hexdig(input: Input<'_>) -> IResult<Input<'_>, u8, ParserError<'_>> { + one_of(HEXDIG).parse_next(input) +} +pub(crate) const HEXDIG: (RangeInclusive<u8>, RangeInclusive<u8>, RangeInclusive<u8>) = + (DIGIT, b'A'..=b'F', b'a'..=b'f'); + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn integers() { + let cases = [ + ("+99", 99), + ("42", 42), + ("0", 0), + ("-17", -17), + ("1_000", 1_000), + ("5_349_221", 5_349_221), + ("1_2_3_4_5", 1_2_3_4_5), + ("0xF", 15), + ("0o0_755", 493), + ("0b1_0_1", 5), + (&std::i64::MIN.to_string()[..], std::i64::MIN), + (&std::i64::MAX.to_string()[..], std::i64::MAX), + ]; + for &(input, expected) in &cases { + dbg!(input); + let parsed = integer.parse(new_input(input)); + assert_eq!(parsed, Ok(expected), "Parsing {input:?}"); + } + + let overflow = "1000000000000000000000000000000000"; + let parsed = integer.parse(new_input(overflow)); + assert!(parsed.is_err()); + } + + #[track_caller] + fn assert_float_eq(actual: f64, expected: f64) { + if expected.is_nan() { + assert!(actual.is_nan()); + } else if expected.is_infinite() { + assert!(actual.is_infinite()); + assert_eq!(expected.is_sign_positive(), actual.is_sign_positive()); + } else { + dbg!(expected); + dbg!(actual); + assert!((expected - actual).abs() < std::f64::EPSILON); + } + } + + #[test] + fn floats() { + let cases = [ + ("+1.0", 1.0), + ("3.1419", 3.1419), + ("-0.01", -0.01), + ("5e+22", 5e+22), + ("1e6", 1e6), + ("-2E-2", -2E-2), + ("6.626e-34", 6.626e-34), + ("9_224_617.445_991_228_313", 9_224_617.445_991_227), + ("-1.7976931348623157e+308", std::f64::MIN), + ("1.7976931348623157e+308", std::f64::MAX), + ("nan", f64::NAN), + ("+nan", f64::NAN), + ("-nan", f64::NAN), + ("inf", f64::INFINITY), + ("+inf", f64::INFINITY), + ("-inf", f64::NEG_INFINITY), + // ("1e+400", std::f64::INFINITY), + ]; + for &(input, expected) in &cases { + dbg!(input); + let parsed = float.parse(new_input(input)).unwrap(); + assert_float_eq(parsed, expected); + + let overflow = "9e99999"; + let parsed = float.parse(new_input(overflow)); + assert!(parsed.is_err(), "{:?}", parsed); + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/parser/state.rs b/vendor/toml_edit-0.19.11/src/parser/state.rs new file mode 100644 index 000000000..efa884d2f --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/state.rs @@ -0,0 +1,323 @@ +use crate::key::Key; +use crate::parser::errors::CustomError; +use crate::repr::Decor; +use crate::table::TableKeyValue; +use crate::{ArrayOfTables, Document, InternalString, Item, RawString, Table}; + +pub(crate) struct ParseState { + document: Document, + trailing: Option<std::ops::Range<usize>>, + current_table_position: usize, + current_table: Table, + current_is_array: bool, + current_table_path: Vec<Key>, +} + +impl ParseState { + pub(crate) fn into_document(mut self) -> Result<Document, CustomError> { + self.finalize_table()?; + let trailing = self.trailing.map(RawString::with_span); + self.document.trailing = trailing.unwrap_or_default(); + Ok(self.document) + } + + pub(crate) fn on_ws(&mut self, span: std::ops::Range<usize>) { + if let Some(old) = self.trailing.take() { + self.trailing = Some(old.start..span.end); + } else { + self.trailing = Some(span); + } + } + + pub(crate) fn on_comment(&mut self, span: std::ops::Range<usize>) { + if let Some(old) = self.trailing.take() { + self.trailing = Some(old.start..span.end); + } else { + self.trailing = Some(span); + } + } + + pub(crate) fn on_keyval( + &mut self, + mut path: Vec<Key>, + mut kv: TableKeyValue, + ) -> Result<(), CustomError> { + { + let mut prefix = self.trailing.take(); + let first_key = if path.is_empty() { + &mut kv.key + } else { + &mut path[0] + }; + let prefix = match ( + prefix.take(), + first_key.decor.prefix().and_then(|d| d.span()), + ) { + (Some(p), Some(k)) => Some(p.start..k.end), + (Some(p), None) | (None, Some(p)) => Some(p), + (None, None) => None, + }; + first_key + .decor + .set_prefix(prefix.map(RawString::with_span).unwrap_or_default()); + } + + if let (Some(existing), Some(value)) = (self.current_table.span(), kv.value.span()) { + self.current_table.span = Some((existing.start)..(value.end)); + } + let table = &mut self.current_table; + let table = Self::descend_path(table, &path, true)?; + + // "Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed" + let mixed_table_types = table.is_dotted() == path.is_empty(); + if mixed_table_types { + return Err(CustomError::DuplicateKey { + key: kv.key.get().into(), + table: None, + }); + } + + let key: InternalString = kv.key.get_internal().into(); + match table.items.entry(key) { + indexmap::map::Entry::Vacant(o) => { + o.insert(kv); + } + indexmap::map::Entry::Occupied(o) => { + // "Since tables cannot be defined more than once, redefining such tables using a [table] header is not allowed" + return Err(CustomError::DuplicateKey { + key: o.key().as_str().into(), + table: Some(self.current_table_path.clone()), + }); + } + } + + Ok(()) + } + + pub(crate) fn start_aray_table( + &mut self, + path: Vec<Key>, + decor: Decor, + span: std::ops::Range<usize>, + ) -> Result<(), CustomError> { + debug_assert!(!path.is_empty()); + debug_assert!(self.current_table.is_empty()); + debug_assert!(self.current_table_path.is_empty()); + + // Look up the table on start to ensure the duplicate_key error points to the right line + let root = self.document.as_table_mut(); + let parent_table = Self::descend_path(root, &path[..path.len() - 1], false)?; + let key = &path[path.len() - 1]; + let entry = parent_table + .entry_format(key) + .or_insert(Item::ArrayOfTables(ArrayOfTables::new())); + entry + .as_array_of_tables() + .ok_or_else(|| CustomError::duplicate_key(&path, path.len() - 1))?; + + self.current_table_position += 1; + self.current_table.decor = decor; + self.current_table.set_implicit(false); + self.current_table.set_dotted(false); + self.current_table.set_position(self.current_table_position); + self.current_table.span = Some(span); + self.current_is_array = true; + self.current_table_path = path; + + Ok(()) + } + + pub(crate) fn start_table( + &mut self, + path: Vec<Key>, + decor: Decor, + span: std::ops::Range<usize>, + ) -> Result<(), CustomError> { + debug_assert!(!path.is_empty()); + debug_assert!(self.current_table.is_empty()); + debug_assert!(self.current_table_path.is_empty()); + + // 1. Look up the table on start to ensure the duplicate_key error points to the right line + // 2. Ensure any child tables from an implicit table are preserved + let root = self.document.as_table_mut(); + let parent_table = Self::descend_path(root, &path[..path.len() - 1], false)?; + let key = &path[path.len() - 1]; + if let Some(entry) = parent_table.remove(key.get()) { + match entry { + Item::Table(t) if t.implicit && !t.is_dotted() => { + self.current_table = t; + } + // Since tables cannot be defined more than once, redefining such tables using a [table] header is not allowed. Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed. + _ => return Err(CustomError::duplicate_key(&path, path.len() - 1)), + } + } + + self.current_table_position += 1; + self.current_table.decor = decor; + self.current_table.set_implicit(false); + self.current_table.set_dotted(false); + self.current_table.set_position(self.current_table_position); + self.current_table.span = Some(span); + self.current_is_array = false; + self.current_table_path = path; + + Ok(()) + } + + pub(crate) fn finalize_table(&mut self) -> Result<(), CustomError> { + let mut table = std::mem::take(&mut self.current_table); + let path = std::mem::take(&mut self.current_table_path); + + let root = self.document.as_table_mut(); + if path.is_empty() { + assert!(root.is_empty()); + std::mem::swap(&mut table, root); + } else if self.current_is_array { + let parent_table = Self::descend_path(root, &path[..path.len() - 1], false)?; + let key = &path[path.len() - 1]; + + let entry = parent_table + .entry_format(key) + .or_insert(Item::ArrayOfTables(ArrayOfTables::new())); + let array = entry + .as_array_of_tables_mut() + .ok_or_else(|| CustomError::duplicate_key(&path, path.len() - 1))?; + array.push(table); + let span = if let (Some(first), Some(last)) = ( + array.values.first().and_then(|t| t.span()), + array.values.last().and_then(|t| t.span()), + ) { + Some((first.start)..(last.end)) + } else { + None + }; + array.span = span; + } else { + let parent_table = Self::descend_path(root, &path[..path.len() - 1], false)?; + let key = &path[path.len() - 1]; + + let entry = parent_table.entry_format(key); + match entry { + crate::Entry::Occupied(entry) => { + match entry.into_mut() { + // if [a.b.c] header preceded [a.b] + Item::Table(ref mut t) if t.implicit => { + std::mem::swap(t, &mut table); + } + _ => return Err(CustomError::duplicate_key(&path, path.len() - 1)), + } + } + crate::Entry::Vacant(entry) => { + let item = Item::Table(table); + entry.insert(item); + } + } + } + + Ok(()) + } + + pub(crate) fn descend_path<'t, 'k>( + mut table: &'t mut Table, + path: &'k [Key], + dotted: bool, + ) -> Result<&'t mut Table, CustomError> { + for (i, key) in path.iter().enumerate() { + let entry = table.entry_format(key).or_insert_with(|| { + let mut new_table = Table::new(); + new_table.set_implicit(true); + new_table.set_dotted(dotted); + + Item::Table(new_table) + }); + match *entry { + Item::Value(ref v) => { + return Err(CustomError::extend_wrong_type(path, i, v.type_name())); + } + Item::ArrayOfTables(ref mut array) => { + debug_assert!(!array.is_empty()); + + let index = array.len() - 1; + let last_child = array.get_mut(index).unwrap(); + + table = last_child; + } + Item::Table(ref mut sweet_child_of_mine) => { + // Since tables cannot be defined more than once, redefining such tables using a + // [table] header is not allowed. Likewise, using dotted keys to redefine tables + // already defined in [table] form is not allowed. + if dotted && !sweet_child_of_mine.is_implicit() { + return Err(CustomError::DuplicateKey { + key: key.get().into(), + table: None, + }); + } + table = sweet_child_of_mine; + } + _ => unreachable!(), + } + } + Ok(table) + } + + pub(crate) fn on_std_header( + &mut self, + path: Vec<Key>, + trailing: std::ops::Range<usize>, + span: std::ops::Range<usize>, + ) -> Result<(), CustomError> { + debug_assert!(!path.is_empty()); + + self.finalize_table()?; + let leading = self + .trailing + .take() + .map(RawString::with_span) + .unwrap_or_default(); + self.start_table( + path, + Decor::new(leading, RawString::with_span(trailing)), + span, + )?; + + Ok(()) + } + + pub(crate) fn on_array_header( + &mut self, + path: Vec<Key>, + trailing: std::ops::Range<usize>, + span: std::ops::Range<usize>, + ) -> Result<(), CustomError> { + debug_assert!(!path.is_empty()); + + self.finalize_table()?; + let leading = self + .trailing + .take() + .map(RawString::with_span) + .unwrap_or_default(); + self.start_aray_table( + path, + Decor::new(leading, RawString::with_span(trailing)), + span, + )?; + + Ok(()) + } +} + +impl Default for ParseState { + fn default() -> Self { + let mut root = Table::new(); + root.span = Some(0..0); + Self { + document: Document::new(), + trailing: None, + current_table_position: 0, + current_table: root, + current_is_array: false, + current_table_path: Vec::new(), + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/parser/strings.rs b/vendor/toml_edit-0.19.11/src/parser/strings.rs new file mode 100644 index 000000000..2ce160506 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/strings.rs @@ -0,0 +1,464 @@ +use std::borrow::Cow; +use std::char; +use std::ops::RangeInclusive; + +use winnow::combinator::alt; +use winnow::combinator::cut_err; +use winnow::combinator::delimited; +use winnow::combinator::fail; +use winnow::combinator::opt; +use winnow::combinator::peek; +use winnow::combinator::preceded; +use winnow::combinator::repeat; +use winnow::combinator::success; +use winnow::combinator::terminated; +use winnow::prelude::*; +use winnow::token::any; +use winnow::token::none_of; +use winnow::token::one_of; +use winnow::token::tag; +use winnow::token::take_while; + +use crate::parser::errors::CustomError; +use crate::parser::numbers::HEXDIG; +use crate::parser::prelude::*; +use crate::parser::trivia::{from_utf8_unchecked, newline, ws, ws_newlines, NON_ASCII, WSCHAR}; + +// ;; String + +// string = ml-basic-string / basic-string / ml-literal-string / literal-string +pub(crate) fn string(input: Input<'_>) -> IResult<Input<'_>, Cow<'_, str>, ParserError<'_>> { + alt(( + ml_basic_string, + basic_string, + ml_literal_string, + literal_string.map(Cow::Borrowed), + )) + .parse_next(input) +} + +// ;; Basic String + +// basic-string = quotation-mark *basic-char quotation-mark +pub(crate) fn basic_string(input: Input<'_>) -> IResult<Input<'_>, Cow<'_, str>, ParserError<'_>> { + let (mut input, _) = one_of(QUOTATION_MARK).parse_next(input)?; + + let mut c = Cow::Borrowed(""); + if let Some((i, ci)) = ok_error(basic_chars.parse_next(input))? { + input = i; + c = ci; + } + while let Some((i, ci)) = ok_error(basic_chars.parse_next(input))? { + input = i; + c.to_mut().push_str(&ci); + } + + let (input, _) = cut_err(one_of(QUOTATION_MARK)) + .context(Context::Expression("basic string")) + .parse_next(input)?; + + Ok((input, c)) +} + +// quotation-mark = %x22 ; " +pub(crate) const QUOTATION_MARK: u8 = b'"'; + +// basic-char = basic-unescaped / escaped +fn basic_chars(input: Input<'_>) -> IResult<Input<'_>, Cow<'_, str>, ParserError<'_>> { + alt(( + // Deviate from the official grammar by batching the unescaped chars so we build a string a + // chunk at a time, rather than a `char` at a time. + take_while(1.., BASIC_UNESCAPED) + .try_map(std::str::from_utf8) + .map(Cow::Borrowed), + escaped.map(|c| Cow::Owned(String::from(c))), + )) + .parse_next(input) +} + +// basic-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii +pub(crate) const BASIC_UNESCAPED: ( + (u8, u8), + u8, + RangeInclusive<u8>, + RangeInclusive<u8>, + RangeInclusive<u8>, +) = (WSCHAR, 0x21, 0x23..=0x5B, 0x5D..=0x7E, NON_ASCII); + +// escaped = escape escape-seq-char +fn escaped(input: Input<'_>) -> IResult<Input<'_>, char, ParserError<'_>> { + preceded(ESCAPE, escape_seq_char).parse_next(input) +} + +// escape = %x5C ; \ +pub(crate) const ESCAPE: u8 = b'\\'; + +// escape-seq-char = %x22 ; " quotation mark U+0022 +// escape-seq-char =/ %x5C ; \ reverse solidus U+005C +// escape-seq-char =/ %x62 ; b backspace U+0008 +// escape-seq-char =/ %x66 ; f form feed U+000C +// escape-seq-char =/ %x6E ; n line feed U+000A +// escape-seq-char =/ %x72 ; r carriage return U+000D +// escape-seq-char =/ %x74 ; t tab U+0009 +// escape-seq-char =/ %x75 4HEXDIG ; uXXXX U+XXXX +// escape-seq-char =/ %x55 8HEXDIG ; UXXXXXXXX U+XXXXXXXX +fn escape_seq_char(input: Input<'_>) -> IResult<Input<'_>, char, ParserError<'_>> { + dispatch! {any; + b'b' => success('\u{8}'), + b'f' => success('\u{c}'), + b'n' => success('\n'), + b'r' => success('\r'), + b't' => success('\t'), + b'u' => cut_err(hexescape::<4>).context(Context::Expression("unicode 4-digit hex code")), + b'U' => cut_err(hexescape::<8>).context(Context::Expression("unicode 8-digit hex code")), + b'\\' => success('\\'), + b'"' => success('"'), + _ => { + cut_err(fail::<_, char, _>) + .context(Context::Expression("escape sequence")) + .context(Context::Expected(ParserValue::CharLiteral('b'))) + .context(Context::Expected(ParserValue::CharLiteral('f'))) + .context(Context::Expected(ParserValue::CharLiteral('n'))) + .context(Context::Expected(ParserValue::CharLiteral('r'))) + .context(Context::Expected(ParserValue::CharLiteral('t'))) + .context(Context::Expected(ParserValue::CharLiteral('u'))) + .context(Context::Expected(ParserValue::CharLiteral('U'))) + .context(Context::Expected(ParserValue::CharLiteral('\\'))) + .context(Context::Expected(ParserValue::CharLiteral('"'))) + } + } + .parse_next(input) +} + +pub(crate) fn hexescape<const N: usize>( + input: Input<'_>, +) -> IResult<Input<'_>, char, ParserError<'_>> { + take_while(0..=N, HEXDIG) + .verify(|b: &[u8]| b.len() == N) + .map(|b: &[u8]| unsafe { from_utf8_unchecked(b, "`is_ascii_digit` filters out on-ASCII") }) + .verify_map(|s| u32::from_str_radix(s, 16).ok()) + .try_map(|h| char::from_u32(h).ok_or(CustomError::OutOfRange)) + .parse_next(input) +} + +// ;; Multiline Basic String + +// ml-basic-string = ml-basic-string-delim [ newline ] ml-basic-body +// ml-basic-string-delim +fn ml_basic_string(input: Input<'_>) -> IResult<Input<'_>, Cow<'_, str>, ParserError<'_>> { + delimited( + ML_BASIC_STRING_DELIM, + preceded(opt(newline), cut_err(ml_basic_body)), + cut_err(ML_BASIC_STRING_DELIM), + ) + .context(Context::Expression("multiline basic string")) + .parse_next(input) +} + +// ml-basic-string-delim = 3quotation-mark +pub(crate) const ML_BASIC_STRING_DELIM: &[u8] = b"\"\"\""; + +// ml-basic-body = *mlb-content *( mlb-quotes 1*mlb-content ) [ mlb-quotes ] +fn ml_basic_body(mut input: Input<'_>) -> IResult<Input<'_>, Cow<'_, str>, ParserError<'_>> { + let mut c = Cow::Borrowed(""); + if let Some((i, ci)) = ok_error(mlb_content.parse_next(input))? { + input = i; + c = ci; + } + while let Some((i, ci)) = ok_error(mlb_content.parse_next(input))? { + input = i; + c.to_mut().push_str(&ci); + } + + while let Some((i, qi)) = ok_error(mlb_quotes(none_of(b'\"').value(())).parse_next(input))? { + if let Some((i, ci)) = ok_error(mlb_content.parse_next(i))? { + input = i; + c.to_mut().push_str(qi); + c.to_mut().push_str(&ci); + while let Some((i, ci)) = ok_error(mlb_content.parse_next(input))? { + input = i; + c.to_mut().push_str(&ci); + } + } else { + break; + } + } + + if let Some((i, qi)) = + ok_error(mlb_quotes(tag(ML_BASIC_STRING_DELIM).value(())).parse_next(input))? + { + input = i; + c.to_mut().push_str(qi); + } + + Ok((input, c)) +} + +// mlb-content = mlb-char / newline / mlb-escaped-nl +// mlb-char = mlb-unescaped / escaped +fn mlb_content(input: Input<'_>) -> IResult<Input<'_>, Cow<'_, str>, ParserError<'_>> { + alt(( + // Deviate from the official grammar by batching the unescaped chars so we build a string a + // chunk at a time, rather than a `char` at a time. + take_while(1.., MLB_UNESCAPED) + .try_map(std::str::from_utf8) + .map(Cow::Borrowed), + // Order changed fromg grammar so `escaped` can more easily `cut_err` on bad escape sequences + mlb_escaped_nl.map(|_| Cow::Borrowed("")), + escaped.map(|c| Cow::Owned(String::from(c))), + newline.map(|_| Cow::Borrowed("\n")), + )) + .parse_next(input) +} + +// mlb-quotes = 1*2quotation-mark +fn mlb_quotes<'i>( + mut term: impl winnow::Parser<Input<'i>, (), ParserError<'i>>, +) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, &str, ParserError<'i>> { + move |input| { + let res = terminated(b"\"\"", peek(term.by_ref())) + .map(|b| unsafe { from_utf8_unchecked(b, "`bytes` out non-ASCII") }) + .parse_next(input); + + match res { + Err(winnow::error::ErrMode::Backtrack(_)) => terminated(b"\"", peek(term.by_ref())) + .map(|b| unsafe { from_utf8_unchecked(b, "`bytes` out non-ASCII") }) + .parse_next(input), + res => res, + } + } +} + +// mlb-unescaped = wschar / %x21 / %x23-5B / %x5D-7E / non-ascii +pub(crate) const MLB_UNESCAPED: ( + (u8, u8), + u8, + RangeInclusive<u8>, + RangeInclusive<u8>, + RangeInclusive<u8>, +) = (WSCHAR, 0x21, 0x23..=0x5B, 0x5D..=0x7E, NON_ASCII); + +// mlb-escaped-nl = escape ws newline *( wschar / newline +// When the last non-whitespace character on a line is a \, +// it will be trimmed along with all whitespace +// (including newlines) up to the next non-whitespace +// character or closing delimiter. +fn mlb_escaped_nl(input: Input<'_>) -> IResult<Input<'_>, (), ParserError<'_>> { + repeat(1.., (ESCAPE, ws, ws_newlines)) + .map(|()| ()) + .value(()) + .parse_next(input) +} + +// ;; Literal String + +// literal-string = apostrophe *literal-char apostrophe +pub(crate) fn literal_string(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + delimited( + APOSTROPHE, + cut_err(take_while(0.., LITERAL_CHAR)), + cut_err(APOSTROPHE), + ) + .try_map(std::str::from_utf8) + .context(Context::Expression("literal string")) + .parse_next(input) +} + +// apostrophe = %x27 ; ' apostrophe +pub(crate) const APOSTROPHE: u8 = b'\''; + +// literal-char = %x09 / %x20-26 / %x28-7E / non-ascii +pub(crate) const LITERAL_CHAR: ( + u8, + RangeInclusive<u8>, + RangeInclusive<u8>, + RangeInclusive<u8>, +) = (0x9, 0x20..=0x26, 0x28..=0x7E, NON_ASCII); + +// ;; Multiline Literal String + +// ml-literal-string = ml-literal-string-delim [ newline ] ml-literal-body +// ml-literal-string-delim +fn ml_literal_string(input: Input<'_>) -> IResult<Input<'_>, Cow<'_, str>, ParserError<'_>> { + delimited( + (ML_LITERAL_STRING_DELIM, opt(newline)), + cut_err(ml_literal_body.map(|t| { + if t.contains("\r\n") { + Cow::Owned(t.replace("\r\n", "\n")) + } else { + Cow::Borrowed(t) + } + })), + cut_err(ML_LITERAL_STRING_DELIM), + ) + .context(Context::Expression("multiline literal string")) + .parse_next(input) +} + +// ml-literal-string-delim = 3apostrophe +pub(crate) const ML_LITERAL_STRING_DELIM: &[u8] = b"'''"; + +// ml-literal-body = *mll-content *( mll-quotes 1*mll-content ) [ mll-quotes ] +fn ml_literal_body(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + ( + repeat(0.., mll_content).map(|()| ()), + repeat( + 0.., + ( + mll_quotes(none_of(APOSTROPHE).value(())), + repeat(1.., mll_content).map(|()| ()), + ), + ) + .map(|()| ()), + opt(mll_quotes(tag(ML_LITERAL_STRING_DELIM).value(()))), + ) + .recognize() + .try_map(std::str::from_utf8) + .parse_next(input) +} + +// mll-content = mll-char / newline +fn mll_content(input: Input<'_>) -> IResult<Input<'_>, u8, ParserError<'_>> { + alt((one_of(MLL_CHAR), newline)).parse_next(input) +} + +// mll-char = %x09 / %x20-26 / %x28-7E / non-ascii +const MLL_CHAR: ( + u8, + RangeInclusive<u8>, + RangeInclusive<u8>, + RangeInclusive<u8>, +) = (0x9, 0x20..=0x26, 0x28..=0x7E, NON_ASCII); + +// mll-quotes = 1*2apostrophe +fn mll_quotes<'i>( + mut term: impl winnow::Parser<Input<'i>, (), ParserError<'i>>, +) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, &str, ParserError<'i>> { + move |input| { + let res = terminated(b"''", peek(term.by_ref())) + .map(|b| unsafe { from_utf8_unchecked(b, "`bytes` out non-ASCII") }) + .parse_next(input); + + match res { + Err(winnow::error::ErrMode::Backtrack(_)) => terminated(b"'", peek(term.by_ref())) + .map(|b| unsafe { from_utf8_unchecked(b, "`bytes` out non-ASCII") }) + .parse_next(input), + res => res, + } + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn basic_string() { + let input = + r#""I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF. \U0002070E""#; + let expected = "I\'m a string. \"You can quote me\". Name\tJosé\nLocation\tSF. \u{2070E}"; + let parsed = string.parse(new_input(input)); + assert_eq!(parsed.as_deref(), Ok(expected), "Parsing {input:?}"); + } + + #[test] + fn ml_basic_string() { + let cases = [ + ( + r#"""" +Roses are red +Violets are blue""""#, + r#"Roses are red +Violets are blue"#, + ), + (r#"""" \""" """"#, " \"\"\" "), + (r#"""" \\""""#, " \\"), + ]; + + for &(input, expected) in &cases { + let parsed = string.parse(new_input(input)); + assert_eq!(parsed.as_deref(), Ok(expected), "Parsing {input:?}"); + } + + let invalid_cases = [r#"""" """#, r#"""" \""""#]; + + for input in &invalid_cases { + let parsed = string.parse(new_input(input)); + assert!(parsed.is_err()); + } + } + + #[test] + fn ml_basic_string_escape_ws() { + let inputs = [ + r#"""" +The quick brown \ + + + fox jumps over \ + the lazy dog.""""#, + r#""""\ + The quick brown \ + fox jumps over \ + the lazy dog.\ + """"#, + ]; + for input in &inputs { + let expected = "The quick brown fox jumps over the lazy dog."; + let parsed = string.parse(new_input(input)); + assert_eq!(parsed.as_deref(), Ok(expected), "Parsing {input:?}"); + } + let empties = [ + r#""""\ + """"#, + r#"""" +\ + \ +""""#, + ]; + for input in &empties { + let expected = ""; + let parsed = string.parse(new_input(input)); + assert_eq!(parsed.as_deref(), Ok(expected), "Parsing {input:?}"); + } + } + + #[test] + fn literal_string() { + let inputs = [ + r#"'C:\Users\nodejs\templates'"#, + r#"'\\ServerX\admin$\system32\'"#, + r#"'Tom "Dubs" Preston-Werner'"#, + r#"'<\i\c*\s*>'"#, + ]; + + for input in &inputs { + let expected = &input[1..input.len() - 1]; + let parsed = string.parse(new_input(input)); + assert_eq!(parsed.as_deref(), Ok(expected), "Parsing {input:?}"); + } + } + + #[test] + fn ml_literal_string() { + let inputs = [ + r#"'''I [dw]on't need \d{2} apples'''"#, + r#"''''one_quote''''"#, + ]; + for input in &inputs { + let expected = &input[3..input.len() - 3]; + let parsed = string.parse(new_input(input)); + assert_eq!(parsed.as_deref(), Ok(expected), "Parsing {input:?}"); + } + + let input = r#"''' +The first newline is +trimmed in raw strings. + All other whitespace + is preserved. +'''"#; + let expected = &input[4..input.len() - 3]; + let parsed = string.parse(new_input(input)); + assert_eq!(parsed.as_deref(), Ok(expected), "Parsing {input:?}"); + } +} diff --git a/vendor/toml_edit-0.19.11/src/parser/table.rs b/vendor/toml_edit-0.19.11/src/parser/table.rs new file mode 100644 index 000000000..9d2675868 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/table.rs @@ -0,0 +1,89 @@ +use std::cell::RefCell; +#[allow(unused_imports)] +use std::ops::DerefMut; + +use winnow::combinator::cut_err; +use winnow::combinator::delimited; +use winnow::combinator::peek; +use winnow::token::take; + +// https://github.com/rust-lang/rust/issues/41358 +use crate::parser::key::key; +use crate::parser::prelude::*; +use crate::parser::state::ParseState; +use crate::parser::trivia::line_trailing; + +// std-table-open = %x5B ws ; [ Left square bracket +pub(crate) const STD_TABLE_OPEN: u8 = b'['; +// std-table-close = ws %x5D ; ] Right square bracket +const STD_TABLE_CLOSE: u8 = b']'; +// array-table-open = %x5B.5B ws ; [[ Double left square bracket +const ARRAY_TABLE_OPEN: &[u8] = b"[["; +// array-table-close = ws %x5D.5D ; ]] Double right quare bracket +const ARRAY_TABLE_CLOSE: &[u8] = b"]]"; + +// ;; Standard Table + +// std-table = std-table-open key *( table-key-sep key) std-table-close +pub(crate) fn std_table<'s, 'i>( + state: &'s RefCell<ParseState>, +) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'i>> + 's { + move |i| { + ( + delimited( + STD_TABLE_OPEN, + cut_err(key), + cut_err(STD_TABLE_CLOSE) + .context(Context::Expected(ParserValue::CharLiteral('.'))) + .context(Context::Expected(ParserValue::StringLiteral("]"))), + ) + .with_span(), + cut_err(line_trailing) + .context(Context::Expected(ParserValue::CharLiteral('\n'))) + .context(Context::Expected(ParserValue::CharLiteral('#'))), + ) + .try_map(|((h, span), t)| state.borrow_mut().deref_mut().on_std_header(h, t, span)) + .parse_next(i) + } +} + +// ;; Array Table + +// array-table = array-table-open key *( table-key-sep key) array-table-close +pub(crate) fn array_table<'s, 'i>( + state: &'s RefCell<ParseState>, +) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'i>> + 's { + move |i| { + ( + delimited( + ARRAY_TABLE_OPEN, + cut_err(key), + cut_err(ARRAY_TABLE_CLOSE) + .context(Context::Expected(ParserValue::CharLiteral('.'))) + .context(Context::Expected(ParserValue::StringLiteral("]]"))), + ) + .with_span(), + cut_err(line_trailing) + .context(Context::Expected(ParserValue::CharLiteral('\n'))) + .context(Context::Expected(ParserValue::CharLiteral('#'))), + ) + .try_map(|((h, span), t)| state.borrow_mut().deref_mut().on_array_header(h, t, span)) + .parse_next(i) + } +} + +// ;; Table + +// table = std-table / array-table +pub(crate) fn table<'s, 'i>( + state: &'s RefCell<ParseState>, +) -> impl FnMut(Input<'i>) -> IResult<Input<'i>, (), ParserError<'i>> + 's { + move |i| { + dispatch!(peek::<_, &[u8],_,_>(take(2usize)); + b"[[" => array_table(state), + _ => std_table(state), + ) + .context(Context::Expression("table header")) + .parse_next(i) + } +} diff --git a/vendor/toml_edit-0.19.11/src/parser/trivia.rs b/vendor/toml_edit-0.19.11/src/parser/trivia.rs new file mode 100644 index 000000000..ba47dcde6 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/trivia.rs @@ -0,0 +1,158 @@ +use std::ops::RangeInclusive; + +use winnow::combinator::alt; +use winnow::combinator::eof; +use winnow::combinator::opt; +use winnow::combinator::repeat; +use winnow::combinator::terminated; +use winnow::prelude::*; +use winnow::token::one_of; +use winnow::token::take_while; + +use crate::parser::prelude::*; + +pub(crate) unsafe fn from_utf8_unchecked<'b>( + bytes: &'b [u8], + safety_justification: &'static str, +) -> &'b str { + if cfg!(debug_assertions) { + // Catch problems more quickly when testing + std::str::from_utf8(bytes).expect(safety_justification) + } else { + std::str::from_utf8_unchecked(bytes) + } +} + +// wschar = ( %x20 / ; Space +// %x09 ) ; Horizontal tab +pub(crate) const WSCHAR: (u8, u8) = (b' ', b'\t'); + +// ws = *wschar +pub(crate) fn ws(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + take_while(0.., WSCHAR) + .map(|b| unsafe { from_utf8_unchecked(b, "`is_wschar` filters out on-ASCII") }) + .parse_next(input) +} + +// non-ascii = %x80-D7FF / %xE000-10FFFF +// - ASCII is 0xxxxxxx +// - First byte for UTF-8 is 11xxxxxx +// - Subsequent UTF-8 bytes are 10xxxxxx +pub(crate) const NON_ASCII: RangeInclusive<u8> = 0x80..=0xff; + +// non-eol = %x09 / %x20-7E / non-ascii +pub(crate) const NON_EOL: (u8, RangeInclusive<u8>, RangeInclusive<u8>) = + (0x09, 0x20..=0x7E, NON_ASCII); + +// comment-start-symbol = %x23 ; # +pub(crate) const COMMENT_START_SYMBOL: u8 = b'#'; + +// comment = comment-start-symbol *non-eol +pub(crate) fn comment(input: Input<'_>) -> IResult<Input<'_>, &[u8], ParserError<'_>> { + (COMMENT_START_SYMBOL, take_while(0.., NON_EOL)) + .recognize() + .parse_next(input) +} + +// newline = ( %x0A / ; LF +// %x0D.0A ) ; CRLF +pub(crate) fn newline(input: Input<'_>) -> IResult<Input<'_>, u8, ParserError<'_>> { + alt(( + one_of(LF).value(b'\n'), + (one_of(CR), one_of(LF)).value(b'\n'), + )) + .parse_next(input) +} +pub(crate) const LF: u8 = b'\n'; +pub(crate) const CR: u8 = b'\r'; + +// ws-newline = *( wschar / newline ) +pub(crate) fn ws_newline(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + repeat( + 0.., + alt((newline.value(&b"\n"[..]), take_while(1.., WSCHAR))), + ) + .map(|()| ()) + .recognize() + .map(|b| unsafe { from_utf8_unchecked(b, "`is_wschar` and `newline` filters out on-ASCII") }) + .parse_next(input) +} + +// ws-newlines = newline *( wschar / newline ) +pub(crate) fn ws_newlines(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + (newline, ws_newline) + .recognize() + .map(|b| unsafe { + from_utf8_unchecked(b, "`is_wschar` and `newline` filters out on-ASCII") + }) + .parse_next(input) +} + +// note: this rule is not present in the original grammar +// ws-comment-newline = *( ws-newline-nonempty / comment ) +pub(crate) fn ws_comment_newline(input: Input<'_>) -> IResult<Input<'_>, &[u8], ParserError<'_>> { + repeat( + 0.., + alt(( + repeat( + 1.., + alt((take_while(1.., WSCHAR), newline.value(&b"\n"[..]))), + ) + .map(|()| ()), + comment.value(()), + )), + ) + .map(|()| ()) + .recognize() + .parse_next(input) +} + +// note: this rule is not present in the original grammar +// line-ending = newline / eof +pub(crate) fn line_ending(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> { + alt((newline.value("\n"), eof.value(""))).parse_next(input) +} + +// note: this rule is not present in the original grammar +// line-trailing = ws [comment] skip-line-ending +pub(crate) fn line_trailing( + input: Input<'_>, +) -> IResult<Input<'_>, std::ops::Range<usize>, ParserError<'_>> { + terminated((ws, opt(comment)).span(), line_ending).parse_next(input) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn trivia() { + let inputs = [ + "", + r#" "#, + r#" +"#, + r#" +# comment + +# comment2 + + +"#, + r#" + "#, + r#"# comment +# comment2 + + + "#, + ]; + for input in inputs { + dbg!(input); + let parsed = ws_comment_newline.parse(new_input(input)); + assert!(parsed.is_ok(), "{:?}", parsed); + let parsed = parsed.unwrap(); + assert_eq!(parsed, input.as_bytes()); + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/parser/value.rs b/vendor/toml_edit-0.19.11/src/parser/value.rs new file mode 100644 index 000000000..19950585b --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/parser/value.rs @@ -0,0 +1,157 @@ +use winnow::branch::alt; +use winnow::bytes::any; +use winnow::combinator::fail; +use winnow::combinator::peek; + +use crate::parser::array::array; +use crate::parser::datetime::date_time; +use crate::parser::inline_table::inline_table; +use crate::parser::numbers::{float, integer}; +use crate::parser::prelude::*; +use crate::parser::strings::string; +use crate::repr::{Formatted, Repr}; +use crate::value as v; +use crate::RawString; +use crate::Value; + +// val = string / boolean / array / inline-table / date-time / float / integer +pub(crate) fn value( + check: RecursionCheck, +) -> impl FnMut(Input<'_>) -> IResult<Input<'_>, v::Value, ParserError<'_>> { + move |input| { + dispatch!{peek(any); + crate::parser::strings::QUOTATION_MARK | + crate::parser::strings::APOSTROPHE => string.map(|s| { + v::Value::String(Formatted::new( + s.into_owned() + )) + }), + crate::parser::array::ARRAY_OPEN => array(check).map(v::Value::Array), + crate::parser::inline_table::INLINE_TABLE_OPEN => inline_table(check).map(v::Value::InlineTable), + // Date/number starts + b'+' | b'-' | b'0'..=b'9' => { + // Uncommon enough not to be worth optimizing at this time + alt(( + date_time + .map(v::Value::from), + float + .map(v::Value::from), + integer + .map(v::Value::from), + )) + }, + // Report as if they were numbers because its most likely a typo + b'_' => { + integer + .map(v::Value::from) + .context(Context::Expected(ParserValue::Description("leading digit"))) + }, + // Report as if they were numbers because its most likely a typo + b'.' => { + float + .map(v::Value::from) + .context(Context::Expected(ParserValue::Description("leading digit"))) + }, + b't' => { + crate::parser::numbers::true_.map(v::Value::from) + .context(Context::Expression("string")) + .context(Context::Expected(ParserValue::CharLiteral('"'))) + .context(Context::Expected(ParserValue::CharLiteral('\''))) + }, + b'f' => { + crate::parser::numbers::false_.map(v::Value::from) + .context(Context::Expression("string")) + .context(Context::Expected(ParserValue::CharLiteral('"'))) + .context(Context::Expected(ParserValue::CharLiteral('\''))) + }, + b'i' => { + crate::parser::numbers::inf.map(v::Value::from) + .context(Context::Expression("string")) + .context(Context::Expected(ParserValue::CharLiteral('"'))) + .context(Context::Expected(ParserValue::CharLiteral('\''))) + }, + b'n' => { + crate::parser::numbers::nan.map(v::Value::from) + .context(Context::Expression("string")) + .context(Context::Expected(ParserValue::CharLiteral('"'))) + .context(Context::Expected(ParserValue::CharLiteral('\''))) + }, + _ => { + fail + .context(Context::Expression("string")) + .context(Context::Expected(ParserValue::CharLiteral('"'))) + .context(Context::Expected(ParserValue::CharLiteral('\''))) + }, + } + .with_span() + .try_map(|(value, span)| apply_raw(value, span)) + .parse_next(input) + } +} + +fn apply_raw(mut val: Value, span: std::ops::Range<usize>) -> Result<Value, std::str::Utf8Error> { + match val { + Value::String(ref mut f) => { + let raw = RawString::with_span(span); + f.set_repr_unchecked(Repr::new_unchecked(raw)); + } + Value::Integer(ref mut f) => { + let raw = RawString::with_span(span); + f.set_repr_unchecked(Repr::new_unchecked(raw)); + } + Value::Float(ref mut f) => { + let raw = RawString::with_span(span); + f.set_repr_unchecked(Repr::new_unchecked(raw)); + } + Value::Boolean(ref mut f) => { + let raw = RawString::with_span(span); + f.set_repr_unchecked(Repr::new_unchecked(raw)); + } + Value::Datetime(ref mut f) => { + let raw = RawString::with_span(span); + f.set_repr_unchecked(Repr::new_unchecked(raw)); + } + Value::Array(ref mut arr) => { + arr.span = Some(span); + } + Value::InlineTable(ref mut table) => { + table.span = Some(span); + } + }; + val.decorate("", ""); + Ok(val) +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn values() { + let inputs = [ + "1979-05-27T00:32:00.999999", + "-239", + "1e200", + "9_224_617.445_991_228_313", + r#"'''I [dw]on't need \d{2} apples'''"#, + r#"''' +The first newline is +trimmed in raw strings. + All other whitespace + is preserved. +'''"#, + r#""Jos\u00E9\n""#, + r#""\\\"\b/\f\n\r\t\u00E9\U000A0000""#, + r#"{ hello = "world", a = 1}"#, + r#"[ { x = 1, a = "2" }, {a = "a",b = "b", c = "c"} ]"#, + ]; + for input in inputs { + dbg!(input); + let mut parsed = value(Default::default()).parse(new_input(input)); + if let Ok(parsed) = &mut parsed { + parsed.despan(input); + } + assert_eq!(parsed.map(|a| a.to_string()), Ok(input.to_owned())); + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/raw_string.rs b/vendor/toml_edit-0.19.11/src/raw_string.rs new file mode 100644 index 000000000..c5961f133 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/raw_string.rs @@ -0,0 +1,182 @@ +use crate::InternalString; + +/// Opaque string storage for raw TOML; internal to `toml_edit` +#[derive(PartialEq, Eq, Clone, Hash)] +pub struct RawString(RawStringInner); + +#[derive(PartialEq, Eq, Clone, Hash)] +enum RawStringInner { + Empty, + Explicit(InternalString), + Spanned(std::ops::Range<usize>), +} + +impl RawString { + pub(crate) fn with_span(span: std::ops::Range<usize>) -> Self { + if span.start == span.end { + RawString(RawStringInner::Empty) + } else { + RawString(RawStringInner::Spanned(span)) + } + } + + /// Access the underlying string + pub fn as_str(&self) -> Option<&str> { + match &self.0 { + RawStringInner::Empty => Some(""), + RawStringInner::Explicit(s) => Some(s.as_str()), + RawStringInner::Spanned(_) => None, + } + } + + pub(crate) fn to_str<'s>(&'s self, input: &'s str) -> &'s str { + match &self.0 { + RawStringInner::Empty => "", + RawStringInner::Explicit(s) => s.as_str(), + RawStringInner::Spanned(span) => input.get(span.clone()).unwrap_or_else(|| { + panic!("span {:?} should be in input:\n```\n{}\n```", span, input) + }), + } + } + + pub(crate) fn to_str_with_default<'s>( + &'s self, + input: Option<&'s str>, + default: &'s str, + ) -> &'s str { + match &self.0 { + RawStringInner::Empty => "", + RawStringInner::Explicit(s) => s.as_str(), + RawStringInner::Spanned(span) => { + if let Some(input) = input { + input.get(span.clone()).unwrap_or_else(|| { + panic!("span {:?} should be in input:\n```\n{}\n```", span, input) + }) + } else { + default + } + } + } + } + + /// Access the underlying span + pub(crate) fn span(&self) -> Option<std::ops::Range<usize>> { + match &self.0 { + RawStringInner::Empty => None, + RawStringInner::Explicit(_) => None, + RawStringInner::Spanned(span) => Some(span.clone()), + } + } + + pub(crate) fn despan(&mut self, input: &str) { + match &self.0 { + RawStringInner::Empty => {} + RawStringInner::Explicit(_) => {} + RawStringInner::Spanned(span) => { + *self = Self::from(input.get(span.clone()).unwrap_or_else(|| { + panic!("span {:?} should be in input:\n```\n{}\n```", span, input) + })) + } + } + } + + pub(crate) fn encode(&self, buf: &mut dyn std::fmt::Write, input: &str) -> std::fmt::Result { + let raw = self.to_str(input); + for part in raw.split('\r') { + write!(buf, "{}", part)?; + } + Ok(()) + } + + pub(crate) fn encode_with_default( + &self, + buf: &mut dyn std::fmt::Write, + input: Option<&str>, + default: &str, + ) -> std::fmt::Result { + let raw = self.to_str_with_default(input, default); + for part in raw.split('\r') { + write!(buf, "{}", part)?; + } + Ok(()) + } +} + +impl Default for RawString { + fn default() -> Self { + Self(RawStringInner::Empty) + } +} + +impl std::fmt::Debug for RawString { + #[inline] + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + match &self.0 { + RawStringInner::Empty => write!(formatter, "empty"), + RawStringInner::Explicit(s) => write!(formatter, "{:?}", s), + RawStringInner::Spanned(s) => write!(formatter, "{:?}", s), + } + } +} + +impl From<&str> for RawString { + #[inline] + fn from(s: &str) -> Self { + if s.is_empty() { + Self(RawStringInner::Empty) + } else { + InternalString::from(s).into() + } + } +} + +impl From<String> for RawString { + #[inline] + fn from(s: String) -> Self { + if s.is_empty() { + Self(RawStringInner::Empty) + } else { + InternalString::from(s).into() + } + } +} + +impl From<&String> for RawString { + #[inline] + fn from(s: &String) -> Self { + if s.is_empty() { + Self(RawStringInner::Empty) + } else { + InternalString::from(s).into() + } + } +} + +impl From<InternalString> for RawString { + #[inline] + fn from(inner: InternalString) -> Self { + Self(RawStringInner::Explicit(inner)) + } +} + +impl From<&InternalString> for RawString { + #[inline] + fn from(s: &InternalString) -> Self { + if s.is_empty() { + Self(RawStringInner::Empty) + } else { + InternalString::from(s).into() + } + } +} + +impl From<Box<str>> for RawString { + #[inline] + fn from(s: Box<str>) -> Self { + if s.is_empty() { + Self(RawStringInner::Empty) + } else { + InternalString::from(s).into() + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/repr.rs b/vendor/toml_edit-0.19.11/src/repr.rs new file mode 100644 index 000000000..d4ab6c231 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/repr.rs @@ -0,0 +1,253 @@ +use std::borrow::Cow; + +use crate::RawString; + +/// A value together with its `to_string` representation, +/// including surrounding it whitespaces and comments. +#[derive(Eq, PartialEq, Clone, Hash)] +pub struct Formatted<T> { + value: T, + repr: Option<Repr>, + decor: Decor, +} + +impl<T> Formatted<T> +where + T: ValueRepr, +{ + /// Default-formatted value + pub fn new(value: T) -> Self { + Self { + value, + repr: None, + decor: Default::default(), + } + } + + pub(crate) fn set_repr_unchecked(&mut self, repr: Repr) { + self.repr = Some(repr); + } + + /// The wrapped value + pub fn value(&self) -> &T { + &self.value + } + + /// The wrapped value + pub fn into_value(self) -> T { + self.value + } + + /// Returns the raw representation, if available. + pub fn as_repr(&self) -> Option<&Repr> { + self.repr.as_ref() + } + + /// Returns the default raw representation. + pub fn default_repr(&self) -> Repr { + self.value.to_repr() + } + + /// Returns a raw representation. + pub fn display_repr(&self) -> Cow<str> { + self.as_repr() + .and_then(|r| r.as_raw().as_str()) + .map(Cow::Borrowed) + .unwrap_or_else(|| { + Cow::Owned(self.default_repr().as_raw().as_str().unwrap().to_owned()) + }) + } + + /// Returns the location within the original document + pub(crate) fn span(&self) -> Option<std::ops::Range<usize>> { + self.repr.as_ref().and_then(|r| r.span()) + } + + pub(crate) fn despan(&mut self, input: &str) { + self.decor.despan(input); + if let Some(repr) = &mut self.repr { + repr.despan(input); + } + } + + /// Returns the surrounding whitespace + pub fn decor_mut(&mut self) -> &mut Decor { + &mut self.decor + } + + /// Returns the surrounding whitespace + pub fn decor(&self) -> &Decor { + &self.decor + } + + /// Auto formats the value. + pub fn fmt(&mut self) { + self.repr = Some(self.value.to_repr()); + } +} + +impl<T> std::fmt::Debug for Formatted<T> +where + T: std::fmt::Debug, +{ + #[inline] + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + let mut d = formatter.debug_struct("Formatted"); + d.field("value", &self.value); + match &self.repr { + Some(r) => d.field("repr", r), + None => d.field("repr", &"default"), + }; + d.field("decor", &self.decor); + d.finish() + } +} + +impl<T> std::fmt::Display for Formatted<T> +where + T: ValueRepr, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + crate::encode::Encode::encode(self, f, None, ("", "")) + } +} + +pub trait ValueRepr: crate::private::Sealed { + /// The TOML representation of the value + fn to_repr(&self) -> Repr; +} + +/// TOML-encoded value +#[derive(Eq, PartialEq, Clone, Hash)] +pub struct Repr { + raw_value: RawString, +} + +impl Repr { + pub(crate) fn new_unchecked(raw: impl Into<RawString>) -> Self { + Repr { + raw_value: raw.into(), + } + } + + /// Access the underlying value + pub fn as_raw(&self) -> &RawString { + &self.raw_value + } + + /// Returns the location within the original document + pub(crate) fn span(&self) -> Option<std::ops::Range<usize>> { + self.raw_value.span() + } + + pub(crate) fn despan(&mut self, input: &str) { + self.raw_value.despan(input) + } + + pub(crate) fn encode(&self, buf: &mut dyn std::fmt::Write, input: &str) -> std::fmt::Result { + self.as_raw().encode(buf, input) + } +} + +impl std::fmt::Debug for Repr { + #[inline] + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + self.raw_value.fmt(formatter) + } +} + +/// A prefix and suffix, +/// +/// Including comments, whitespaces and newlines. +#[derive(Eq, PartialEq, Clone, Default, Hash)] +pub struct Decor { + prefix: Option<RawString>, + suffix: Option<RawString>, +} + +impl Decor { + /// Creates a new decor from the given prefix and suffix. + pub fn new(prefix: impl Into<RawString>, suffix: impl Into<RawString>) -> Self { + Self { + prefix: Some(prefix.into()), + suffix: Some(suffix.into()), + } + } + + /// Go back to default decor + pub fn clear(&mut self) { + self.prefix = None; + self.suffix = None; + } + + /// Get the prefix. + pub fn prefix(&self) -> Option<&RawString> { + self.prefix.as_ref() + } + + pub(crate) fn prefix_encode( + &self, + buf: &mut dyn std::fmt::Write, + input: Option<&str>, + default: &str, + ) -> std::fmt::Result { + if let Some(prefix) = self.prefix() { + prefix.encode_with_default(buf, input, default) + } else { + write!(buf, "{}", default) + } + } + + /// Set the prefix. + pub fn set_prefix(&mut self, prefix: impl Into<RawString>) { + self.prefix = Some(prefix.into()); + } + + /// Get the suffix. + pub fn suffix(&self) -> Option<&RawString> { + self.suffix.as_ref() + } + + pub(crate) fn suffix_encode( + &self, + buf: &mut dyn std::fmt::Write, + input: Option<&str>, + default: &str, + ) -> std::fmt::Result { + if let Some(suffix) = self.suffix() { + suffix.encode_with_default(buf, input, default) + } else { + write!(buf, "{}", default) + } + } + + /// Set the suffix. + pub fn set_suffix(&mut self, suffix: impl Into<RawString>) { + self.suffix = Some(suffix.into()); + } + + pub(crate) fn despan(&mut self, input: &str) { + if let Some(prefix) = &mut self.prefix { + prefix.despan(input); + } + if let Some(suffix) = &mut self.suffix { + suffix.despan(input); + } + } +} + +impl std::fmt::Debug for Decor { + #[inline] + fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { + let mut d = formatter.debug_struct("Decor"); + match &self.prefix { + Some(r) => d.field("prefix", r), + None => d.field("prefix", &"default"), + }; + match &self.suffix { + Some(r) => d.field("suffix", r), + None => d.field("suffix", &"default"), + }; + d.finish() + } +} diff --git a/vendor/toml_edit-0.19.11/src/ser/array.rs b/vendor/toml_edit-0.19.11/src/ser/array.rs new file mode 100644 index 000000000..80eba8ba7 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/ser/array.rs @@ -0,0 +1,84 @@ +use super::Error; + +#[doc(hidden)] +pub struct SerializeValueArray { + values: Vec<crate::Item>, +} + +impl SerializeValueArray { + pub(crate) fn new() -> Self { + Self { values: Vec::new() } + } + + pub(crate) fn with_capacity(len: usize) -> Self { + Self { + values: Vec::with_capacity(len), + } + } +} + +impl serde::ser::SerializeSeq for SerializeValueArray { + type Ok = crate::Value; + type Error = Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: serde::ser::Serialize, + { + let value = value.serialize(super::ValueSerializer {})?; + self.values.push(crate::Item::Value(value)); + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(crate::Value::Array(crate::Array::with_vec(self.values))) + } +} + +impl serde::ser::SerializeTuple for SerializeValueArray { + type Ok = crate::Value; + type Error = Error; + + fn serialize_element<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: serde::ser::Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + serde::ser::SerializeSeq::end(self) + } +} + +impl serde::ser::SerializeTupleVariant for SerializeValueArray { + type Ok = crate::Value; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: serde::ser::Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + serde::ser::SerializeSeq::end(self) + } +} + +impl serde::ser::SerializeTupleStruct for SerializeValueArray { + type Ok = crate::Value; + type Error = Error; + + fn serialize_field<T: ?Sized>(&mut self, value: &T) -> Result<(), Error> + where + T: serde::ser::Serialize, + { + serde::ser::SerializeSeq::serialize_element(self, value) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + serde::ser::SerializeSeq::end(self) + } +} diff --git a/vendor/toml_edit-0.19.11/src/ser/key.rs b/vendor/toml_edit-0.19.11/src/ser/key.rs new file mode 100644 index 000000000..d5e381bf7 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/ser/key.rs @@ -0,0 +1,173 @@ +use crate::InternalString; + +use super::Error; + +pub(crate) struct KeySerializer; + +impl serde::ser::Serializer for KeySerializer { + type Ok = InternalString; + type Error = Error; + type SerializeSeq = serde::ser::Impossible<InternalString, Error>; + type SerializeTuple = serde::ser::Impossible<InternalString, Error>; + type SerializeTupleStruct = serde::ser::Impossible<InternalString, Error>; + type SerializeTupleVariant = serde::ser::Impossible<InternalString, Error>; + type SerializeMap = serde::ser::Impossible<InternalString, Error>; + type SerializeStruct = serde::ser::Impossible<InternalString, Error>; + type SerializeStructVariant = serde::ser::Impossible<InternalString, Error>; + + fn serialize_bool(self, _v: bool) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_i8(self, _v: i8) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_i16(self, _v: i16) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_i32(self, _v: i32) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_i64(self, _v: i64) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_u8(self, _v: u8) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_u16(self, _v: u16) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_u32(self, _v: u32) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_u64(self, _v: u64) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_f32(self, _v: f32) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_f64(self, _v: f64) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_char(self, _v: char) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_str(self, value: &str) -> Result<InternalString, Self::Error> { + Ok(InternalString::from(value)) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_none(self) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<InternalString, Self::Error> + where + T: serde::ser::Serialize, + { + Err(Error::KeyNotString) + } + + fn serialize_unit(self) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<InternalString, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result<InternalString, Self::Error> { + Ok(variant.into()) + } + + fn serialize_newtype_struct<T: ?Sized>( + self, + _name: &'static str, + value: &T, + ) -> Result<InternalString, Self::Error> + where + T: serde::ser::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<InternalString, Self::Error> + where + T: serde::ser::Serialize, + { + Err(Error::KeyNotString) + } + + fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleStruct, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeStruct, Self::Error> { + Err(Error::KeyNotString) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error> { + Err(Error::KeyNotString) + } +} diff --git a/vendor/toml_edit-0.19.11/src/ser/map.rs b/vendor/toml_edit-0.19.11/src/ser/map.rs new file mode 100644 index 000000000..d743e3d5d --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/ser/map.rs @@ -0,0 +1,405 @@ +use super::{Error, KeySerializer}; + +#[doc(hidden)] +pub enum SerializeMap { + Datetime(SerializeDatetime), + Table(SerializeInlineTable), +} + +impl SerializeMap { + pub(crate) fn table() -> Self { + Self::Table(SerializeInlineTable::new()) + } + + pub(crate) fn table_with_capacity(len: usize) -> Self { + Self::Table(SerializeInlineTable::with_capacity(len)) + } + + pub(crate) fn datetime() -> Self { + Self::Datetime(SerializeDatetime::new()) + } +} + +impl serde::ser::SerializeMap for SerializeMap { + type Ok = crate::Value; + type Error = Error; + + fn serialize_key<T: ?Sized>(&mut self, input: &T) -> Result<(), Self::Error> + where + T: serde::ser::Serialize, + { + match self { + Self::Datetime(s) => s.serialize_key(input), + Self::Table(s) => s.serialize_key(input), + } + } + + fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error> + where + T: serde::ser::Serialize, + { + match self { + Self::Datetime(s) => s.serialize_value(value), + Self::Table(s) => s.serialize_value(value), + } + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + match self { + Self::Datetime(s) => s.end().map(|items| items.into()), + Self::Table(s) => s.end().map(|items| items.into()), + } + } +} + +impl serde::ser::SerializeStruct for SerializeMap { + type Ok = crate::Value; + type Error = Error; + + fn serialize_field<T: ?Sized>( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), Self::Error> + where + T: serde::ser::Serialize, + { + match self { + Self::Datetime(s) => s.serialize_field(key, value), + Self::Table(s) => s.serialize_field(key, value), + } + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + match self { + Self::Datetime(s) => s.end().map(|items| items.into()), + Self::Table(s) => s.end().map(|items| items.into()), + } + } +} + +#[doc(hidden)] +pub struct SerializeDatetime { + value: Option<crate::Datetime>, +} + +impl SerializeDatetime { + pub(crate) fn new() -> Self { + Self { value: None } + } +} + +impl serde::ser::SerializeMap for SerializeDatetime { + type Ok = crate::Datetime; + type Error = Error; + + fn serialize_key<T: ?Sized>(&mut self, _input: &T) -> Result<(), Self::Error> + where + T: serde::ser::Serialize, + { + unreachable!("datetimes should only be serialized as structs, not maps") + } + + fn serialize_value<T: ?Sized>(&mut self, _value: &T) -> Result<(), Self::Error> + where + T: serde::ser::Serialize, + { + unreachable!("datetimes should only be serialized as structs, not maps") + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + unreachable!("datetimes should only be serialized as structs, not maps") + } +} + +impl serde::ser::SerializeStruct for SerializeDatetime { + type Ok = crate::Datetime; + type Error = Error; + + fn serialize_field<T: ?Sized>( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), Self::Error> + where + T: serde::ser::Serialize, + { + if key == toml_datetime::__unstable::FIELD { + self.value = Some(value.serialize(DatetimeFieldSerializer::default())?); + } + + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + self.value.ok_or(Error::UnsupportedNone) + } +} + +#[doc(hidden)] +pub struct SerializeInlineTable { + items: crate::table::KeyValuePairs, + key: Option<crate::InternalString>, +} + +impl SerializeInlineTable { + pub(crate) fn new() -> Self { + Self { + items: Default::default(), + key: Default::default(), + } + } + + pub(crate) fn with_capacity(len: usize) -> Self { + let mut s = Self::new(); + s.items.reserve(len); + s + } +} + +impl serde::ser::SerializeMap for SerializeInlineTable { + type Ok = crate::InlineTable; + type Error = Error; + + fn serialize_key<T: ?Sized>(&mut self, input: &T) -> Result<(), Self::Error> + where + T: serde::ser::Serialize, + { + self.key = None; + self.key = Some(input.serialize(KeySerializer)?); + Ok(()) + } + + fn serialize_value<T: ?Sized>(&mut self, value: &T) -> Result<(), Self::Error> + where + T: serde::ser::Serialize, + { + let res = value.serialize(super::ValueSerializer {}); + match res { + Ok(item) => { + let key = self.key.take().unwrap(); + let kv = crate::table::TableKeyValue::new( + crate::Key::new(&key), + crate::Item::Value(item), + ); + self.items.insert(key, kv); + } + Err(e) => { + if e != Error::UnsupportedNone { + return Err(e); + } + } + } + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(crate::InlineTable::with_pairs(self.items)) + } +} + +impl serde::ser::SerializeStruct for SerializeInlineTable { + type Ok = crate::InlineTable; + type Error = Error; + + fn serialize_field<T: ?Sized>( + &mut self, + key: &'static str, + value: &T, + ) -> Result<(), Self::Error> + where + T: serde::ser::Serialize, + { + let res = value.serialize(super::ValueSerializer {}); + match res { + Ok(item) => { + let kv = crate::table::TableKeyValue::new( + crate::Key::new(key), + crate::Item::Value(item), + ); + self.items.insert(crate::InternalString::from(key), kv); + } + Err(e) => { + if e != Error::UnsupportedNone { + return Err(e); + } + } + }; + Ok(()) + } + + fn end(self) -> Result<Self::Ok, Self::Error> { + Ok(crate::InlineTable::with_pairs(self.items)) + } +} + +#[derive(Default)] +struct DatetimeFieldSerializer {} + +impl serde::ser::Serializer for DatetimeFieldSerializer { + type Ok = toml_datetime::Datetime; + type Error = Error; + type SerializeSeq = serde::ser::Impossible<Self::Ok, Self::Error>; + type SerializeTuple = serde::ser::Impossible<Self::Ok, Self::Error>; + type SerializeTupleStruct = serde::ser::Impossible<Self::Ok, Self::Error>; + type SerializeTupleVariant = serde::ser::Impossible<Self::Ok, Self::Error>; + type SerializeMap = serde::ser::Impossible<Self::Ok, Self::Error>; + type SerializeStruct = serde::ser::Impossible<Self::Ok, Self::Error>; + type SerializeStructVariant = serde::ser::Impossible<Self::Ok, Self::Error>; + + fn serialize_bool(self, _value: bool) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_i8(self, _value: i8) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_i16(self, _value: i16) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_i32(self, _value: i32) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_i64(self, _value: i64) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_u8(self, _value: u8) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_u16(self, _value: u16) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_u32(self, _value: u32) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_u64(self, _value: u64) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_f32(self, _value: f32) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_f64(self, _value: f64) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_char(self, _value: char) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> { + v.parse::<toml_datetime::Datetime>().map_err(Error::custom) + } + + fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_none(self) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_some<T: ?Sized>(self, _value: &T) -> Result<Self::Ok, Self::Error> + where + T: serde::ser::Serialize, + { + Err(Error::DateInvalid) + } + + fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + ) -> Result<Self::Ok, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_newtype_struct<T: ?Sized>( + self, + _name: &'static str, + _value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: serde::ser::Serialize, + { + Err(Error::DateInvalid) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: serde::ser::Serialize, + { + Err(Error::DateInvalid) + } + + fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleStruct, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_struct( + self, + _name: &'static str, + _len: usize, + ) -> Result<Self::SerializeStruct, Self::Error> { + Err(Error::DateInvalid) + } + + fn serialize_struct_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error> { + Err(Error::DateInvalid) + } +} diff --git a/vendor/toml_edit-0.19.11/src/ser/mod.rs b/vendor/toml_edit-0.19.11/src/ser/mod.rs new file mode 100644 index 000000000..2c310206b --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/ser/mod.rs @@ -0,0 +1,165 @@ +//! Serializing Rust structures into TOML. +//! +//! This module contains all the Serde support for serializing Rust structures into TOML. + +mod array; +mod key; +mod map; +mod pretty; +mod value; + +pub(crate) use array::*; +pub(crate) use key::*; +pub(crate) use map::*; + +use crate::visit_mut::VisitMut; + +/// Errors that can occur when deserializing a type. +#[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] +pub enum Error { + /// Type could not be serialized to TOML + UnsupportedType(Option<&'static str>), + /// Value was out of range for the given type + OutOfRange(Option<&'static str>), + /// `None` could not be serialized to TOML + UnsupportedNone, + /// Key was not convertable to `String` for serializing to TOML + KeyNotString, + /// A serialized date was invalid + DateInvalid, + /// Other serialization error + Custom(String), +} + +impl Error { + pub(crate) fn custom<T>(msg: T) -> Self + where + T: std::fmt::Display, + { + Error::Custom(msg.to_string()) + } +} + +impl serde::ser::Error for Error { + fn custom<T>(msg: T) -> Self + where + T: std::fmt::Display, + { + Self::custom(msg) + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + Self::UnsupportedType(Some(t)) => write!(formatter, "unsupported {t} type"), + Self::UnsupportedType(None) => write!(formatter, "unsupported rust type"), + Self::OutOfRange(Some(t)) => write!(formatter, "out-of-range value for {t} type"), + Self::OutOfRange(None) => write!(formatter, "out-of-range value"), + Self::UnsupportedNone => "unsupported None value".fmt(formatter), + Self::KeyNotString => "map key was not a string".fmt(formatter), + Self::DateInvalid => "a serialized date was invalid".fmt(formatter), + Self::Custom(s) => s.fmt(formatter), + } + } +} + +impl From<crate::TomlError> for Error { + fn from(e: crate::TomlError) -> Error { + Self::custom(e) + } +} + +impl From<Error> for crate::TomlError { + fn from(e: Error) -> crate::TomlError { + Self::custom(e.to_string(), None) + } +} + +impl std::error::Error for Error {} + +/// Serialize the given data structure as a TOML byte vector. +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, if `T` contains a map with non-string keys, or if `T` attempts to +/// serialize an unsupported datatype such as an enum, tuple, or tuple struct. +pub fn to_vec<T: ?Sized>(value: &T) -> Result<Vec<u8>, Error> +where + T: serde::ser::Serialize, +{ + to_string(value).map(|e| e.into_bytes()) +} + +/// Serialize the given data structure as a String of TOML. +/// +/// Serialization can fail if `T`'s implementation of `Serialize` decides to +/// fail, if `T` contains a map with non-string keys, or if `T` attempts to +/// serialize an unsupported datatype such as an enum, tuple, or tuple struct. +/// +/// # Examples +/// +/// ``` +/// use serde::Serialize; +/// +/// #[derive(Serialize)] +/// struct Config { +/// database: Database, +/// } +/// +/// #[derive(Serialize)] +/// struct Database { +/// ip: String, +/// port: Vec<u16>, +/// connection_max: u32, +/// enabled: bool, +/// } +/// +/// let config = Config { +/// database: Database { +/// ip: "192.168.1.1".to_string(), +/// port: vec![8001, 8002, 8003], +/// connection_max: 5000, +/// enabled: false, +/// }, +/// }; +/// +/// let toml = toml_edit::ser::to_string(&config).unwrap(); +/// println!("{}", toml) +/// ``` +pub fn to_string<T: ?Sized>(value: &T) -> Result<String, Error> +where + T: serde::ser::Serialize, +{ + to_document(value).map(|e| e.to_string()) +} + +/// Serialize the given data structure as a "pretty" String of TOML. +/// +/// This is identical to `to_string` except the output string has a more +/// "pretty" output. See `ValueSerializer::pretty` for more details. +pub fn to_string_pretty<T: ?Sized>(value: &T) -> Result<String, Error> +where + T: serde::ser::Serialize, +{ + let mut document = to_document(value)?; + pretty::Pretty.visit_document_mut(&mut document); + Ok(document.to_string()) +} + +/// Serialize the given data structure into a TOML document. +/// +/// This would allow custom formatting to be applied, mixing with format preserving edits, etc. +pub fn to_document<T: ?Sized>(value: &T) -> Result<crate::Document, Error> +where + T: serde::ser::Serialize, +{ + let value = value.serialize(ValueSerializer::new())?; + let item = crate::Item::Value(value); + let root = item + .into_table() + .map_err(|_| Error::UnsupportedType(None))?; + Ok(root.into()) +} + +pub use value::ValueSerializer; diff --git a/vendor/toml_edit-0.19.11/src/ser/pretty.rs b/vendor/toml_edit-0.19.11/src/ser/pretty.rs new file mode 100644 index 000000000..2c22f6804 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/ser/pretty.rs @@ -0,0 +1,45 @@ +pub(crate) struct Pretty; + +impl crate::visit_mut::VisitMut for Pretty { + fn visit_document_mut(&mut self, node: &mut crate::Document) { + crate::visit_mut::visit_document_mut(self, node); + } + + fn visit_item_mut(&mut self, node: &mut crate::Item) { + node.make_item(); + + crate::visit_mut::visit_item_mut(self, node); + } + + fn visit_table_mut(&mut self, node: &mut crate::Table) { + node.decor_mut().clear(); + + // Empty tables could be semantically meaningful, so make sure they are not implicit + if !node.is_empty() { + node.set_implicit(true); + } + + crate::visit_mut::visit_table_mut(self, node); + } + + fn visit_value_mut(&mut self, node: &mut crate::Value) { + node.decor_mut().clear(); + + crate::visit_mut::visit_value_mut(self, node); + } + + fn visit_array_mut(&mut self, node: &mut crate::Array) { + crate::visit_mut::visit_array_mut(self, node); + + if (0..=1).contains(&node.len()) { + node.set_trailing(""); + node.set_trailing_comma(false); + } else { + for item in node.iter_mut() { + item.decor_mut().set_prefix("\n "); + } + node.set_trailing("\n"); + node.set_trailing_comma(true); + } + } +} diff --git a/vendor/toml_edit-0.19.11/src/ser/value.rs b/vendor/toml_edit-0.19.11/src/ser/value.rs new file mode 100644 index 000000000..d29390a4c --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/ser/value.rs @@ -0,0 +1,243 @@ +use super::Error; + +/// Serialization for TOML [values][crate::Value]. +/// +/// This structure implements serialization support for TOML to serialize an +/// arbitrary type to TOML. Note that the TOML format does not support all +/// datatypes in Rust, such as enums, tuples, and tuple structs. These types +/// will generate an error when serialized. +/// +/// Currently a serializer always writes its output to an in-memory `String`, +/// which is passed in when creating the serializer itself. +/// +/// # Examples +/// +/// ``` +/// use serde::Serialize; +/// +/// #[derive(Serialize)] +/// struct Config { +/// database: Database, +/// } +/// +/// #[derive(Serialize)] +/// struct Database { +/// ip: String, +/// port: Vec<u16>, +/// connection_max: u32, +/// enabled: bool, +/// } +/// +/// let config = Config { +/// database: Database { +/// ip: "192.168.1.1".to_string(), +/// port: vec![8001, 8002, 8003], +/// connection_max: 5000, +/// enabled: false, +/// }, +/// }; +/// +/// let value = serde::Serialize::serialize( +/// &config, +/// toml_edit::ser::ValueSerializer::new() +/// ).unwrap(); +/// println!("{}", value) +/// ``` +#[derive(Default)] +#[non_exhaustive] +pub struct ValueSerializer {} + +impl ValueSerializer { + /// Creates a new serializer generate a TOML document. + pub fn new() -> Self { + Self {} + } +} + +impl serde::ser::Serializer for ValueSerializer { + type Ok = crate::Value; + type Error = Error; + type SerializeSeq = super::SerializeValueArray; + type SerializeTuple = super::SerializeValueArray; + type SerializeTupleStruct = super::SerializeValueArray; + type SerializeTupleVariant = super::SerializeValueArray; + type SerializeMap = super::SerializeMap; + type SerializeStruct = super::SerializeMap; + type SerializeStructVariant = serde::ser::Impossible<Self::Ok, Self::Error>; + + fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> { + Ok(v.into()) + } + + fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> { + self.serialize_i64(v as i64) + } + + fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> { + self.serialize_i64(v as i64) + } + + fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> { + self.serialize_i64(v as i64) + } + + fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> { + Ok(v.into()) + } + + fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> { + self.serialize_i64(v as i64) + } + + fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> { + self.serialize_i64(v as i64) + } + + fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> { + self.serialize_i64(v as i64) + } + + fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> { + let v: i64 = v + .try_into() + .map_err(|_err| Error::OutOfRange(Some("u64")))?; + self.serialize_i64(v) + } + + fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> { + self.serialize_f64(v as f64) + } + + fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> { + Ok(v.into()) + } + + fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> { + let mut buf = [0; 4]; + self.serialize_str(v.encode_utf8(&mut buf)) + } + + fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> { + Ok(v.into()) + } + + fn serialize_bytes(self, value: &[u8]) -> Result<Self::Ok, Self::Error> { + use serde::ser::Serialize; + value.serialize(self) + } + + fn serialize_none(self) -> Result<Self::Ok, Self::Error> { + Err(Error::UnsupportedNone) + } + + fn serialize_some<T: ?Sized>(self, value: &T) -> Result<Self::Ok, Self::Error> + where + T: serde::ser::Serialize, + { + value.serialize(self) + } + + fn serialize_unit(self) -> Result<Self::Ok, Self::Error> { + Err(Error::UnsupportedType(Some("unit"))) + } + + fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> { + Err(Error::UnsupportedType(Some(name))) + } + + fn serialize_unit_variant( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + ) -> Result<Self::Ok, Self::Error> { + self.serialize_str(variant) + } + + fn serialize_newtype_struct<T: ?Sized>( + self, + _name: &'static str, + value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: serde::ser::Serialize, + { + value.serialize(self) + } + + fn serialize_newtype_variant<T: ?Sized>( + self, + _name: &'static str, + _variant_index: u32, + variant: &'static str, + value: &T, + ) -> Result<Self::Ok, Self::Error> + where + T: serde::ser::Serialize, + { + let value = value.serialize(self)?; + let mut table = crate::InlineTable::new(); + table.insert(variant, value); + Ok(table.into()) + } + + fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> { + let serializer = match len { + Some(len) => super::SerializeValueArray::with_capacity(len), + None => super::SerializeValueArray::new(), + }; + Ok(serializer) + } + + fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_struct( + self, + _name: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleStruct, Self::Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_tuple_variant( + self, + _name: &'static str, + _variant_index: u32, + _variant: &'static str, + len: usize, + ) -> Result<Self::SerializeTupleVariant, Self::Error> { + self.serialize_seq(Some(len)) + } + + fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> { + let serializer = match len { + Some(len) => super::SerializeMap::table_with_capacity(len), + None => super::SerializeMap::table(), + }; + Ok(serializer) + } + + fn serialize_struct( + self, + name: &'static str, + len: usize, + ) -> Result<Self::SerializeStruct, Self::Error> { + if name == toml_datetime::__unstable::NAME { + Ok(super::SerializeMap::datetime()) + } else { + self.serialize_map(Some(len)) + } + } + + fn serialize_struct_variant( + self, + name: &'static str, + _variant_index: u32, + _variant: &'static str, + _len: usize, + ) -> Result<Self::SerializeStructVariant, Self::Error> { + Err(Error::UnsupportedType(Some(name))) + } +} diff --git a/vendor/toml_edit-0.19.11/src/table.rs b/vendor/toml_edit-0.19.11/src/table.rs new file mode 100644 index 000000000..2f61abf73 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/table.rs @@ -0,0 +1,743 @@ +use std::iter::FromIterator; + +use indexmap::map::IndexMap; + +use crate::key::Key; +use crate::repr::Decor; +use crate::value::DEFAULT_VALUE_DECOR; +use crate::{InlineTable, InternalString, Item, KeyMut, Value}; + +/// Type representing a TOML non-inline table +#[derive(Clone, Debug, Default)] +pub struct Table { + // Comments/spaces before and after the header + pub(crate) decor: Decor, + // Whether to hide an empty table + pub(crate) implicit: bool, + // Whether this is a proxy for dotted keys + pub(crate) dotted: bool, + // Used for putting tables back in their original order when serialising. + // + // `None` for user created tables (can be overridden with `set_position`) + doc_position: Option<usize>, + pub(crate) span: Option<std::ops::Range<usize>>, + pub(crate) items: KeyValuePairs, +} + +/// Constructors +/// +/// See also `FromIterator` +impl Table { + /// Creates an empty table. + pub fn new() -> Self { + Default::default() + } + + pub(crate) fn with_pos(doc_position: Option<usize>) -> Self { + Self { + doc_position, + ..Default::default() + } + } + + pub(crate) fn with_pairs(items: KeyValuePairs) -> Self { + Self { + items, + ..Default::default() + } + } + + /// Convert to an inline table + pub fn into_inline_table(mut self) -> InlineTable { + for (_, kv) in self.items.iter_mut() { + kv.value.make_value(); + } + let mut t = InlineTable::with_pairs(self.items); + t.fmt(); + t + } +} + +/// Formatting +impl Table { + /// Get key/values for values that are visually children of this table + /// + /// For example, this will return dotted keys + pub fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> { + let mut values = Vec::new(); + let root = Vec::new(); + self.append_values(&root, &mut values); + values + } + + fn append_values<'s, 'c>( + &'s self, + parent: &[&'s Key], + values: &'c mut Vec<(Vec<&'s Key>, &'s Value)>, + ) { + for value in self.items.values() { + let mut path = parent.to_vec(); + path.push(&value.key); + match &value.value { + Item::Table(table) if table.is_dotted() => { + table.append_values(&path, values); + } + Item::Value(value) => { + if let Some(table) = value.as_inline_table() { + if table.is_dotted() { + table.append_values(&path, values); + } else { + values.push((path, value)); + } + } else { + values.push((path, value)); + } + } + _ => {} + } + } + } + + /// Auto formats the table. + pub fn fmt(&mut self) { + decorate_table(self); + } + + /// Sorts Key/Value Pairs of the table. + /// + /// Doesn't affect subtables or subarrays. + pub fn sort_values(&mut self) { + // Assuming standard tables have their doc_position set and this won't negatively impact them + self.items.sort_keys(); + for kv in self.items.values_mut() { + match &mut kv.value { + Item::Table(table) if table.is_dotted() => { + table.sort_values(); + } + _ => {} + } + } + } + + /// Sort Key/Value Pairs of the table using the using the comparison function `compare`. + /// + /// The comparison function receives two key and value pairs to compare (you can sort by keys or + /// values or their combination as needed). + pub fn sort_values_by<F>(&mut self, mut compare: F) + where + F: FnMut(&Key, &Item, &Key, &Item) -> std::cmp::Ordering, + { + self.sort_values_by_internal(&mut compare); + } + + fn sort_values_by_internal<F>(&mut self, compare: &mut F) + where + F: FnMut(&Key, &Item, &Key, &Item) -> std::cmp::Ordering, + { + let modified_cmp = |_: &InternalString, + val1: &TableKeyValue, + _: &InternalString, + val2: &TableKeyValue| + -> std::cmp::Ordering { + compare(&val1.key, &val1.value, &val2.key, &val2.value) + }; + + self.items.sort_by(modified_cmp); + + for kv in self.items.values_mut() { + match &mut kv.value { + Item::Table(table) if table.is_dotted() => { + table.sort_values_by_internal(compare); + } + _ => {} + } + } + } + + /// If a table has no key/value pairs and implicit, it will not be displayed. + /// + /// # Examples + /// + /// ```notrust + /// [target."x86_64/windows.json".dependencies] + /// ``` + /// + /// In the document above, tables `target` and `target."x86_64/windows.json"` are implicit. + /// + /// ``` + /// use toml_edit::Document; + /// let mut doc = "[a]\n[a.b]\n".parse::<Document>().expect("invalid toml"); + /// + /// doc["a"].as_table_mut().unwrap().set_implicit(true); + /// assert_eq!(doc.to_string(), "[a.b]\n"); + /// ``` + pub fn set_implicit(&mut self, implicit: bool) { + self.implicit = implicit; + } + + /// If a table has no key/value pairs and implicit, it will not be displayed. + pub fn is_implicit(&self) -> bool { + self.implicit + } + + /// Change this table's dotted status + pub fn set_dotted(&mut self, yes: bool) { + self.dotted = yes; + } + + /// Check if this is a wrapper for dotted keys, rather than a standard table + pub fn is_dotted(&self) -> bool { + self.dotted + } + + /// Sets the position of the `Table` within the `Document`. + pub fn set_position(&mut self, doc_position: usize) { + self.doc_position = Some(doc_position); + } + + /// The position of the `Table` within the `Document`. + /// + /// Returns `None` if the `Table` was created manually (i.e. not via parsing) + /// in which case its position is set automatically. This can be overridden with + /// [`Table::set_position`]. + pub fn position(&self) -> Option<usize> { + self.doc_position + } + + /// Returns the surrounding whitespace + pub fn decor_mut(&mut self) -> &mut Decor { + &mut self.decor + } + + /// Returns the decor associated with a given key of the table. + pub fn decor(&self) -> &Decor { + &self.decor + } + + /// Returns the decor associated with a given key of the table. + pub fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> { + self.items.get_mut(key).map(|kv| &mut kv.key.decor) + } + + /// Returns the decor associated with a given key of the table. + pub fn key_decor(&self, key: &str) -> Option<&Decor> { + self.items.get(key).map(|kv| &kv.key.decor) + } + + /// Returns the location within the original document + pub(crate) fn span(&self) -> Option<std::ops::Range<usize>> { + self.span.clone() + } + + pub(crate) fn despan(&mut self, input: &str) { + self.span = None; + self.decor.despan(input); + for kv in self.items.values_mut() { + kv.key.despan(input); + kv.value.despan(input); + } + } +} + +impl Table { + /// Returns an iterator over all key/value pairs, including empty. + pub fn iter(&self) -> Iter<'_> { + Box::new( + self.items + .iter() + .filter(|(_, kv)| !kv.value.is_none()) + .map(|(key, kv)| (&key[..], &kv.value)), + ) + } + + /// Returns an mutable iterator over all key/value pairs, including empty. + pub fn iter_mut(&mut self) -> IterMut<'_> { + Box::new( + self.items + .iter_mut() + .filter(|(_, kv)| !kv.value.is_none()) + .map(|(_, kv)| (kv.key.as_mut(), &mut kv.value)), + ) + } + + /// Returns the number of non-empty items in the table. + pub fn len(&self) -> usize { + self.items.iter().filter(|i| !(i.1).value.is_none()).count() + } + + /// Returns true if the table is empty. + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + /// Clears the table, removing all key-value pairs. Keeps the allocated memory for reuse. + pub fn clear(&mut self) { + self.items.clear() + } + + /// Gets the given key's corresponding entry in the Table for in-place manipulation. + pub fn entry<'a>(&'a mut self, key: &str) -> Entry<'a> { + // Accept a `&str` rather than an owned type to keep `InternalString`, well, internal + match self.items.entry(key.into()) { + indexmap::map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { entry }), + indexmap::map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { entry, key: None }), + } + } + + /// Gets the given key's corresponding entry in the Table for in-place manipulation. + pub fn entry_format<'a>(&'a mut self, key: &Key) -> Entry<'a> { + // Accept a `&Key` to be consistent with `entry` + match self.items.entry(key.get().into()) { + indexmap::map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { entry }), + indexmap::map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { + entry, + key: Some(key.to_owned()), + }), + } + } + + /// Returns an optional reference to an item given the key. + pub fn get<'a>(&'a self, key: &str) -> Option<&'a Item> { + self.items.get(key).and_then(|kv| { + if !kv.value.is_none() { + Some(&kv.value) + } else { + None + } + }) + } + + /// Returns an optional mutable reference to an item given the key. + pub fn get_mut<'a>(&'a mut self, key: &str) -> Option<&'a mut Item> { + self.items.get_mut(key).and_then(|kv| { + if !kv.value.is_none() { + Some(&mut kv.value) + } else { + None + } + }) + } + + /// Return references to the key-value pair stored for key, if it is present, else None. + pub fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> { + self.items.get(key).and_then(|kv| { + if !kv.value.is_none() { + Some((&kv.key, &kv.value)) + } else { + None + } + }) + } + + /// Return mutable references to the key-value pair stored for key, if it is present, else None. + pub fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> { + self.items.get_mut(key).and_then(|kv| { + if !kv.value.is_none() { + Some((kv.key.as_mut(), &mut kv.value)) + } else { + None + } + }) + } + + /// Returns true if the table contains an item with the given key. + pub fn contains_key(&self, key: &str) -> bool { + if let Some(kv) = self.items.get(key) { + !kv.value.is_none() + } else { + false + } + } + + /// Returns true if the table contains a table with the given key. + pub fn contains_table(&self, key: &str) -> bool { + if let Some(kv) = self.items.get(key) { + kv.value.is_table() + } else { + false + } + } + + /// Returns true if the table contains a value with the given key. + pub fn contains_value(&self, key: &str) -> bool { + if let Some(kv) = self.items.get(key) { + kv.value.is_value() + } else { + false + } + } + + /// Returns true if the table contains an array of tables with the given key. + pub fn contains_array_of_tables(&self, key: &str) -> bool { + if let Some(kv) = self.items.get(key) { + kv.value.is_array_of_tables() + } else { + false + } + } + + /// Inserts a key-value pair into the map. + pub fn insert(&mut self, key: &str, item: Item) -> Option<Item> { + let kv = TableKeyValue::new(Key::new(key), item); + self.items.insert(key.into(), kv).map(|kv| kv.value) + } + + /// Inserts a key-value pair into the map. + pub fn insert_formatted(&mut self, key: &Key, item: Item) -> Option<Item> { + let kv = TableKeyValue::new(key.to_owned(), item); + self.items.insert(key.get().into(), kv).map(|kv| kv.value) + } + + /// Removes an item given the key. + pub fn remove(&mut self, key: &str) -> Option<Item> { + self.items.shift_remove(key).map(|kv| kv.value) + } + + /// Removes a key from the map, returning the stored key and value if the key was previously in the map. + pub fn remove_entry(&mut self, key: &str) -> Option<(Key, Item)> { + self.items.shift_remove(key).map(|kv| (kv.key, kv.value)) + } +} + +impl std::fmt::Display for Table { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + use crate::encode::Encode; + let children = self.get_values(); + // print table body + for (key_path, value) in children { + key_path.as_slice().encode(f, None, DEFAULT_KEY_DECOR)?; + write!(f, "=")?; + value.encode(f, None, DEFAULT_VALUE_DECOR)?; + writeln!(f)?; + } + Ok(()) + } +} + +impl<K: Into<Key>, V: Into<Value>> Extend<(K, V)> for Table { + fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) { + for (key, value) in iter { + let key = key.into(); + let value = Item::Value(value.into()); + let value = TableKeyValue::new(key, value); + self.items.insert(value.key.get().into(), value); + } + } +} + +impl<K: Into<Key>, V: Into<Value>> FromIterator<(K, V)> for Table { + fn from_iter<I>(iter: I) -> Self + where + I: IntoIterator<Item = (K, V)>, + { + let mut table = Table::new(); + table.extend(iter); + table + } +} + +impl IntoIterator for Table { + type Item = (InternalString, Item); + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + Box::new(self.items.into_iter().map(|(k, kv)| (k, kv.value))) + } +} + +impl<'s> IntoIterator for &'s Table { + type Item = (&'s str, &'s Item); + type IntoIter = Iter<'s>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +pub(crate) type KeyValuePairs = IndexMap<InternalString, TableKeyValue>; + +fn decorate_table(table: &mut Table) { + for (key_decor, value) in table + .items + .iter_mut() + .filter(|&(_, ref kv)| kv.value.is_value()) + .map(|(_, kv)| (&mut kv.key.decor, kv.value.as_value_mut().unwrap())) + { + key_decor.clear(); + value.decor_mut().clear(); + } +} + +// `key1 = value1` +pub(crate) const DEFAULT_KEY_DECOR: (&str, &str) = ("", " "); +pub(crate) const DEFAULT_TABLE_DECOR: (&str, &str) = ("\n", ""); +pub(crate) const DEFAULT_KEY_PATH_DECOR: (&str, &str) = ("", ""); + +#[derive(Debug, Clone)] +pub(crate) struct TableKeyValue { + pub(crate) key: Key, + pub(crate) value: Item, +} + +impl TableKeyValue { + pub(crate) fn new(key: Key, value: Item) -> Self { + TableKeyValue { key, value } + } +} + +/// An owned iterator type over `Table`'s key/value pairs. +pub type IntoIter = Box<dyn Iterator<Item = (InternalString, Item)>>; +/// An iterator type over `Table`'s key/value pairs. +pub type Iter<'a> = Box<dyn Iterator<Item = (&'a str, &'a Item)> + 'a>; +/// A mutable iterator type over `Table`'s key/value pairs. +pub type IterMut<'a> = Box<dyn Iterator<Item = (KeyMut<'a>, &'a mut Item)> + 'a>; + +/// This trait represents either a `Table`, or an `InlineTable`. +pub trait TableLike: crate::private::Sealed { + /// Returns an iterator over key/value pairs. + fn iter(&self) -> Iter<'_>; + /// Returns an mutable iterator over all key/value pairs, including empty. + fn iter_mut(&mut self) -> IterMut<'_>; + /// Returns the number of nonempty items. + fn len(&self) -> usize { + self.iter().filter(|&(_, v)| !v.is_none()).count() + } + /// Returns true if the table is empty. + fn is_empty(&self) -> bool { + self.len() == 0 + } + /// Clears the table, removing all key-value pairs. Keeps the allocated memory for reuse. + fn clear(&mut self); + /// Gets the given key's corresponding entry in the Table for in-place manipulation. + fn entry<'a>(&'a mut self, key: &str) -> Entry<'a>; + /// Gets the given key's corresponding entry in the Table for in-place manipulation. + fn entry_format<'a>(&'a mut self, key: &Key) -> Entry<'a>; + /// Returns an optional reference to an item given the key. + fn get<'s>(&'s self, key: &str) -> Option<&'s Item>; + /// Returns an optional mutable reference to an item given the key. + fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item>; + /// Return references to the key-value pair stored for key, if it is present, else None. + fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)>; + /// Return mutable references to the key-value pair stored for key, if it is present, else None. + fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)>; + /// Returns true if the table contains an item with the given key. + fn contains_key(&self, key: &str) -> bool; + /// Inserts a key-value pair into the map. + fn insert(&mut self, key: &str, value: Item) -> Option<Item>; + /// Removes an item given the key. + fn remove(&mut self, key: &str) -> Option<Item>; + + /// Get key/values for values that are visually children of this table + /// + /// For example, this will return dotted keys + fn get_values(&self) -> Vec<(Vec<&Key>, &Value)>; + + /// Auto formats the table. + fn fmt(&mut self); + /// Sorts Key/Value Pairs of the table. + /// + /// Doesn't affect subtables or subarrays. + fn sort_values(&mut self); + /// Change this table's dotted status + fn set_dotted(&mut self, yes: bool); + /// Check if this is a wrapper for dotted keys, rather than a standard table + fn is_dotted(&self) -> bool; + + /// Returns the decor associated with a given key of the table. + fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor>; + /// Returns the decor associated with a given key of the table. + fn key_decor(&self, key: &str) -> Option<&Decor>; +} + +impl TableLike for Table { + fn iter(&self) -> Iter<'_> { + self.iter() + } + fn iter_mut(&mut self) -> IterMut<'_> { + self.iter_mut() + } + fn clear(&mut self) { + self.clear(); + } + fn entry<'a>(&'a mut self, key: &str) -> Entry<'a> { + self.entry(key) + } + fn entry_format<'a>(&'a mut self, key: &Key) -> Entry<'a> { + self.entry_format(key) + } + fn get<'s>(&'s self, key: &str) -> Option<&'s Item> { + self.get(key) + } + fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item> { + self.get_mut(key) + } + fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> { + self.get_key_value(key) + } + fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> { + self.get_key_value_mut(key) + } + fn contains_key(&self, key: &str) -> bool { + self.contains_key(key) + } + fn insert(&mut self, key: &str, value: Item) -> Option<Item> { + self.insert(key, value) + } + fn remove(&mut self, key: &str) -> Option<Item> { + self.remove(key) + } + + fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> { + self.get_values() + } + fn fmt(&mut self) { + self.fmt() + } + fn sort_values(&mut self) { + self.sort_values() + } + fn is_dotted(&self) -> bool { + self.is_dotted() + } + fn set_dotted(&mut self, yes: bool) { + self.set_dotted(yes) + } + + fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> { + self.key_decor_mut(key) + } + fn key_decor(&self, key: &str) -> Option<&Decor> { + self.key_decor(key) + } +} + +/// A view into a single location in a map, which may be vacant or occupied. +pub enum Entry<'a> { + /// An occupied Entry. + Occupied(OccupiedEntry<'a>), + /// A vacant Entry. + Vacant(VacantEntry<'a>), +} + +impl<'a> Entry<'a> { + /// Returns the entry key + /// + /// # Examples + /// + /// ``` + /// use toml_edit::Table; + /// + /// let mut map = Table::new(); + /// + /// assert_eq!("hello", map.entry("hello").key()); + /// ``` + pub fn key(&self) -> &str { + match self { + Entry::Occupied(e) => e.key(), + Entry::Vacant(e) => e.key(), + } + } + + /// Ensures a value is in the entry by inserting the default if empty, and returns + /// a mutable reference to the value in the entry. + pub fn or_insert(self, default: Item) -> &'a mut Item { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default), + } + } + + /// Ensures a value is in the entry by inserting the result of the default function if empty, + /// and returns a mutable reference to the value in the entry. + pub fn or_insert_with<F: FnOnce() -> Item>(self, default: F) -> &'a mut Item { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(entry) => entry.insert(default()), + } + } +} + +/// A view into a single occupied location in a `IndexMap`. +pub struct OccupiedEntry<'a> { + pub(crate) entry: indexmap::map::OccupiedEntry<'a, InternalString, TableKeyValue>, +} + +impl<'a> OccupiedEntry<'a> { + /// Gets a reference to the entry key + /// + /// # Examples + /// + /// ``` + /// use toml_edit::Table; + /// + /// let mut map = Table::new(); + /// + /// assert_eq!("foo", map.entry("foo").key()); + /// ``` + pub fn key(&self) -> &str { + self.entry.key().as_str() + } + + /// Gets a mutable reference to the entry key + pub fn key_mut(&mut self) -> KeyMut<'_> { + self.entry.get_mut().key.as_mut() + } + + /// Gets a reference to the value in the entry. + pub fn get(&self) -> &Item { + &self.entry.get().value + } + + /// Gets a mutable reference to the value in the entry. + pub fn get_mut(&mut self) -> &mut Item { + &mut self.entry.get_mut().value + } + + /// Converts the OccupiedEntry into a mutable reference to the value in the entry + /// with a lifetime bound to the map itself + pub fn into_mut(self) -> &'a mut Item { + &mut self.entry.into_mut().value + } + + /// Sets the value of the entry, and returns the entry's old value + pub fn insert(&mut self, mut value: Item) -> Item { + std::mem::swap(&mut value, &mut self.entry.get_mut().value); + value + } + + /// Takes the value out of the entry, and returns it + pub fn remove(self) -> Item { + self.entry.shift_remove().value + } +} + +/// A view into a single empty location in a `IndexMap`. +pub struct VacantEntry<'a> { + pub(crate) entry: indexmap::map::VacantEntry<'a, InternalString, TableKeyValue>, + pub(crate) key: Option<Key>, +} + +impl<'a> VacantEntry<'a> { + /// Gets a reference to the entry key + /// + /// # Examples + /// + /// ``` + /// use toml_edit::Table; + /// + /// let mut map = Table::new(); + /// + /// assert_eq!("foo", map.entry("foo").key()); + /// ``` + pub fn key(&self) -> &str { + self.entry.key().as_str() + } + + /// Sets the value of the entry with the VacantEntry's key, + /// and returns a mutable reference to it + pub fn insert(self, value: Item) -> &'a mut Item { + let entry = self.entry; + let key = self.key.unwrap_or_else(|| Key::new(entry.key().as_str())); + &mut entry.insert(TableKeyValue::new(key, value)).value + } +} diff --git a/vendor/toml_edit-0.19.11/src/value.rs b/vendor/toml_edit-0.19.11/src/value.rs new file mode 100644 index 000000000..f10da9a4c --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/value.rs @@ -0,0 +1,372 @@ +use std::iter::FromIterator; +use std::str::FromStr; + +use toml_datetime::*; + +use crate::key::Key; +use crate::parser; +use crate::repr::{Decor, Formatted}; +use crate::{Array, InlineTable, InternalString, RawString}; + +/// Representation of a TOML Value (as part of a Key/Value Pair). +#[derive(Debug, Clone)] +pub enum Value { + /// A string value. + String(Formatted<String>), + /// A 64-bit integer value. + Integer(Formatted<i64>), + /// A 64-bit float value. + Float(Formatted<f64>), + /// A boolean value. + Boolean(Formatted<bool>), + /// An RFC 3339 formatted date-time with offset. + Datetime(Formatted<Datetime>), + /// An inline array of values. + Array(Array), + /// An inline table of key/value pairs. + InlineTable(InlineTable), +} + +/// Downcasting +impl Value { + /// Text description of value type + pub fn type_name(&self) -> &'static str { + match self { + Value::String(..) => "string", + Value::Integer(..) => "integer", + Value::Float(..) => "float", + Value::Boolean(..) => "boolean", + Value::Datetime(..) => "datetime", + Value::Array(..) => "array", + Value::InlineTable(..) => "inline table", + } + } + + /// Casts `self` to str. + pub fn as_str(&self) -> Option<&str> { + match *self { + Value::String(ref value) => Some(value.value()), + _ => None, + } + } + + /// Returns true iff `self` is a string. + pub fn is_str(&self) -> bool { + self.as_str().is_some() + } + + /// Casts `self` to integer. + pub fn as_integer(&self) -> Option<i64> { + match *self { + Value::Integer(ref value) => Some(*value.value()), + _ => None, + } + } + + /// Returns true iff `self` is an integer. + pub fn is_integer(&self) -> bool { + self.as_integer().is_some() + } + + /// Casts `self` to float. + pub fn as_float(&self) -> Option<f64> { + match *self { + Value::Float(ref value) => Some(*value.value()), + _ => None, + } + } + + /// Returns true iff `self` is a float. + pub fn is_float(&self) -> bool { + self.as_float().is_some() + } + + /// Casts `self` to boolean. + pub fn as_bool(&self) -> Option<bool> { + match *self { + Value::Boolean(ref value) => Some(*value.value()), + _ => None, + } + } + + /// Returns true iff `self` is a boolean. + pub fn is_bool(&self) -> bool { + self.as_bool().is_some() + } + + /// Casts `self` to date-time. + pub fn as_datetime(&self) -> Option<&Datetime> { + match *self { + Value::Datetime(ref value) => Some(value.value()), + _ => None, + } + } + + /// Returns true iff `self` is a date-time. + pub fn is_datetime(&self) -> bool { + self.as_datetime().is_some() + } + + /// Casts `self` to array. + pub fn as_array(&self) -> Option<&Array> { + match *self { + Value::Array(ref value) => Some(value), + _ => None, + } + } + + /// Casts `self` to mutable array. + pub fn as_array_mut(&mut self) -> Option<&mut Array> { + match *self { + Value::Array(ref mut value) => Some(value), + _ => None, + } + } + + /// Returns true iff `self` is an array. + pub fn is_array(&self) -> bool { + self.as_array().is_some() + } + + /// Casts `self` to inline table. + pub fn as_inline_table(&self) -> Option<&InlineTable> { + match *self { + Value::InlineTable(ref value) => Some(value), + _ => None, + } + } + + /// Casts `self` to mutable inline table. + pub fn as_inline_table_mut(&mut self) -> Option<&mut InlineTable> { + match *self { + Value::InlineTable(ref mut value) => Some(value), + _ => None, + } + } + + /// Returns true iff `self` is an inline table. + pub fn is_inline_table(&self) -> bool { + self.as_inline_table().is_some() + } +} + +impl Value { + /// Get the decoration of the value. + /// # Example + /// ```rust + /// let v = toml_edit::Value::from(true); + /// assert_eq!(v.decor().suffix(), None); + ///``` + pub fn decor_mut(&mut self) -> &mut Decor { + match self { + Value::String(f) => f.decor_mut(), + Value::Integer(f) => f.decor_mut(), + Value::Float(f) => f.decor_mut(), + Value::Boolean(f) => f.decor_mut(), + Value::Datetime(f) => f.decor_mut(), + Value::Array(a) => a.decor_mut(), + Value::InlineTable(t) => t.decor_mut(), + } + } + + /// Get the decoration of the value. + /// # Example + /// ```rust + /// let v = toml_edit::Value::from(true); + /// assert_eq!(v.decor().suffix(), None); + ///``` + pub fn decor(&self) -> &Decor { + match *self { + Value::String(ref f) => f.decor(), + Value::Integer(ref f) => f.decor(), + Value::Float(ref f) => f.decor(), + Value::Boolean(ref f) => f.decor(), + Value::Datetime(ref f) => f.decor(), + Value::Array(ref a) => a.decor(), + Value::InlineTable(ref t) => t.decor(), + } + } + + /// Sets the prefix and the suffix for value. + /// # Example + /// ```rust + /// let mut v = toml_edit::Value::from(42); + /// assert_eq!(&v.to_string(), "42"); + /// let d = v.decorated(" ", " "); + /// assert_eq!(&d.to_string(), " 42 "); + /// ``` + pub fn decorated(mut self, prefix: impl Into<RawString>, suffix: impl Into<RawString>) -> Self { + self.decorate(prefix, suffix); + self + } + + pub(crate) fn decorate(&mut self, prefix: impl Into<RawString>, suffix: impl Into<RawString>) { + let decor = self.decor_mut(); + *decor = Decor::new(prefix, suffix); + } + + /// Returns the location within the original document + pub(crate) fn span(&self) -> Option<std::ops::Range<usize>> { + match self { + Value::String(f) => f.span(), + Value::Integer(f) => f.span(), + Value::Float(f) => f.span(), + Value::Boolean(f) => f.span(), + Value::Datetime(f) => f.span(), + Value::Array(a) => a.span(), + Value::InlineTable(t) => t.span(), + } + } + + pub(crate) fn despan(&mut self, input: &str) { + match self { + Value::String(f) => f.despan(input), + Value::Integer(f) => f.despan(input), + Value::Float(f) => f.despan(input), + Value::Boolean(f) => f.despan(input), + Value::Datetime(f) => f.despan(input), + Value::Array(a) => a.despan(input), + Value::InlineTable(t) => t.despan(input), + } + } +} + +impl FromStr for Value { + type Err = crate::TomlError; + + /// Parses a value from a &str + fn from_str(s: &str) -> Result<Self, Self::Err> { + parser::parse_value(s) + } +} + +impl<'b> From<&'b Value> for Value { + fn from(s: &'b Value) -> Self { + s.clone() + } +} + +impl<'b> From<&'b str> for Value { + fn from(s: &'b str) -> Self { + s.to_owned().into() + } +} + +impl<'b> From<&'b String> for Value { + fn from(s: &'b String) -> Self { + s.to_owned().into() + } +} + +impl From<String> for Value { + fn from(s: String) -> Self { + Value::String(Formatted::new(s)) + } +} + +impl<'b> From<&'b InternalString> for Value { + fn from(s: &'b InternalString) -> Self { + s.as_str().into() + } +} + +impl From<InternalString> for Value { + fn from(s: InternalString) -> Self { + s.as_str().into() + } +} + +impl From<i64> for Value { + fn from(i: i64) -> Self { + Value::Integer(Formatted::new(i)) + } +} + +impl From<f64> for Value { + fn from(f: f64) -> Self { + Value::Float(Formatted::new(f)) + } +} + +impl From<bool> for Value { + fn from(b: bool) -> Self { + Value::Boolean(Formatted::new(b)) + } +} + +impl From<Datetime> for Value { + fn from(d: Datetime) -> Self { + Value::Datetime(Formatted::new(d)) + } +} + +impl From<Date> for Value { + fn from(d: Date) -> Self { + let d: Datetime = d.into(); + d.into() + } +} + +impl From<Time> for Value { + fn from(d: Time) -> Self { + let d: Datetime = d.into(); + d.into() + } +} + +impl From<Array> for Value { + fn from(array: Array) -> Self { + Value::Array(array) + } +} + +impl From<InlineTable> for Value { + fn from(table: InlineTable) -> Self { + Value::InlineTable(table) + } +} + +impl<V: Into<Value>> FromIterator<V> for Value { + fn from_iter<I>(iter: I) -> Self + where + I: IntoIterator<Item = V>, + { + let array: Array = iter.into_iter().collect(); + Value::Array(array) + } +} + +impl<K: Into<Key>, V: Into<Value>> FromIterator<(K, V)> for Value { + fn from_iter<I>(iter: I) -> Self + where + I: IntoIterator<Item = (K, V)>, + { + let table: InlineTable = iter.into_iter().collect(); + Value::InlineTable(table) + } +} + +impl std::fmt::Display for Value { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + crate::encode::Encode::encode(self, f, None, ("", "")) + } +} + +// `key1 = value1` +pub(crate) const DEFAULT_VALUE_DECOR: (&str, &str) = (" ", ""); +// `{ key = value }` +pub(crate) const DEFAULT_TRAILING_VALUE_DECOR: (&str, &str) = (" ", " "); +// `[value1, value2]` +pub(crate) const DEFAULT_LEADING_VALUE_DECOR: (&str, &str) = ("", ""); + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn from_iter_formatting() { + let features = vec!["node".to_owned(), "mouth".to_owned()]; + let features: Value = features.iter().cloned().collect(); + assert_eq!(features.to_string(), r#"["node", "mouth"]"#); + } +} diff --git a/vendor/toml_edit-0.19.11/src/visit.rs b/vendor/toml_edit-0.19.11/src/visit.rs new file mode 100644 index 000000000..1bc640a88 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/visit.rs @@ -0,0 +1,236 @@ +#![allow(missing_docs)] + +//! Document tree traversal to walk a shared borrow of a document tree. +//! +//! Each method of the [`Visit`] trait is a hook that can be overridden +//! to customize the behavior when mutating the corresponding type of node. +//! By default, every method recursively visits the substructure of the +//! input by invoking the right visitor method of each of its fields. +//! +//! ``` +//! # use toml_edit::{Item, ArrayOfTables, Table, Value}; +//! +//! pub trait Visit<'doc> { +//! /* ... */ +//! +//! fn visit_item(&mut self, i: &'doc Item) { +//! visit_item(self, i); +//! } +//! +//! /* ... */ +//! # fn visit_value(&mut self, i: &'doc Value); +//! # fn visit_table(&mut self, i: &'doc Table); +//! # fn visit_array_of_tables(&mut self, i: &'doc ArrayOfTables); +//! } +//! +//! pub fn visit_item<'doc, V>(v: &mut V, node: &'doc Item) +//! where +//! V: Visit<'doc> + ?Sized, +//! { +//! match node { +//! Item::None => {} +//! Item::Value(value) => v.visit_value(value), +//! Item::Table(table) => v.visit_table(table), +//! Item::ArrayOfTables(array) => v.visit_array_of_tables(array), +//! } +//! } +//! ``` +//! +//! The API is modeled after [`syn::visit`](https://docs.rs/syn/1/syn/visit). +//! +//! # Examples +//! +//! This visitor stores every string in the document. +//! +//! ``` +//! # use toml_edit::*; +//! use toml_edit::visit::*; +//! +//! #[derive(Default)] +//! struct StringCollector<'doc> { +//! strings: Vec<&'doc str>, +//! } +//! +//! impl<'doc> Visit<'doc> for StringCollector<'doc> { +//! fn visit_string(&mut self, node: &'doc Formatted<String>) { +//! self.strings.push(node.value().as_str()); +//! } +//! } +//! +//! let input = r#" +//! laputa = "sky-castle" +//! the-force = { value = "surrounds-you" } +//! "#; +//! +//! let mut document: Document = input.parse().unwrap(); +//! let mut visitor = StringCollector::default(); +//! visitor.visit_document(&document); +//! +//! assert_eq!(visitor.strings, vec!["sky-castle", "surrounds-you"]); +//! ``` +//! +//! For a more complex example where the visitor has internal state, see `examples/visit.rs` +//! [on GitHub](https://github.com/ordian/toml_edit/blob/master/examples/visit.rs). + +use crate::{ + Array, ArrayOfTables, Datetime, Document, Formatted, InlineTable, Item, Table, TableLike, Value, +}; + +/// Document tree traversal to mutate an exclusive borrow of a document tree in-place. +/// +/// See the [module documentation](self) for details. +pub trait Visit<'doc> { + fn visit_document(&mut self, node: &'doc Document) { + visit_document(self, node); + } + + fn visit_item(&mut self, node: &'doc Item) { + visit_item(self, node); + } + + fn visit_table(&mut self, node: &'doc Table) { + visit_table(self, node); + } + + fn visit_inline_table(&mut self, node: &'doc InlineTable) { + visit_inline_table(self, node) + } + + fn visit_table_like(&mut self, node: &'doc dyn TableLike) { + visit_table_like(self, node); + } + + fn visit_table_like_kv(&mut self, key: &'doc str, node: &'doc Item) { + visit_table_like_kv(self, key, node); + } + + fn visit_array(&mut self, node: &'doc Array) { + visit_array(self, node); + } + + fn visit_array_of_tables(&mut self, node: &'doc ArrayOfTables) { + visit_array_of_tables(self, node); + } + + fn visit_value(&mut self, node: &'doc Value) { + visit_value(self, node); + } + + fn visit_boolean(&mut self, node: &'doc Formatted<bool>) { + visit_boolean(self, node) + } + + fn visit_datetime(&mut self, node: &'doc Formatted<Datetime>) { + visit_datetime(self, node); + } + + fn visit_float(&mut self, node: &'doc Formatted<f64>) { + visit_float(self, node) + } + + fn visit_integer(&mut self, node: &'doc Formatted<i64>) { + visit_integer(self, node) + } + + fn visit_string(&mut self, node: &'doc Formatted<String>) { + visit_string(self, node) + } +} + +pub fn visit_document<'doc, V>(v: &mut V, node: &'doc Document) +where + V: Visit<'doc> + ?Sized, +{ + v.visit_table(node.as_table()); +} + +pub fn visit_item<'doc, V>(v: &mut V, node: &'doc Item) +where + V: Visit<'doc> + ?Sized, +{ + match node { + Item::None => {} + Item::Value(value) => v.visit_value(value), + Item::Table(table) => v.visit_table(table), + Item::ArrayOfTables(array) => v.visit_array_of_tables(array), + } +} + +pub fn visit_table<'doc, V>(v: &mut V, node: &'doc Table) +where + V: Visit<'doc> + ?Sized, +{ + v.visit_table_like(node) +} + +pub fn visit_inline_table<'doc, V>(v: &mut V, node: &'doc InlineTable) +where + V: Visit<'doc> + ?Sized, +{ + v.visit_table_like(node) +} + +pub fn visit_table_like<'doc, V>(v: &mut V, node: &'doc dyn TableLike) +where + V: Visit<'doc> + ?Sized, +{ + for (key, item) in node.iter() { + v.visit_table_like_kv(key, item) + } +} + +pub fn visit_table_like_kv<'doc, V>(v: &mut V, _key: &'doc str, node: &'doc Item) +where + V: Visit<'doc> + ?Sized, +{ + v.visit_item(node) +} + +pub fn visit_array<'doc, V>(v: &mut V, node: &'doc Array) +where + V: Visit<'doc> + ?Sized, +{ + for value in node.iter() { + v.visit_value(value); + } +} + +pub fn visit_array_of_tables<'doc, V>(v: &mut V, node: &'doc ArrayOfTables) +where + V: Visit<'doc> + ?Sized, +{ + for table in node.iter() { + v.visit_table(table); + } +} + +pub fn visit_value<'doc, V>(v: &mut V, node: &'doc Value) +where + V: Visit<'doc> + ?Sized, +{ + match node { + Value::String(s) => v.visit_string(s), + Value::Integer(i) => v.visit_integer(i), + Value::Float(f) => v.visit_float(f), + Value::Boolean(b) => v.visit_boolean(b), + Value::Datetime(dt) => v.visit_datetime(dt), + Value::Array(array) => v.visit_array(array), + Value::InlineTable(table) => v.visit_inline_table(table), + } +} + +macro_rules! empty_visit { + ($name: ident, $t: ty) => { + fn $name<'doc, V>(_v: &mut V, _node: &'doc $t) + where + V: Visit<'doc> + ?Sized, + { + } + }; +} + +empty_visit!(visit_boolean, Formatted<bool>); +empty_visit!(visit_datetime, Formatted<Datetime>); +empty_visit!(visit_float, Formatted<f64>); +empty_visit!(visit_integer, Formatted<i64>); +empty_visit!(visit_string, Formatted<String>); diff --git a/vendor/toml_edit-0.19.11/src/visit_mut.rs b/vendor/toml_edit-0.19.11/src/visit_mut.rs new file mode 100644 index 000000000..2c2af9752 --- /dev/null +++ b/vendor/toml_edit-0.19.11/src/visit_mut.rs @@ -0,0 +1,252 @@ +#![allow(missing_docs)] + +//! Document tree traversal to mutate an exclusive borrow of a document tree in place. +//! +//! +//! Each method of the [`VisitMut`] trait is a hook that can be overridden +//! to customize the behavior when mutating the corresponding type of node. +//! By default, every method recursively visits the substructure of the +//! input by invoking the right visitor method of each of its fields. +//! +//! ``` +//! # use toml_edit::{Item, ArrayOfTables, Table, Value}; +//! +//! pub trait VisitMut { +//! /* ... */ +//! +//! fn visit_item_mut(&mut self, i: &mut Item) { +//! visit_item_mut(self, i); +//! } +//! +//! /* ... */ +//! # fn visit_value_mut(&mut self, i: &mut Value); +//! # fn visit_table_mut(&mut self, i: &mut Table); +//! # fn visit_array_of_tables_mut(&mut self, i: &mut ArrayOfTables); +//! } +//! +//! pub fn visit_item_mut<V>(v: &mut V, node: &mut Item) +//! where +//! V: VisitMut + ?Sized, +//! { +//! match node { +//! Item::None => {} +//! Item::Value(value) => v.visit_value_mut(value), +//! Item::Table(table) => v.visit_table_mut(table), +//! Item::ArrayOfTables(array) => v.visit_array_of_tables_mut(array), +//! } +//! } +//! ``` +//! +//! The API is modeled after [`syn::visit_mut`](https://docs.rs/syn/1/syn/visit_mut). +//! +//! # Examples +//! +//! This visitor replaces every floating point value with its decimal string representation, to +//! 2 decimal points. +//! +//! ``` +//! # use toml_edit::*; +//! use toml_edit::visit_mut::*; +//! +//! struct FloatToString; +//! +//! impl VisitMut for FloatToString { +//! fn visit_value_mut(&mut self, node: &mut Value) { +//! if let Value::Float(f) = node { +//! // Convert the float to a string. +//! let mut s = Formatted::new(format!("{:.2}", f.value())); +//! // Copy over the formatting. +//! std::mem::swap(s.decor_mut(), f.decor_mut()); +//! *node = Value::String(s); +//! } +//! // Most of the time, you will also need to call the default implementation to recurse +//! // further down the document tree. +//! visit_value_mut(self, node); +//! } +//! } +//! +//! let input = r#" +//! banana = 3.26 +//! table = { apple = 4.5 } +//! "#; +//! +//! let mut document: Document = input.parse().unwrap(); +//! let mut visitor = FloatToString; +//! visitor.visit_document_mut(&mut document); +//! +//! let output = r#" +//! banana = "3.26" +//! table = { apple = "4.50" } +//! "#; +//! +//! assert_eq!(format!("{}", document), output); +//! ``` +//! +//! For a more complex example where the visitor has internal state, see `examples/visit.rs` +//! [on GitHub](https://github.com/ordian/toml_edit/blob/master/examples/visit.rs). + +use crate::{ + Array, ArrayOfTables, Datetime, Document, Formatted, InlineTable, Item, KeyMut, Table, + TableLike, Value, +}; + +/// Document tree traversal to mutate an exclusive borrow of a document tree in-place. +/// +/// See the [module documentation](self) for details. +pub trait VisitMut { + fn visit_document_mut(&mut self, node: &mut Document) { + visit_document_mut(self, node); + } + + fn visit_item_mut(&mut self, node: &mut Item) { + visit_item_mut(self, node); + } + + fn visit_table_mut(&mut self, node: &mut Table) { + visit_table_mut(self, node); + } + + fn visit_inline_table_mut(&mut self, node: &mut InlineTable) { + visit_inline_table_mut(self, node) + } + + /// [`visit_table_mut`](Self::visit_table_mut) and + /// [`visit_inline_table_mut`](Self::visit_inline_table_mut) both recurse into this method. + fn visit_table_like_mut(&mut self, node: &mut dyn TableLike) { + visit_table_like_mut(self, node); + } + + fn visit_table_like_kv_mut(&mut self, key: KeyMut<'_>, node: &mut Item) { + visit_table_like_kv_mut(self, key, node); + } + + fn visit_array_mut(&mut self, node: &mut Array) { + visit_array_mut(self, node); + } + + fn visit_array_of_tables_mut(&mut self, node: &mut ArrayOfTables) { + visit_array_of_tables_mut(self, node); + } + + fn visit_value_mut(&mut self, node: &mut Value) { + visit_value_mut(self, node); + } + + fn visit_boolean_mut(&mut self, node: &mut Formatted<bool>) { + visit_boolean_mut(self, node) + } + + fn visit_datetime_mut(&mut self, node: &mut Formatted<Datetime>) { + visit_datetime_mut(self, node); + } + + fn visit_float_mut(&mut self, node: &mut Formatted<f64>) { + visit_float_mut(self, node) + } + + fn visit_integer_mut(&mut self, node: &mut Formatted<i64>) { + visit_integer_mut(self, node) + } + + fn visit_string_mut(&mut self, node: &mut Formatted<String>) { + visit_string_mut(self, node) + } +} + +pub fn visit_document_mut<V>(v: &mut V, node: &mut Document) +where + V: VisitMut + ?Sized, +{ + v.visit_table_mut(node.as_table_mut()); +} + +pub fn visit_item_mut<V>(v: &mut V, node: &mut Item) +where + V: VisitMut + ?Sized, +{ + match node { + Item::None => {} + Item::Value(value) => v.visit_value_mut(value), + Item::Table(table) => v.visit_table_mut(table), + Item::ArrayOfTables(array) => v.visit_array_of_tables_mut(array), + } +} + +pub fn visit_table_mut<V>(v: &mut V, node: &mut Table) +where + V: VisitMut + ?Sized, +{ + v.visit_table_like_mut(node); +} + +pub fn visit_inline_table_mut<V>(v: &mut V, node: &mut InlineTable) +where + V: VisitMut + ?Sized, +{ + v.visit_table_like_mut(node); +} + +pub fn visit_table_like_mut<V>(v: &mut V, node: &mut dyn TableLike) +where + V: VisitMut + ?Sized, +{ + for (key, item) in node.iter_mut() { + v.visit_table_like_kv_mut(key, item); + } +} + +pub fn visit_table_like_kv_mut<V>(v: &mut V, _key: KeyMut<'_>, node: &mut Item) +where + V: VisitMut + ?Sized, +{ + v.visit_item_mut(node) +} + +pub fn visit_array_mut<V>(v: &mut V, node: &mut Array) +where + V: VisitMut + ?Sized, +{ + for value in node.iter_mut() { + v.visit_value_mut(value); + } +} + +pub fn visit_array_of_tables_mut<V>(v: &mut V, node: &mut ArrayOfTables) +where + V: VisitMut + ?Sized, +{ + for table in node.iter_mut() { + v.visit_table_mut(table); + } +} + +pub fn visit_value_mut<V>(v: &mut V, node: &mut Value) +where + V: VisitMut + ?Sized, +{ + match node { + Value::String(s) => v.visit_string_mut(s), + Value::Integer(i) => v.visit_integer_mut(i), + Value::Float(f) => v.visit_float_mut(f), + Value::Boolean(b) => v.visit_boolean_mut(b), + Value::Datetime(dt) => v.visit_datetime_mut(dt), + Value::Array(array) => v.visit_array_mut(array), + Value::InlineTable(table) => v.visit_inline_table_mut(table), + } +} + +macro_rules! empty_visit_mut { + ($name: ident, $t: ty) => { + fn $name<V>(_v: &mut V, _node: &mut $t) + where + V: VisitMut + ?Sized, + { + } + }; +} + +empty_visit_mut!(visit_boolean_mut, Formatted<bool>); +empty_visit_mut!(visit_datetime_mut, Formatted<Datetime>); +empty_visit_mut!(visit_float_mut, Formatted<f64>); +empty_visit_mut!(visit_integer_mut, Formatted<i64>); +empty_visit_mut!(visit_string_mut, Formatted<String>); |