Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

461
vendor/toml_edit-0.22.27/src/array.rs vendored Normal file
View File

@@ -0,0 +1,461 @@
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};
/// A TOML [`Value`] that contains a sequence of [`Value`]s
#[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 [`Array`]'s [`Value`]s
pub type ArrayIntoIter = Box<dyn Iterator<Item = Value>>;
/// An iterator type over [`Array`]'s [`Value`]s
pub type ArrayIter<'a> = Box<dyn Iterator<Item = &'a Value> + 'a>;
/// An iterator type over [`Array`]'s [`Value`]s
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
}
/// The location within the original document
///
/// This generally requires an [`ImDocument`][crate::ImDocument].
pub 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 if `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
/// # #[cfg(feature = "parse")] {
/// 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
/// # #[cfg(feature = "parse")] {
/// 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
/// # #[cfg(feature = "parse")] {
/// 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 {x:?} in an array"),
}
}
/// 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 {x:?} in an array"),
}
}
/// Retains only the values specified by the `keep` predicate.
///
/// In other words, remove all values for which `keep(&value)` returns `false`.
///
/// This method operates in place, visiting each element exactly once in the
/// original order, and preserves the order of the retained elements.
pub fn retain<F>(&mut self, mut keep: F)
where
F: FnMut(&Value) -> bool,
{
self.values
.retain(|item| item.as_value().map(&mut keep).unwrap_or(false));
}
/// Sorts the slice with a comparator function.
///
/// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) worst-case.
///
/// The comparator function must define a total ordering for the elements in the slice. If
/// the ordering is not total, the order of the elements is unspecified. An order is a
/// total order if it is (for all `a`, `b` and `c`):
///
/// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and
/// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
///
/// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use
/// `partial_cmp` as our sort function when we know the slice doesn't contain a `NaN`.
#[inline]
pub fn sort_by<F>(&mut self, mut compare: F)
where
F: FnMut(&Value, &Value) -> std::cmp::Ordering,
{
self.values.sort_by(move |lhs, rhs| {
let lhs = lhs.as_value();
let rhs = rhs.as_value();
match (lhs, rhs) {
(None, None) => std::cmp::Ordering::Equal,
(Some(_), None) => std::cmp::Ordering::Greater,
(None, Some(_)) => std::cmp::Ordering::Less,
(Some(lhs), Some(rhs)) => compare(lhs, rhs),
}
});
}
/// Sorts the array with a key extraction function.
///
/// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*))
/// worst-case, where the key function is *O*(*m*).
#[inline]
pub fn sort_by_key<K, F>(&mut self, mut f: F)
where
F: FnMut(&Value) -> K,
K: Ord,
{
#[allow(clippy::manual_map)] // needed for lifetimes
self.values.sort_by_key(move |item| {
if let Some(value) = item.as_value() {
Some(f(value))
} else {
None
}
});
}
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)
}
}
#[cfg(feature = "display")]
impl std::fmt::Display for Array {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
crate::encode::encode_array(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("");
}

View File

@@ -0,0 +1,169 @@
use std::iter::FromIterator;
use crate::{Array, Item, Table};
/// A top-level sequence of [`Table`]s, each under their own header
#[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
}
/// The location within the original document
///
/// This generally requires an [`ImDocument`][crate::ImDocument].
pub 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 if `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);
}
/// Retains only the elements specified by the `keep` predicate.
///
/// In other words, remove all tables for which `keep(&table)` returns `false`.
///
/// This method operates in place, visiting each element exactly once in the
/// original order, and preserves the order of the retained elements.
pub fn retain<F>(&mut self, mut keep: F)
where
F: FnMut(&Table) -> bool,
{
self.values
.retain(|item| item.as_table().map(&mut keep).unwrap_or(false));
}
}
/// An iterator type over [`ArrayOfTables`]'s [`Table`]s
pub type ArrayOfTablesIter<'a> = Box<dyn Iterator<Item = &'a Table> + 'a>;
/// An iterator type over [`ArrayOfTables`]'s [`Table`]s
pub type ArrayOfTablesIterMut<'a> = Box<dyn Iterator<Item = &'a mut Table> + 'a>;
/// An iterator type over [`ArrayOfTables`]'s [`Table`]s
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()
}
}
#[cfg(feature = "display")]
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)
}
}

View File

@@ -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 serde::de::IntoDeserializer<'_, 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),
}
}
}

View File

@@ -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")
}
}
}

151
vendor/toml_edit-0.22.27/src/de/key.rs vendored Normal file
View File

@@ -0,0 +1,151 @@
use serde::de::IntoDeserializer;
use super::Error;
pub(crate) struct KeyDeserializer {
span: Option<std::ops::Range<usize>>,
key: crate::Key,
}
impl KeyDeserializer {
pub(crate) fn new(key: crate::Key, span: Option<std::ops::Range<usize>>) -> Self {
KeyDeserializer { span, key }
}
}
impl IntoDeserializer<'_, 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.get(), span));
}
}
self.deserialize_any(visitor)
}
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)
}
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
ignored_any unit_struct tuple_struct tuple identifier
}
}
impl<'de> serde::de::EnumAccess<'de> for KeyDeserializer {
type Error = 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",
))
}
}

327
vendor/toml_edit-0.22.27/src/de/mod.rs vendored Normal file
View File

@@ -0,0 +1,327 @@
//! 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_enum::TableEnumDeserializer;
pub use value::ValueDeserializer;
/// Errors that can occur when deserializing a type.
#[derive(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 std::fmt::Debug 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 TOML [documents][crate::DocumentMut] into `T`.
#[cfg(feature = "parse")]
pub fn from_str<T>(s: &'_ str) -> Result<T, Error>
where
T: DeserializeOwned,
{
let de = Deserializer::parse(s)?;
T::deserialize(de)
}
/// Convert a TOML [documents][crate::DocumentMut] into `T`.
#[cfg(feature = "parse")]
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 [`DocumentMut`][crate::DocumentMut] into `T`.
pub fn from_document<T>(d: impl Into<Deserializer>) -> Result<T, Error>
where
T: DeserializeOwned,
{
let deserializer = d.into();
T::deserialize(deserializer)
}
/// Deserialization for TOML [documents][crate::DocumentMut].
pub struct Deserializer<S = String> {
root: crate::Item,
raw: Option<S>,
}
impl Deserializer {
/// Deserialization implementation for TOML.
#[deprecated(since = "0.22.6", note = "Replaced with `Deserializer::from`")]
pub fn new(input: crate::DocumentMut) -> Self {
Self::from(input)
}
}
#[cfg(feature = "parse")]
impl<S: AsRef<str>> Deserializer<S> {
/// Parse a TOML document
pub fn parse(raw: S) -> Result<Self, Error> {
crate::ImDocument::parse(raw)
.map(Self::from)
.map_err(Into::into)
}
}
impl From<crate::DocumentMut> for Deserializer {
fn from(doc: crate::DocumentMut) -> Self {
let crate::DocumentMut { root, .. } = doc;
Self { root, raw: None }
}
}
impl<S> From<crate::ImDocument<S>> for Deserializer<S> {
fn from(doc: crate::ImDocument<S>) -> Self {
let crate::ImDocument { root, raw, .. } = doc;
let raw = Some(raw);
Self { root, raw }
}
}
#[cfg(feature = "parse")]
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 doc: crate::ImDocument<_> = s.parse().map_err(Error::from)?;
Ok(Deserializer::from(doc))
}
}
// Note: this is wrapped by `toml::de::Deserializer` and any trait methods
// implemented here need to be wrapped there
impl<'de, S: Into<String>> serde::Deserializer<'de> for Deserializer<S> {
type Error = Error;
fn deserialize_any<V>(self, visitor: V) -> Result<V::Value, Self::Error>
where
V: serde::de::Visitor<'de>,
{
let raw = self.raw;
self.root
.into_deserializer()
.deserialize_any(visitor)
.map_err(|mut e: Self::Error| {
e.inner.set_raw(raw.map(|r| r.into()));
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 raw = self.raw;
self.root
.into_deserializer()
.deserialize_option(visitor)
.map_err(|mut e: Self::Error| {
e.inner.set_raw(raw.map(|r| r.into()));
e
})
}
fn deserialize_newtype_struct<V>(
self,
name: &'static str,
visitor: V,
) -> Result<V::Value, Error>
where
V: serde::de::Visitor<'de>,
{
let raw = self.raw;
self.root
.into_deserializer()
.deserialize_newtype_struct(name, visitor)
.map_err(|mut e: Self::Error| {
e.inner.set_raw(raw.map(|r| r.into()));
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 raw = self.raw;
self.root
.into_deserializer()
.deserialize_struct(name, fields, visitor)
.map_err(|mut e: Self::Error| {
e.inner.set_raw(raw.map(|r| r.into()));
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 raw = self.raw;
self.root
.into_deserializer()
.deserialize_enum(name, variants, visitor)
.map_err(|mut e: Self::Error| {
e.inner.set_raw(raw.map(|r| r.into()));
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 serde::de::IntoDeserializer<'_, Error> for Deserializer {
type Deserializer = Deserializer;
fn into_deserializer(self) -> Self::Deserializer {
self
}
}
impl serde::de::IntoDeserializer<'_, Error> for crate::DocumentMut {
type Deserializer = Deserializer;
fn into_deserializer(self) -> Self::Deserializer {
Deserializer::from(self)
}
}
impl serde::de::IntoDeserializer<'_, Error> for crate::ImDocument<String> {
type Deserializer = Deserializer;
fn into_deserializer(self) -> Self::Deserializer {
Deserializer::from(self)
}
}
pub(crate) fn validate_struct_keys(
table: &crate::table::KeyValuePairs,
fields: &'static [&'static str],
) -> Result<(), Error> {
let extra_fields = table
.keys()
.filter_map(|key| {
if !fields.contains(&key.get()) {
Some(key.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.get())
.collect::<Vec<_>>()
.join(", "),
fields.join(", "),
),
extra_fields[0].span(),
))
}
}

View File

@@ -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")
}
}
}

214
vendor/toml_edit-0.22.27/src/de/table.rs vendored Normal file
View File

@@ -0,0 +1,214 @@
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(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(Error::custom(
"wanted exactly 1 element, found 0 elements",
self.span,
))
} else if self.items.len() != 1 {
Err(Error::custom(
"wanted exactly 1 element, more than 1 element",
self.span,
))
} else {
visitor.visit_enum(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 IntoDeserializer<'_, 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::Key, crate::Item>,
span: Option<std::ops::Range<usize>>,
value: Option<(crate::Key, 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 key_span = k.span();
let ret = seed
.deserialize(super::KeyDeserializer::new(k.clone(), key_span.clone()))
.map(Some)
.map_err(|mut e: Self::Error| {
if e.span().is_none() {
e.set_span(key_span);
}
e
});
self.value = Some((k, v));
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().or_else(|| k.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.get().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(key.span());
}
e
})?;
let variant = super::TableEnumDeserializer::new(value);
Ok((val, variant))
}
}

View File

@@ -0,0 +1,176 @@
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::ArrayOfTables(values) => {
if values.is_empty() {
Ok(())
} else {
Err(Error::custom("expected empty array", values.span()))
}
}
crate::Item::Value(crate::Value::Array(values)) => {
if values.is_empty() {
Ok(())
} else {
Err(Error::custom("expected empty table", values.span()))
}
}
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::ArrayOfTables(values) => {
let values_span = values.span();
let tuple_values = values.values.into_iter().collect::<Vec<_>>();
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::Array(values)) => {
let values_span = values.span();
let tuple_values = values.values.into_iter().collect::<Vec<_>>();
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::Table(values) => {
let values_span = values.span();
let tuple_values: Result<Vec<_>, _> = values
.items
.into_iter()
.enumerate()
.map(|(index, (key, value))| match key.get().parse::<usize>() {
Ok(key_index) if key_index == index => Ok(value),
Ok(_) | Err(_) => Err(Error::custom(
format!("expected table key `{}`, but was `{}`", index, key.get()),
key.span(),
)),
})
.collect();
let tuple_values = tuple_values?;
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: Result<Vec<_>, _> = values
.items
.into_iter()
.enumerate()
.map(|(index, (key, value))| match key.get().parse::<usize>() {
Ok(key_index) if key_index == index => Ok(value),
Ok(_) | Err(_) => Err(Error::custom(
format!("expected table key `{}`, but was `{}`", index, key.get()),
key.span(),
)),
})
.collect();
let tuple_values = tuple_values?;
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,
)
}
}

257
vendor/toml_edit-0.22.27/src/de/value.rs vendored Normal file
View File

@@ -0,0 +1,257 @@
use serde::de::IntoDeserializer as _;
use crate::de::DatetimeDeserializer;
use crate::de::Error;
/// Deserialization implementation for TOML [values][crate::Value].
///
/// Can be created either directly from TOML strings, using [`std::str::FromStr`],
/// or from parsed [values][crate::Value] using [`serde::de::IntoDeserializer::into_deserializer`].
///
/// # Example
///
/// ```
/// # #[cfg(feature = "parse")] {
/// # #[cfg(feature = "display")] {
/// 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(Error::custom(
"wanted exactly 1 element, found 0 elements",
v.span(),
))
} else if v.len() != 1 {
Err(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(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 serde::de::IntoDeserializer<'_, Error> for ValueDeserializer {
type Deserializer = Self;
fn into_deserializer(self) -> Self::Deserializer {
self
}
}
impl serde::de::IntoDeserializer<'_, 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)
}
}
#[cfg(feature = "parse")]
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 value = s.parse::<crate::Value>().map_err(Error::from)?;
Ok(value.into_deserializer())
}
}

235
vendor/toml_edit-0.22.27/src/document.rs vendored Normal file
View File

@@ -0,0 +1,235 @@
use std::str::FromStr;
use crate::table::Iter;
use crate::{Item, RawString, Table};
/// The root TOML [`Table`], containing [`Key`][crate::Key]/[`Value`][crate::Value] pairs and all other logic [`Table`]s
#[derive(Debug, Clone)]
pub struct ImDocument<S> {
pub(crate) root: Item,
// Trailing comments and whitespaces
pub(crate) trailing: RawString,
pub(crate) raw: S,
}
impl ImDocument<&'static str> {
/// Creates an empty document
pub fn new() -> Self {
Default::default()
}
}
#[cfg(feature = "parse")]
impl<S: AsRef<str>> ImDocument<S> {
/// Parse a TOML document
pub fn parse(raw: S) -> Result<Self, crate::TomlError> {
crate::parser::parse_document(raw)
}
}
impl<S: AsRef<str>> ImDocument<S> {
/// # Panics
///
/// If run on a [`DocumentMut`] not generated by the parser
pub(crate) fn despan(&mut self) {
self.root.despan(self.raw.as_ref());
self.trailing.despan(self.raw.as_ref());
}
}
impl<S> ImDocument<S> {
/// Returns a reference to the root item.
pub fn as_item(&self) -> &Item {
&self.root
}
/// Returns the root item.
pub fn into_item(self) -> Item {
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 the root table.
pub fn into_table(self) -> Table {
self.root
.into_table()
.expect("root should always be a table")
}
/// Returns an iterator over the root table.
pub fn iter(&self) -> Iter<'_> {
self.as_table().iter()
}
/// Whitespace after last element
pub fn trailing(&self) -> &RawString {
&self.trailing
}
}
impl<S: AsRef<str>> ImDocument<S> {
/// Access the raw, unparsed document
pub fn raw(&self) -> &str {
self.raw.as_ref()
}
}
impl<S: AsRef<str>> ImDocument<S> {
/// Allow editing of the [`DocumentMut`]
pub fn into_mut(mut self) -> DocumentMut {
self.despan();
DocumentMut {
root: self.root,
trailing: self.trailing,
}
}
}
impl Default for ImDocument<&'static str> {
fn default() -> Self {
Self {
root: Item::Table(Table::with_pos(Some(0))),
trailing: Default::default(),
raw: "",
}
}
}
#[cfg(feature = "parse")]
impl FromStr for ImDocument<String> {
type Err = crate::TomlError;
/// Parses a document from a &str
fn from_str(s: &str) -> Result<Self, Self::Err> {
Self::parse(s.to_owned())
}
}
impl<S> std::ops::Deref for ImDocument<S> {
type Target = Table;
fn deref(&self) -> &Self::Target {
self.as_table()
}
}
/// The editable root TOML [`Table`], containing [`Key`][crate::Key]/[`Value`][crate::Value] pairs and all other logic [`Table`]s
#[derive(Debug, Clone)]
pub struct DocumentMut {
pub(crate) root: Item,
// Trailing comments and whitespaces
pub(crate) trailing: RawString,
}
impl DocumentMut {
/// 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 the root item.
pub fn into_item(self) -> Item {
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 the root table.
pub fn into_table(self) -> Table {
self.root
.into_table()
.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
}
}
impl Default for DocumentMut {
fn default() -> Self {
Self {
root: Item::Table(Table::with_pos(Some(0))),
trailing: Default::default(),
}
}
}
#[cfg(feature = "parse")]
impl FromStr for DocumentMut {
type Err = crate::TomlError;
/// Parses a document from a &str
fn from_str(s: &str) -> Result<Self, Self::Err> {
let im = ImDocument::from_str(s)?;
Ok(im.into_mut())
}
}
impl std::ops::Deref for DocumentMut {
type Target = Table;
fn deref(&self) -> &Self::Target {
self.as_table()
}
}
impl std::ops::DerefMut for DocumentMut {
fn deref_mut(&mut self) -> &mut Self::Target {
self.as_table_mut()
}
}
impl From<Table> for DocumentMut {
fn from(root: Table) -> Self {
Self {
root: Item::Table(root),
..Default::default()
}
}
}
#[test]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
fn default_roundtrip() {
DocumentMut::default()
.to_string()
.parse::<DocumentMut>()
.unwrap();
}

410
vendor/toml_edit-0.22.27/src/encode.rs vendored Normal file
View File

@@ -0,0 +1,410 @@
use std::borrow::Cow;
use std::fmt::{Display, Formatter, Result, Write};
use toml_datetime::Datetime;
use toml_write::ToTomlValue as _;
use toml_write::TomlWrite as _;
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_ROOT_DECOR, DEFAULT_TABLE_DECOR,
};
use crate::value::{
DEFAULT_LEADING_VALUE_DECOR, DEFAULT_TRAILING_VALUE_DECOR, DEFAULT_VALUE_DECOR,
};
use crate::DocumentMut;
use crate::{Array, InlineTable, Item, Table, Value};
pub(crate) fn encode_key(this: &Key, buf: &mut dyn Write, input: Option<&str>) -> Result {
if let Some(input) = input {
let repr = this
.as_repr()
.map(Cow::Borrowed)
.unwrap_or_else(|| Cow::Owned(this.default_repr()));
repr.encode(buf, input)?;
} else {
let repr = this.display_repr();
write!(buf, "{repr}")?;
};
Ok(())
}
fn encode_key_path(
this: &[Key],
mut buf: &mut dyn Write,
input: Option<&str>,
default_decor: (&str, &str),
) -> Result {
let leaf_decor = this.last().expect("always at least one key").leaf_decor();
for (i, key) in this.iter().enumerate() {
let dotted_decor = key.dotted_decor();
let first = i == 0;
let last = i + 1 == this.len();
if first {
leaf_decor.prefix_encode(buf, input, default_decor.0)?;
} else {
buf.key_sep()?;
dotted_decor.prefix_encode(buf, input, DEFAULT_KEY_PATH_DECOR.0)?;
}
encode_key(key, buf, input)?;
if last {
leaf_decor.suffix_encode(buf, input, default_decor.1)?;
} else {
dotted_decor.suffix_encode(buf, input, DEFAULT_KEY_PATH_DECOR.1)?;
}
}
Ok(())
}
pub(crate) fn encode_key_path_ref(
this: &[&Key],
mut buf: &mut dyn Write,
input: Option<&str>,
default_decor: (&str, &str),
) -> Result {
let leaf_decor = this.last().expect("always at least one key").leaf_decor();
for (i, key) in this.iter().enumerate() {
let dotted_decor = key.dotted_decor();
let first = i == 0;
let last = i + 1 == this.len();
if first {
leaf_decor.prefix_encode(buf, input, default_decor.0)?;
} else {
buf.key_sep()?;
dotted_decor.prefix_encode(buf, input, DEFAULT_KEY_PATH_DECOR.0)?;
}
encode_key(key, buf, input)?;
if last {
leaf_decor.suffix_encode(buf, input, default_decor.1)?;
} else {
dotted_decor.suffix_encode(buf, input, DEFAULT_KEY_PATH_DECOR.1)?;
}
}
Ok(())
}
pub(crate) fn encode_formatted<T: ValueRepr>(
this: &Formatted<T>,
buf: &mut dyn Write,
input: Option<&str>,
default_decor: (&str, &str),
) -> Result {
let decor = this.decor();
decor.prefix_encode(buf, input, default_decor.0)?;
if let Some(input) = input {
let repr = this
.as_repr()
.map(Cow::Borrowed)
.unwrap_or_else(|| Cow::Owned(this.default_repr()));
repr.encode(buf, input)?;
} else {
let repr = this.display_repr();
write!(buf, "{repr}")?;
};
decor.suffix_encode(buf, input, default_decor.1)?;
Ok(())
}
pub(crate) fn encode_array(
this: &Array,
mut buf: &mut dyn Write,
input: Option<&str>,
default_decor: (&str, &str),
) -> Result {
let decor = this.decor();
decor.prefix_encode(buf, input, default_decor.0)?;
buf.open_array()?;
for (i, elem) in this.iter().enumerate() {
let inner_decor;
if i == 0 {
inner_decor = DEFAULT_LEADING_VALUE_DECOR;
} else {
inner_decor = DEFAULT_VALUE_DECOR;
buf.val_sep()?;
}
encode_value(elem, buf, input, inner_decor)?;
}
if this.trailing_comma() && !this.is_empty() {
buf.val_sep()?;
}
this.trailing().encode_with_default(buf, input, "")?;
buf.close_array()?;
decor.suffix_encode(buf, input, default_decor.1)?;
Ok(())
}
pub(crate) fn encode_table(
this: &InlineTable,
mut buf: &mut dyn Write,
input: Option<&str>,
default_decor: (&str, &str),
) -> Result {
let decor = this.decor();
decor.prefix_encode(buf, input, default_decor.0)?;
buf.open_inline_table()?;
this.preamble().encode_with_default(buf, input, "")?;
let children = this.get_values();
let len = children.len();
for (i, (key_path, value)) in children.into_iter().enumerate() {
if i != 0 {
buf.val_sep()?;
}
let inner_decor = if i == len - 1 {
DEFAULT_TRAILING_VALUE_DECOR
} else {
DEFAULT_VALUE_DECOR
};
encode_key_path_ref(&key_path, buf, input, DEFAULT_INLINE_KEY_DECOR)?;
buf.keyval_sep()?;
encode_value(value, buf, input, inner_decor)?;
}
buf.close_inline_table()?;
decor.suffix_encode(buf, input, default_decor.1)?;
Ok(())
}
pub(crate) fn encode_value(
this: &Value,
buf: &mut dyn Write,
input: Option<&str>,
default_decor: (&str, &str),
) -> Result {
match this {
Value::String(repr) => encode_formatted(repr, buf, input, default_decor),
Value::Integer(repr) => encode_formatted(repr, buf, input, default_decor),
Value::Float(repr) => encode_formatted(repr, buf, input, default_decor),
Value::Boolean(repr) => encode_formatted(repr, buf, input, default_decor),
Value::Datetime(repr) => encode_formatted(repr, buf, input, default_decor),
Value::Array(array) => encode_array(array, buf, input, default_decor),
Value::InlineTable(table) => encode_table(table, buf, input, default_decor),
}
}
impl Display for DocumentMut {
fn fmt(&self, f: &mut Formatter<'_>) -> Result {
let decor = self.decor();
decor.prefix_encode(f, None, DEFAULT_ROOT_DECOR.0)?;
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, None, table, &path, is_array, &mut first_table)?;
}
decor.suffix_encode(f, None, DEFAULT_ROOT_DECOR.1)?;
self.trailing().encode_with_default(f, None, "")
}
}
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 (key, value) in table.items.iter() {
match value {
Item::Table(ref t) => {
let key = key.clone();
path.push(key);
visit_nested_tables(t, path, false, callback)?;
path.pop();
}
Item::ArrayOfTables(ref a) => {
for t in a.iter() {
let key = key.clone();
path.push(key);
visit_nested_tables(t, path, true, callback)?;
path.pop();
}
}
_ => {}
}
}
Ok(())
}
fn visit_table(
mut 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)?;
buf.open_array_of_tables_header()?;
encode_key_path(path, buf, input, DEFAULT_KEY_PATH_DECOR)?;
buf.close_array_of_tables_header()?;
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)?;
buf.open_table_header()?;
encode_key_path(path, buf, input, DEFAULT_KEY_PATH_DECOR)?;
buf.close_table_header()?;
table.decor.suffix_encode(buf, input, default_decor.1)?;
writeln!(buf)?;
}
// print table body
for (key_path, value) in children {
encode_key_path_ref(&key_path, buf, input, DEFAULT_KEY_DECOR)?;
buf.keyval_sep()?;
encode_value(value, buf, input, DEFAULT_VALUE_DECOR)?;
writeln!(buf)?;
}
Ok(())
}
impl ValueRepr for String {
fn to_repr(&self) -> Repr {
let output = toml_write::TomlStringBuilder::new(self.as_str())
.as_default()
.to_toml_value();
Repr::new_unchecked(output)
}
}
impl ValueRepr for i64 {
fn to_repr(&self) -> Repr {
let repr = self.to_toml_value();
Repr::new_unchecked(repr)
}
}
impl ValueRepr for f64 {
fn to_repr(&self) -> Repr {
let repr = self.to_toml_value();
Repr::new_unchecked(repr)
}
}
impl ValueRepr for bool {
fn to_repr(&self) -> Repr {
let repr = self.to_toml_value();
Repr::new_unchecked(repr)
}
}
impl ValueRepr for Datetime {
fn to_repr(&self) -> Repr {
Repr::new_unchecked(self.to_string())
}
}
#[cfg(test)]
mod test {
use super::*;
use proptest::prelude::*;
proptest! {
#[test]
#[cfg(feature = "parse")]
fn parseable_string(string in "\\PC*") {
let value = Value::from(string.clone());
let encoded = value.to_string();
let _: Value = encoded.parse().unwrap_or_else(|err| {
panic!("error: {err}
string:
```
{string}
```
value:
```
{value}
```
")
});
}
}
proptest! {
#[test]
#[cfg(feature = "parse")]
fn parseable_key(string in "\\PC*") {
let key = Key::new(string.clone());
let encoded = key.to_string();
let _: Key = encoded.parse().unwrap_or_else(|err| {
panic!("error: {err}
string:
```
{string}
```
key:
```
{key}
```
")
});
}
}
}

239
vendor/toml_edit-0.22.27/src/error.rs vendored Normal file
View File

@@ -0,0 +1,239 @@
use std::error::Error as StdError;
use std::fmt::{Display, Formatter, Result};
/// A TOML parse error
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct TomlError {
message: String,
raw: Option<String>,
keys: Vec<String>,
span: Option<std::ops::Range<usize>>,
}
impl TomlError {
#[cfg(feature = "parse")]
pub(crate) fn new(
error: winnow::error::ParseError<
crate::parser::prelude::Input<'_>,
winnow::error::ContextError,
>,
mut raw: crate::parser::prelude::Input<'_>,
) -> Self {
use winnow::stream::Stream;
let message = error.inner().to_string();
let raw = raw.finish();
let raw = String::from_utf8(raw.to_owned()).expect("original document was utf8");
let span = error.char_span();
Self {
message,
raw: Some(raw),
keys: Vec::new(),
span: Some(span),
}
}
#[cfg(any(feature = "serde", feature = "parse"))]
pub(crate) fn custom(message: String, span: Option<std::ops::Range<usize>>) -> Self {
Self {
message,
raw: 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_raw(&mut self, raw: Option<String>) {
self.raw = raw;
}
}
/// 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(raw), Some(span)) = (&self.raw, self.span()) {
context = true;
let (line, column) = translate_position(raw.as_bytes(), span.start);
let line_num = line + 1;
let col_num = column + 1;
let gutter = line_num.to_string().len();
let content = raw.split('\n').nth(line).expect("valid line number");
let highlight_len = span.end - span.start;
// Allow highlight to go one past the line
let highlight_len = highlight_len.min(content.len().saturating_sub(column));
writeln!(f, "TOML parse error at line {line_num}, column {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 1..highlight_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"
}
}
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 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));
}
}

142
vendor/toml_edit-0.22.27/src/index.rs vendored Normal file
View File

@@ -0,0 +1,142 @@
use std::ops;
use crate::key::Key;
use crate::DocumentMut;
use crate::{value, InlineTable, 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(|value| if !value.is_none() { Some(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(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| t.items.entry(Key::new(self)).or_insert_with(|| Item::None)),
_ => 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<T: ?Sized> Index for &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 DocumentMut {
type Output = Item;
fn index(&self, key: &'s str) -> &Item {
self.root.index(key)
}
}
impl<'s> ops::IndexMut<&'s str> for DocumentMut {
fn index_mut(&mut self, key: &'s str) -> &mut Item {
self.root.index_mut(key)
}
}

View File

@@ -0,0 +1,756 @@
use std::iter::FromIterator;
use crate::key::Key;
use crate::repr::Decor;
use crate::table::{Iter, IterMut, KeyValuePairs, TableLike};
use crate::{InternalString, Item, KeyMut, RawString, Table, Value};
/// A TOML [`Value`] that contains a collection of [`Key`]/[`Value`] pairs
#[derive(Debug, Default, Clone)]
pub struct InlineTable {
// `preamble` represents whitespaces in an empty table
preamble: RawString,
// Whether to hide an empty table
pub(crate) implicit: bool,
// 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>(
&'s self,
parent: &[&'s Key],
values: &mut Vec<(Vec<&'s Key>, &'s Value)>,
) {
for (key, value) in self.items.iter() {
let mut path = parent.to_vec();
path.push(key);
match 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 [Key]/[Value]-pairs of the table
///
/// <div class="warning">
///
/// This is not recursive.
///
/// </div>
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 value in self.items.values_mut() {
match 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).
///
/// <div class="warning">
///
/// This is not recursive.
///
/// </div>
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 =
|key1: &Key, val1: &Item, key2: &Key, val2: &Item| -> std::cmp::Ordering {
match (val1.as_value(), val2.as_value()) {
(Some(v1), Some(v2)) => compare(key1, v1, key2, 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 value in self.items.values_mut() {
match value {
Item::Value(Value::InlineTable(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.
///
/// ```
/// # #[cfg(feature = "parse")] {
/// # #[cfg(feature = "display")] {
/// use toml_edit::DocumentMut;
/// let mut doc = "[a]\n[a.b]\n".parse::<DocumentMut>().expect("invalid toml");
///
/// doc["a"].as_table_mut().unwrap().set_implicit(true);
/// assert_eq!(doc.to_string(), "[a.b]\n");
/// # }
/// # }
/// ```
pub(crate) 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(crate) 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
}
/// 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 an accessor to a key's formatting
pub fn key(&self, key: &str) -> Option<&'_ Key> {
self.items.get_full(key).map(|(_, key, _)| key)
}
/// Returns an accessor to a key's formatting
pub fn key_mut(&mut self, key: &str) -> Option<KeyMut<'_>> {
use indexmap::map::MutableKeys;
self.items
.get_full_mut2(key)
.map(|(_, key, _)| key.as_mut())
}
/// Returns the decor associated with a given key of the table.
#[deprecated(since = "0.21.1", note = "Replaced with `key_mut`")]
pub fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> {
#![allow(deprecated)]
use indexmap::map::MutableKeys;
self.items
.get_full_mut2(key)
.map(|(_, key, _)| key.leaf_decor_mut())
}
/// Returns the decor associated with a given key of the table.
#[deprecated(since = "0.21.1", note = "Replaced with `key_mut`")]
pub fn key_decor(&self, key: &str) -> Option<&Decor> {
#![allow(deprecated)]
self.items.get_full(key).map(|(_, key, _)| key.leaf_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
}
/// The location within the original document
///
/// This generally requires an [`ImDocument`][crate::ImDocument].
pub fn span(&self) -> Option<std::ops::Range<usize>> {
self.span.clone()
}
pub(crate) fn despan(&mut self, input: &str) {
use indexmap::map::MutableKeys;
self.span = None;
self.decor.despan(input);
self.preamble.despan(input);
for (key, value) in self.items.iter_mut2() {
key.despan(input);
value.despan(input);
}
}
}
impl InlineTable {
/// Returns an iterator over key/value pairs.
pub fn iter(&self) -> InlineTableIter<'_> {
Box::new(
self.items
.iter()
.filter(|(_, value)| !value.is_none())
.map(|(key, value)| (key.get(), value.as_value().unwrap())),
)
}
/// Returns an iterator over key/value pairs.
pub fn iter_mut(&mut self) -> InlineTableIterMut<'_> {
use indexmap::map::MutableKeys;
Box::new(
self.items
.iter_mut2()
.filter(|(_, value)| value.is_value())
.map(|(key, value)| (key.as_mut(), value.as_value_mut().unwrap())),
)
}
/// Returns the number of key/value pairs.
pub fn len(&self) -> usize {
self.iter().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(&'_ mut self, key: impl Into<InternalString>) -> InlineEntry<'_> {
match self.items.entry(key.into().into()) {
indexmap::map::Entry::Occupied(mut entry) => {
// Ensure it is a `Value` to simplify `InlineOccupiedEntry`'s code.
let scratch = std::mem::take(entry.get_mut());
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() = scratch;
InlineEntry::Occupied(InlineOccupiedEntry { entry })
}
indexmap::map::Entry::Vacant(entry) => InlineEntry::Vacant(InlineVacantEntry { entry }),
}
}
/// 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.clone()) {
indexmap::map::Entry::Occupied(mut entry) => {
// Ensure it is a `Value` to simplify `InlineOccupiedEntry`'s code.
let scratch = std::mem::take(entry.get_mut());
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() = scratch;
InlineEntry::Occupied(InlineOccupiedEntry { entry })
}
indexmap::map::Entry::Vacant(entry) => InlineEntry::Vacant(InlineVacantEntry { entry }),
}
}
/// 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(|value| 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(|value| 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_full(key).and_then(|(_, key, value)| {
if !value.is_none() {
Some((key, 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)> {
use indexmap::map::MutableKeys;
self.items.get_full_mut2(key).and_then(|(_, key, value)| {
if !value.is_none() {
Some((key.as_mut(), value))
} else {
None
}
})
}
/// Returns true if the table contains given key.
pub fn contains_key(&self, key: &str) -> bool {
if let Some(value) = self.items.get(key) {
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::new(key))
.or_insert(Item::Value(value.into()))
.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> {
use indexmap::map::MutableEntryKey;
let key = Key::new(key);
let value = Item::Value(value);
match self.items.entry(key.clone()) {
indexmap::map::Entry::Occupied(mut entry) => {
entry.key_mut().fmt();
let old = std::mem::replace(entry.get_mut(), value);
old.into_value().ok()
}
indexmap::map::Entry::Vacant(entry) => {
entry.insert(value);
None
}
}
}
/// Inserts a key-value pair into the map.
pub fn insert_formatted(&mut self, key: &Key, value: Value) -> Option<Value> {
use indexmap::map::MutableEntryKey;
let value = Item::Value(value);
match self.items.entry(key.clone()) {
indexmap::map::Entry::Occupied(mut entry) => {
*entry.key_mut() = key.clone();
let old = std::mem::replace(entry.get_mut(), value);
old.into_value().ok()
}
indexmap::map::Entry::Vacant(entry) => {
entry.insert(value);
None
}
}
}
/// Removes an item given the key.
pub fn remove(&mut self, key: &str) -> Option<Value> {
self.items
.shift_remove(key)
.and_then(|value| 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_entry(key)
.and_then(|(key, value)| Some((key, value.into_value().ok()?)))
}
/// Retains only the elements specified by the `keep` predicate.
///
/// In other words, remove all pairs `(key, value)` for which
/// `keep(&key, &mut value)` returns `false`.
///
/// The elements are visited in iteration order.
pub fn retain<F>(&mut self, mut keep: F)
where
F: FnMut(&str, &mut Value) -> bool,
{
self.items.retain(|key, item| {
item.as_value_mut()
.map(|value| keep(key, value))
.unwrap_or(false)
});
}
}
#[cfg(feature = "display")]
impl std::fmt::Display for InlineTable {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
crate::encode::encode_table(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());
self.items.insert(key, 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(|(_, value)| value.is_value())
.map(|(key, value)| (key.into(), 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) {
use indexmap::map::MutableKeys;
for (mut key, value) in table
.items
.iter_mut2()
.filter(|(_, value)| value.is_value())
.map(|(key, value)| (key.as_mut(), value.as_value_mut().unwrap()))
{
key.leaf_decor_mut().clear();
key.dotted_decor_mut().clear();
value.decor_mut().clear();
}
}
/// An owned iterator type over an [`InlineTable`]'s [`Key`]/[`Value`] pairs
pub type InlineTableIntoIter = Box<dyn Iterator<Item = (InternalString, Value)>>;
/// An iterator type over [`InlineTable`]'s [`Key`]/[`Value`] pairs
pub type InlineTableIter<'a> = Box<dyn Iterator<Item = (&'a str, &'a Value)> + 'a>;
/// A mutable iterator type over [`InlineTable`]'s [`Key`]/[`Value`] pairs
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, value)| (key.get(), value)))
}
fn iter_mut(&mut self) -> IterMut<'_> {
use indexmap::map::MutableKeys;
Box::new(
self.items
.iter_mut2()
.map(|(key, value)| (key.as_mut(), 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 })
}
}
}
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 })
}
}
}
fn get<'s>(&'s self, key: &str) -> Option<&'s Item> {
self.items.get(key)
}
fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item> {
self.items.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.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(&self, key: &str) -> Option<&'_ Key> {
self.key(key)
}
fn key_mut(&mut self, key: &str) -> Option<KeyMut<'_>> {
self.key_mut(key)
}
fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> {
#![allow(deprecated)]
self.key_decor_mut(key)
}
fn key_decor(&self, key: &str) -> Option<&Decor> {
#![allow(deprecated)]
self.key_decor(key)
}
}
// `{ key1 = value1, ... }`
pub(crate) const DEFAULT_INLINE_KEY_DECOR: (&str, &str) = (" ", " ");
/// A view into a single location in an [`InlineTable`], 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 an [`InlineTable`].
pub struct InlineOccupiedEntry<'a> {
entry: indexmap::map::OccupiedEntry<'a, Key, Item>,
}
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().get()
}
/// Gets a mutable reference to the entry key
pub fn key_mut(&mut self) -> KeyMut<'_> {
use indexmap::map::MutableEntryKey;
self.entry.key_mut().as_mut()
}
/// Gets a reference to the value in the entry.
pub fn get(&self) -> &Value {
self.entry.get().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().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().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 value = Item::Value(value);
self.entry.insert(value).into_value().unwrap()
}
/// Takes the value out of the entry, and returns it
pub fn remove(self) -> Value {
self.entry.shift_remove().into_value().unwrap()
}
}
/// A view into a single empty location in an [`InlineTable`].
pub struct InlineVacantEntry<'a> {
entry: indexmap::map::VacantEntry<'a, Key, Item>,
}
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().get()
}
/// 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 value = Item::Value(value);
entry.insert(value).as_value_mut().unwrap()
}
}

View File

@@ -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 = "perf")]
type Inner = kstring::KString;
#[cfg(not(feature = "perf"))]
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 = "perf")]
let inner = kstring::KString::from_ref(s);
#[cfg(not(feature = "perf"))]
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 serde::de::Visitor<'_> 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,
)),
}
}
}

450
vendor/toml_edit-0.22.27/src/item.rs vendored Normal file
View File

@@ -0,0 +1,450 @@
use std::str::FromStr;
use toml_datetime::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, Default)]
pub enum Item {
/// Type representing none.
#[default]
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 if `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`]
///
/// <div class="warning">
///
/// To operate on both [`Table`]s and [`InlineTable`]s, see [`Item::as_table_like`]
///
/// </div>
pub fn as_table(&self) -> Option<&Table> {
match *self {
Item::Table(ref t) => Some(t),
_ => None,
}
}
/// Casts `self` to [`ArrayOfTables`]
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`]
///
/// <div class="warning">
///
/// To operate on both [`Table`]s and [`InlineTable`]s, see [`Item::as_table_like_mut`]
///
/// </div>
pub fn as_table_mut(&mut self) -> Option<&mut Table> {
match *self {
Item::Table(ref mut t) => Some(t),
_ => None,
}
}
/// Casts `self` to mutable [`ArrayOfTables`]
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`]
///
/// <div class="warning">
///
/// This does not include [`InlineTable`]s
///
/// </div>
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 [`ArrayOfTables`]
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(Item::Table) {
Ok(i) => i,
Err(i) => i,
};
let other = match other.into_array_of_tables().map(Item::ArrayOfTables) {
Ok(i) => i,
Err(i) => i,
};
*self = other;
}
/// Returns true if `self` is a [`Value`]
pub fn is_value(&self) -> bool {
self.as_value().is_some()
}
/// Returns true if `self` is a [`Table`]
///
/// <div class="warning">
///
/// To operate on both [`Table`]s and [`InlineTable`]s, see [`Item::is_table_like`]
///
/// </div>
pub fn is_table(&self) -> bool {
self.as_table().is_some()
}
/// Returns true if `self` is an [`ArrayOfTables`]
pub fn is_array_of_tables(&self) -> bool {
self.as_array_of_tables().is_some()
}
/// Returns true if `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 if `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 if `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 if `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 if `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 if `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 if `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 if `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 if `self` is either a table, or an inline table.
pub fn is_table_like(&self) -> bool {
self.as_table_like().is_some()
}
/// The location within the original document
///
/// This generally requires an [`ImDocument`][crate::ImDocument].
pub 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 Clone for Item {
#[inline(never)]
fn clone(&self) -> Self {
match self {
Item::None => Item::None,
Item::Value(v) => Item::Value(v.clone()),
Item::Table(v) => Item::Table(v.clone()),
Item::ArrayOfTables(v) => Item::ArrayOfTables(v.clone()),
}
}
}
#[cfg(feature = "parse")]
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<'b> From<&'b Item> for Item {
fn from(s: &'b Item) -> Self {
s.clone()
}
}
impl From<Table> for Item {
fn from(s: Table) -> Self {
Item::Table(s)
}
}
impl From<ArrayOfTables> for Item {
fn from(s: ArrayOfTables) -> Self {
Item::ArrayOfTables(s)
}
}
impl<V: Into<Value>> From<V> for Item {
fn from(s: V) -> Self {
Item::Value(s.into())
}
}
#[cfg(feature = "display")]
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
/// # #[cfg(feature = "display")] {
/// # #[cfg(feature = "parse")] {
/// # 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())
}
#[test]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
fn string_roundtrip() {
value("hello").to_string().parse::<Item>().unwrap();
}

430
vendor/toml_edit-0.22.27/src/key.rs vendored Normal file
View File

@@ -0,0 +1,430 @@
use std::borrow::Cow;
use std::str::FromStr;
#[cfg(feature = "display")]
use toml_write::ToTomlKey as _;
use crate::repr::{Decor, Repr};
use crate::InternalString;
/// For Key/[`Value`][crate::Value] pairs under a [`Table`][crate::Table] header or inside an
/// [`InlineTable`][crate::InlineTable]
///
/// # 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)]
pub struct Key {
key: InternalString,
pub(crate) repr: Option<Repr>,
pub(crate) leaf_decor: Decor,
pub(crate) dotted_decor: Decor,
}
impl Key {
/// Create a new table key
pub fn new(key: impl Into<InternalString>) -> Self {
Self {
key: key.into(),
repr: None,
leaf_decor: Default::default(),
dotted_decor: Default::default(),
}
}
/// Parse a TOML key expression
///
/// Unlike `"".parse<Key>()`, this supports dotted keys.
#[cfg(feature = "parse")]
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
#[deprecated(since = "0.21.1", note = "Replaced with `with_leaf_decor`")]
pub fn with_decor(self, decor: Decor) -> Self {
self.with_leaf_decor(decor)
}
/// While creating the `Key`, add `Decor` to it for the line entry
pub fn with_leaf_decor(mut self, decor: Decor) -> Self {
self.leaf_decor = decor;
self
}
/// While creating the `Key`, add `Decor` to it for between dots
pub fn with_dotted_decor(mut self, decor: Decor) -> Self {
self.dotted_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
}
/// Returns key raw representation, if available.
pub fn as_repr(&self) -> Option<&Repr> {
self.repr.as_ref()
}
/// Returns the default raw representation.
#[cfg(feature = "display")]
pub fn default_repr(&self) -> Repr {
let output = toml_write::TomlKeyBuilder::new(&self.key)
.as_default()
.to_toml_key();
Repr::new_unchecked(output)
}
/// Returns a raw representation.
#[cfg(feature = "display")]
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
#[deprecated(
since = "0.21.1",
note = "Replaced with `dotted_decor_mut`, `leaf_decor_mut"
)]
pub fn decor_mut(&mut self) -> &mut Decor {
self.leaf_decor_mut()
}
/// Returns the surrounding whitespace for the line entry
pub fn leaf_decor_mut(&mut self) -> &mut Decor {
&mut self.leaf_decor
}
/// Returns the surrounding whitespace for between dots
pub fn dotted_decor_mut(&mut self) -> &mut Decor {
&mut self.dotted_decor
}
/// Returns the surrounding whitespace
#[deprecated(since = "0.21.1", note = "Replaced with `dotted_decor`, `leaf_decor")]
pub fn decor(&self) -> &Decor {
self.leaf_decor()
}
/// Returns the surrounding whitespace for the line entry
pub fn leaf_decor(&self) -> &Decor {
&self.leaf_decor
}
/// Returns the surrounding whitespace for between dots
pub fn dotted_decor(&self) -> &Decor {
&self.dotted_decor
}
/// The location within the original document
///
/// This generally requires an [`ImDocument`][crate::ImDocument].
pub 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.leaf_decor.despan(input);
self.dotted_decor.despan(input);
if let Some(repr) = &mut self.repr {
repr.despan(input);
}
}
/// Auto formats the key.
pub fn fmt(&mut self) {
self.repr = None;
self.leaf_decor.clear();
self.dotted_decor.clear();
}
#[cfg(feature = "parse")]
fn try_parse_simple(s: &str) -> Result<Key, crate::TomlError> {
let mut key = crate::parser::parse_key(s)?;
key.despan(s);
Ok(key)
}
#[cfg(feature = "parse")]
fn try_parse_path(s: &str) -> Result<Vec<Key>, crate::TomlError> {
let mut keys = crate::parser::parse_key_path(s)?;
for key in &mut keys {
key.despan(s);
}
Ok(keys)
}
}
impl Clone for Key {
#[inline(never)]
fn clone(&self) -> Self {
Self {
key: self.key.clone(),
repr: self.repr.clone(),
leaf_decor: self.leaf_decor.clone(),
dotted_decor: self.dotted_decor.clone(),
}
}
}
impl std::ops::Deref for Key {
type Target = str;
fn deref(&self) -> &Self::Target {
self.get()
}
}
impl std::borrow::Borrow<str> for Key {
#[inline]
fn borrow(&self) -> &str {
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 PartialEq<&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())
}
}
#[cfg(feature = "display")]
impl std::fmt::Display for Key {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
crate::encode::encode_key(self, f, None)
}
}
#[cfg(feature = "parse")]
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)
}
}
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`]'s formatting
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash)]
pub struct KeyMut<'k> {
key: &'k mut Key,
}
impl KeyMut<'_> {
/// 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.
#[cfg(feature = "display")]
pub fn default_repr(&self) -> Repr {
self.key.default_repr()
}
/// Returns a raw representation.
#[cfg(feature = "display")]
pub fn display_repr(&self) -> Cow<'_, str> {
self.key.display_repr()
}
/// Returns the surrounding whitespace
#[deprecated(
since = "0.21.1",
note = "Replaced with `dotted_decor_mut`, `leaf_decor_mut"
)]
pub fn decor_mut(&mut self) -> &mut Decor {
#![allow(deprecated)]
self.key.decor_mut()
}
/// Returns the surrounding whitespace for the line entry
pub fn leaf_decor_mut(&mut self) -> &mut Decor {
self.key.leaf_decor_mut()
}
/// Returns the surrounding whitespace for between dots
pub fn dotted_decor_mut(&mut self) -> &mut Decor {
self.key.dotted_decor_mut()
}
/// Returns the surrounding whitespace
#[deprecated(since = "0.21.1", note = "Replaced with `dotted_decor`, `leaf_decor")]
pub fn decor(&self) -> &Decor {
#![allow(deprecated)]
self.key.decor()
}
/// Returns the surrounding whitespace for the line entry
pub fn leaf_decor(&self) -> &Decor {
self.key.leaf_decor()
}
/// Returns the surrounding whitespace for between dots
pub fn dotted_decor(&self) -> &Decor {
self.key.dotted_decor()
}
/// Auto formats the key.
pub fn fmt(&mut self) {
self.key.fmt();
}
}
impl std::ops::Deref for KeyMut<'_> {
type Target = str;
fn deref(&self) -> &Self::Target {
self.get()
}
}
impl PartialEq<str> for KeyMut<'_> {
#[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 PartialEq<String> for KeyMut<'_> {
#[inline]
fn eq(&self, other: &String) -> bool {
PartialEq::eq(self.get(), other.as_str())
}
}
#[cfg(feature = "display")]
impl std::fmt::Display for KeyMut<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
std::fmt::Display::fmt(&self.key, f)
}
}
#[test]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
fn string_roundtrip() {
Key::new("hello").to_string().parse::<Key>().unwrap();
}

149
vendor/toml_edit-0.22.27/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,149 @@
//! # `toml_edit`
//!
//! This crate allows you to parse and modify toml
//! documents, while preserving comments, spaces *and
//! relative order* of items.
//!
//! If you also need the ease of a more traditional API, see the [`toml`] crate.
//!
//! # Example
//!
//! ```rust
//! # #[cfg(feature = "parse")] {
//! # #[cfg(feature = "display")] {
//! use toml_edit::{DocumentMut, value};
//!
//! let toml = r#"
//! "hello" = 'toml!' # comment
//! ['a'.b]
//! "#;
//! let mut doc = toml.parse::<DocumentMut>().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
//! # #[cfg(feature = "display")] {
//! # #[cfg(feature = "parse")] {
//! let mut doc = toml_edit::DocumentMut::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
//! # #[cfg(feature = "display")] {
//! # #[cfg(feature = "parse")] {
//! let mut doc = toml_edit::DocumentMut::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:
//!
//! * Order of dotted keys, see [issue](https://github.com/toml-rs/toml/issues/163).
//!
//! [`toml`]: https://docs.rs/toml/latest/toml/
// https://github.com/Marwes/combine/issues/172
#![recursion_limit = "256"]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
#![warn(missing_docs)]
#![warn(clippy::print_stderr)]
#![warn(clippy::print_stdout)]
mod array;
mod array_of_tables;
mod document;
#[cfg(feature = "display")]
mod encode;
mod error;
mod index;
mod inline_table;
mod internal_string;
mod item;
mod key;
#[cfg(feature = "parse")]
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,
};
/// Deprecated, replaced with [`DocumentMut`]
#[deprecated(since = "0.22.6", note = "Replaced with `DocumentMut`")]
pub type Document = DocumentMut;
pub use crate::document::DocumentMut;
pub use crate::document::ImDocument;
pub use crate::error::TomlError;
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::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<T: ?Sized> Sealed for &T where T: Sealed {}
impl Sealed for crate::Table {}
impl Sealed for crate::InlineTable {}
}
#[doc = include_str!("../README.md")]
#[cfg(doctest)]
#[cfg(feature = "display")]
#[cfg(feature = "parse")]
pub struct ReadmeDoctests;

View File

@@ -0,0 +1,134 @@
use winnow::combinator::cut_err;
use winnow::combinator::delimited;
use winnow::combinator::opt;
use winnow::combinator::peek;
use winnow::combinator::separated;
use winnow::combinator::trace;
use crate::parser::trivia::ws_comment_newline;
use crate::parser::value::value;
use crate::{Array, Item, RawString};
use crate::parser::prelude::*;
// ;; Array
// array = array-open array-values array-close
pub(crate) fn array<'i>(input: &mut Input<'i>) -> ModalResult<Array> {
trace("array", move |input: &mut Input<'i>| {
delimited(
ARRAY_OPEN,
cut_err(array_values),
cut_err(ARRAY_CLOSE)
.context(StrContext::Label("array"))
.context(StrContext::Expected(StrContextValue::CharLiteral(']'))),
)
.parse_next(input)
})
.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',';
// array-values = ws-comment-newline val ws-comment-newline array-sep array-values
// array-values =/ ws-comment-newline val ws-comment-newline [ array-sep ]
fn array_values(input: &mut Input<'_>) -> ModalResult<Array> {
if peek(opt(ARRAY_CLOSE)).parse_next(input)?.is_some() {
// Optimize for empty arrays, avoiding `value` from being expected to fail
return Ok(Array::new());
}
let array = separated(0.., array_value, ARRAY_SEP).parse_next(input)?;
let mut array = Array::with_vec(array);
if !array.is_empty() {
let comma = opt(ARRAY_SEP).parse_next(input)?.is_some();
array.set_trailing_comma(comma);
}
let trailing = ws_comment_newline.span().parse_next(input)?;
array.set_trailing(RawString::with_span(trailing));
Ok(array)
}
fn array_value(input: &mut Input<'_>) -> ModalResult<Item> {
let prefix = ws_comment_newline.span().parse_next(input)?;
let value = value.parse_next(input)?;
let suffix = ws_comment_newline.span().parse_next(input)?;
let value = value.decorated(RawString::with_span(prefix), RawString::with_span(suffix));
let value = Item::Value(value);
Ok(value)
}
#[cfg(test)]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
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.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.parse(new_input(input));
if let Ok(parsed) = &mut parsed {
parsed.despan(input);
}
assert!(parsed.is_err());
}
}
}

View File

@@ -0,0 +1,469 @@
use std::ops::RangeInclusive;
use crate::parser::error::CustomError;
use crate::parser::prelude::*;
use crate::parser::trivia::from_utf8_unchecked;
use toml_datetime::{Date, Datetime, Offset, Time};
use winnow::combinator::alt;
use winnow::combinator::cut_err;
use winnow::combinator::opt;
use winnow::combinator::preceded;
use winnow::combinator::trace;
use winnow::stream::Stream as _;
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: &mut Input<'_>) -> ModalResult<Datetime> {
trace(
"date-time",
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(StrContext::Label("date-time")),
partial_time
.map(|t| t.into())
.context(StrContext::Label("time")),
)),
)
.parse_next(input)
}
// full-date = date-fullyear "-" date-month "-" date-mday
fn full_date(input: &mut Input<'_>) -> ModalResult<Date> {
trace("full-date", full_date_).parse_next(input)
}
fn full_date_(input: &mut Input<'_>) -> ModalResult<Date> {
let year = date_fullyear.parse_next(input)?;
let _ = b'-'.parse_next(input)?;
let month = cut_err(date_month).parse_next(input)?;
let _ = cut_err(b'-').parse_next(input)?;
let day_start = input.checkpoint();
let day = cut_err(date_mday).parse_next(input)?;
let is_leap_year = (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
let max_days_in_month = match month {
2 if is_leap_year => 29,
2 => 28,
4 | 6 | 9 | 11 => 30,
_ => 31,
};
if max_days_in_month < day {
input.reset(&day_start);
return Err(
winnow::error::ErrMode::from_external_error(input, CustomError::OutOfRange).cut(),
);
}
Ok(Date { year, month, day })
}
// partial-time = time-hour ":" time-minute ":" time-second [time-secfrac]
fn partial_time(input: &mut Input<'_>) -> ModalResult<Time> {
trace(
"partial-time",
(
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
fn time_offset(input: &mut Input<'_>) -> ModalResult<Offset> {
trace(
"time-offset",
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(StrContext::Label("time offset")),
)
.parse_next(input)
}
// date-fullyear = 4DIGIT
fn date_fullyear(input: &mut Input<'_>) -> ModalResult<u16> {
unsigned_digits::<4, 4>
.map(|s: &str| s.parse::<u16>().expect("4DIGIT should match u8"))
.parse_next(input)
}
// date-month = 2DIGIT ; 01-12
fn date_month(input: &mut Input<'_>) -> ModalResult<u8> {
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
fn date_mday(input: &mut Input<'_>) -> ModalResult<u8> {
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
fn time_delim(input: &mut Input<'_>) -> ModalResult<u8> {
one_of(TIME_DELIM).parse_next(input)
}
const TIME_DELIM: (u8, u8, u8) = (b'T', b't', b' ');
// time-hour = 2DIGIT ; 00-23
fn time_hour(input: &mut Input<'_>) -> ModalResult<u8> {
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
fn time_minute(input: &mut Input<'_>) -> ModalResult<u8> {
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
fn time_second(input: &mut Input<'_>) -> ModalResult<u8> {
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
fn time_secfrac(input: &mut Input<'_>) -> ModalResult<u32> {
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)
}
fn unsigned_digits<'i, const MIN: usize, const MAX: usize>(
input: &mut Input<'i>,
) -> ModalResult<&'i str> {
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)]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
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();
}
}

View File

@@ -0,0 +1,130 @@
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::combinator::trace;
use winnow::token::any;
use winnow::token::one_of;
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::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<'s, 'i>(
state_ref: &'s RefCell<ParseState>,
) -> impl ModalParser<Input<'i>, (), ContextError> + 's {
move |i: &mut Input<'i>| {
(
// 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,
).void().parse_next(i)
}
}
fn parse_comment<'s, 'i>(
state: &'s RefCell<ParseState>,
) -> impl ModalParser<Input<'i>, (), ContextError> + 's {
move |i: &mut Input<'i>| {
(comment, line_ending)
.span()
.map(|span| {
state.borrow_mut().on_comment(span);
})
.parse_next(i)
}
}
fn parse_ws<'s, 'i>(
state: &'s RefCell<ParseState>,
) -> impl ModalParser<Input<'i>, (), ContextError> + 's {
move |i: &mut Input<'i>| {
ws.span()
.map(|span| state.borrow_mut().on_ws(span))
.parse_next(i)
}
}
fn parse_newline<'s, 'i>(
state: &'s RefCell<ParseState>,
) -> impl ModalParser<Input<'i>, (), ContextError> + 's {
move |i: &mut Input<'i>| {
newline
.span()
.map(|span| state.borrow_mut().on_ws(span))
.parse_next(i)
}
}
fn keyval<'s, 'i>(
state: &'s RefCell<ParseState>,
) -> impl ModalParser<Input<'i>, (), ContextError> + 's {
move |i: &mut Input<'i>| {
parse_keyval
.try_map(|(p, kv)| state.borrow_mut().on_keyval(p, kv))
.parse_next(i)
}
}
// keyval = key keyval-sep val
fn parse_keyval(input: &mut Input<'_>) -> ModalResult<(Vec<Key>, (Key, Item))> {
trace(
"keyval",
(
key,
cut_err((
one_of(KEYVAL_SEP)
.context(StrContext::Expected(StrContextValue::CharLiteral('.')))
.context(StrContext::Expected(StrContextValue::CharLiteral('='))),
(
ws.span(),
value,
line_trailing
.context(StrContext::Expected(StrContextValue::CharLiteral('\n')))
.context(StrContext::Expected(StrContextValue::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, (key, Item::Value(v))))
}),
)
.parse_next(input)
}

View File

@@ -0,0 +1,86 @@
use std::error::Error as StdError;
use std::fmt::{Display, Formatter, Result};
use crate::Key;
#[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
.as_repr()
.and_then(|key| key.as_raw().as_str())
.map(|s| s.to_owned())
.unwrap_or_else(|| {
#[cfg(feature = "display")]
{
key.default_repr().as_raw().as_str().unwrap().to_owned()
}
#[cfg(not(feature = "display"))]
{
format!("{:?}", key.get())
}
});
Self::DuplicateKey {
key: repr,
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 `{key}` in document root")
} else {
let path = table.iter().map(|k| k.get()).collect::<Vec<_>>().join(".");
write!(f, "duplicate key `{key}` in table `{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 `{path}` attempted to extend non-table type ({actual})"
)
}
CustomError::OutOfRange => write!(f, "value is out of range"),
CustomError::RecursionLimitExceeded => write!(f, "recursion limit exceeded"),
}
}
}

View File

@@ -0,0 +1,195 @@
use winnow::combinator::cut_err;
use winnow::combinator::delimited;
use winnow::combinator::separated;
use winnow::combinator::trace;
use winnow::token::one_of;
use crate::key::Key;
use crate::parser::error::CustomError;
use crate::parser::key::key;
use crate::parser::prelude::*;
use crate::parser::trivia::ws;
use crate::parser::value::value;
use crate::{InlineTable, 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<'i>(input: &mut Input<'i>) -> ModalResult<InlineTable> {
trace("inline-table", move |input: &mut Input<'i>| {
delimited(
INLINE_TABLE_OPEN,
cut_err(inline_table_keyvals.try_map(|(kv, p)| table_from_pairs(kv, p))),
cut_err(INLINE_TABLE_CLOSE)
.context(StrContext::Label("inline table"))
.context(StrContext::Expected(StrContextValue::CharLiteral('}'))),
)
.parse_next(input)
})
.parse_next(input)
}
fn table_from_pairs(
v: Vec<(Vec<Key>, (Key, Item))>,
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, (key, value)) in v {
let table = descend_path(&mut root, &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: key.get().into(),
table: None,
});
}
match table.items.entry(key) {
Entry::Vacant(o) => {
o.insert(value);
}
Entry::Occupied(o) => {
return Err(CustomError::DuplicateKey {
key: o.key().get().into(),
table: None,
});
}
}
}
Ok(root)
}
fn descend_path<'a>(
mut table: &'a mut InlineTable,
path: &'a [Key],
dotted: bool,
) -> Result<&'a mut InlineTable, CustomError> {
for (i, key) in path.iter().enumerate() {
table = match table.entry_format(key) {
crate::InlineEntry::Vacant(entry) => {
let mut new_table = InlineTable::new();
new_table.set_implicit(true);
new_table.set_dotted(dotted);
entry
.insert(Value::InlineTable(new_table))
.as_inline_table_mut()
.unwrap()
}
crate::InlineEntry::Occupied(entry) => {
match entry.into_mut() {
Value::InlineTable(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,
});
}
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(
input: &mut Input<'_>,
) -> ModalResult<(Vec<(Vec<Key>, (Key, Item))>, RawString)> {
(
separated(0.., keyval, INLINE_TABLE_SEP),
ws.span().map(RawString::with_span),
)
.parse_next(input)
}
fn keyval(input: &mut Input<'_>) -> ModalResult<(Vec<Key>, (Key, Item))> {
(
key,
cut_err((
one_of(KEYVAL_SEP)
.context(StrContext::Expected(StrContextValue::CharLiteral('.')))
.context(StrContext::Expected(StrContextValue::CharLiteral('='))),
(ws.span(), value, 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, (key, Item::Value(v)))
})
.parse_next(input)
}
#[cfg(test)]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
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.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.parse(new_input(input));
if let Ok(parsed) = &mut parsed {
parsed.despan(input);
}
assert!(parsed.is_err());
}
}
}

View File

@@ -0,0 +1,134 @@
use std::ops::RangeInclusive;
use winnow::combinator::peek;
use winnow::combinator::separated;
use winnow::combinator::trace;
use winnow::token::any;
use winnow::token::take_while;
use crate::key::Key;
use crate::parser::error::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: &mut Input<'_>) -> ModalResult<Vec<Key>> {
let mut key_path = trace(
"dotted-key",
separated(
1..,
(ws.span(), simple_key, ws.span()).map(|(pre, (raw, key), suffix)| {
Key::new(key)
.with_repr_unchecked(Repr::new_unchecked(raw))
.with_dotted_decor(Decor::new(
RawString::with_span(pre),
RawString::with_span(suffix),
))
}),
DOT_SEP,
)
.context(StrContext::Label("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)?;
let mut leaf_decor = Decor::new("", "");
{
let first_dotted_decor = key_path
.first_mut()
.expect("always at least one key")
.dotted_decor_mut();
if let Some(prefix) = first_dotted_decor.prefix().cloned() {
leaf_decor.set_prefix(prefix);
first_dotted_decor.set_prefix("");
}
}
let last_key = &mut key_path.last_mut().expect("always at least one key");
{
let last_dotted_decor = last_key.dotted_decor_mut();
if let Some(suffix) = last_dotted_decor.suffix().cloned() {
leaf_decor.set_suffix(suffix);
last_dotted_decor.set_suffix("");
}
}
*last_key.leaf_decor_mut() = leaf_decor;
Ok(key_path)
}
// simple-key = quoted-key / unquoted-key
// quoted-key = basic-string / literal-string
pub(crate) fn simple_key(input: &mut Input<'_>) -> ModalResult<(RawString, InternalString)> {
trace(
"simple-key",
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<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
trace(
"unquoted-key",
take_while(1.., UNQUOTED_CHAR)
.map(|b| unsafe { from_utf8_unchecked(b, "`is_unquoted_char` filters out on-ASCII") }),
)
.parse_next(input)
}
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)]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
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:?}"
);
}
}
}

View File

@@ -0,0 +1,255 @@
#![allow(clippy::type_complexity)]
use std::cell::RefCell;
pub(crate) mod array;
pub(crate) mod datetime;
pub(crate) mod document;
pub(crate) mod error;
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(crate) use crate::error::TomlError;
pub(crate) fn parse_document<S: AsRef<str>>(raw: S) -> Result<crate::ImDocument<S>, TomlError> {
use prelude::*;
let b = new_input(raw.as_ref());
let state = RefCell::new(state::ParseState::new());
let state_ref = &state;
document::document(state_ref)
.parse(b.clone())
.map_err(|e| TomlError::new(e, b))?;
let doc = state
.into_inner()
.into_document(raw)
.map_err(|e| TomlError::custom(e.to_string(), None))?;
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.clone());
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.clone());
match result {
Ok(keys) => 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.parse(b.clone());
match parsed {
Ok(value) => Ok(value),
Err(e) => Err(TomlError::new(e, b)),
}
}
pub(crate) mod prelude {
pub(crate) use winnow::combinator::dispatch;
pub(crate) use winnow::error::ContextError;
pub(crate) use winnow::error::FromExternalError;
pub(crate) use winnow::error::StrContext;
pub(crate) use winnow::error::StrContextValue;
pub(crate) use winnow::ModalParser;
pub(crate) use winnow::ModalResult;
pub(crate) use winnow::Parser as _;
pub(crate) type Input<'b> =
winnow::Stateful<winnow::LocatingSlice<&'b winnow::BStr>, RecursionCheck>;
pub(crate) fn new_input(s: &str) -> Input<'_> {
winnow::Stateful {
input: winnow::LocatingSlice::new(winnow::BStr::new(s)),
state: Default::default(),
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub(crate) struct RecursionCheck {
#[cfg(not(feature = "unbounded"))]
current: usize,
}
#[cfg(not(feature = "unbounded"))]
const LIMIT: usize = 80;
impl RecursionCheck {
pub(crate) fn check_depth(_depth: usize) -> Result<(), super::error::CustomError> {
#[cfg(not(feature = "unbounded"))]
if LIMIT <= _depth {
return Err(super::error::CustomError::RecursionLimitExceeded);
}
Ok(())
}
fn enter(&mut self) -> Result<(), super::error::CustomError> {
#[cfg(not(feature = "unbounded"))]
{
self.current += 1;
if LIMIT <= self.current {
return Err(super::error::CustomError::RecursionLimitExceeded);
}
}
Ok(())
}
fn exit(&mut self) {
#[cfg(not(feature = "unbounded"))]
{
self.current -= 1;
}
}
}
pub(crate) fn check_recursion<'b, O>(
mut parser: impl ModalParser<Input<'b>, O, ContextError>,
) -> impl ModalParser<Input<'b>, O, ContextError> {
move |input: &mut Input<'b>| {
input
.state
.enter()
.map_err(|err| winnow::error::ErrMode::from_external_error(input, err).cut())?;
let result = parser.parse_next(input);
input.state.exit();
result
}
}
}
#[cfg(test)]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
mod test {
use super::*;
use snapbox::assert_data_eq;
use snapbox::prelude::*;
#[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.weird .stuff' = """
like
that
# """ # this broke my syntax 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 parsed = parse_document(input).map(|d| d.into_mut());
let doc = match parsed {
Ok(doc) => doc,
Err(err) => {
panic!("Parse error: {err:?}\nFailed to parse:\n```\n{input}\n```")
}
};
assert_data_eq!(doc.to_string(), input.raw());
}
}
#[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 parsed = parse_document(input).map(|d| d.into_mut());
match parsed {
Ok(_) => (),
Err(err) => {
panic!("Parse error: {err:?}\nFailed to parse:\n```\n{input}\n```")
}
}
}
}
#[test]
fn invalid_documents() {
let invalid_inputs = [r#" hello = 'darkness' # my old friend
$"#];
for input in invalid_inputs {
dbg!(input);
let parsed = parse_document(input).map(|d| d.into_mut());
assert!(parsed.is_err(), "Input: {input:?}");
}
}
}

View File

@@ -0,0 +1,399 @@
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::trace;
use winnow::token::one_of;
use winnow::token::rest;
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: &mut Input<'_>) -> ModalResult<bool> {
trace("boolean", alt((true_, false_))).parse_next(input)
}
pub(crate) fn true_(input: &mut Input<'_>) -> ModalResult<bool> {
(peek(TRUE[0]), cut_err(TRUE)).value(true).parse_next(input)
}
const TRUE: &[u8] = b"true";
pub(crate) fn false_(input: &mut Input<'_>) -> ModalResult<bool> {
(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: &mut Input<'_>) -> ModalResult<i64> {
trace("integer",
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<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
trace(
"dec-int",
(
opt(one_of((b'+', b'-'))),
alt((
(
one_of(DIGIT1_9),
repeat(
0..,
alt((
digit.void(),
(
one_of(b'_'),
cut_err(digit).context(StrContext::Expected(
StrContextValue::Description("digit"),
)),
)
.void(),
)),
)
.map(|()| ()),
)
.void(),
digit.void(),
)),
)
.take()
.map(|b: &[u8]| unsafe {
from_utf8_unchecked(b, "`digit` and `_` filter out non-ASCII")
})
.context(StrContext::Label("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<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
trace(
"hex-int",
preceded(
HEX_PREFIX,
cut_err((
hexdig,
repeat(
0..,
alt((
hexdig.void(),
(
one_of(b'_'),
cut_err(hexdig).context(StrContext::Expected(
StrContextValue::Description("digit"),
)),
)
.void(),
)),
)
.map(|()| ()),
))
.take(),
)
.map(|b| unsafe { from_utf8_unchecked(b, "`hexdig` and `_` filter out non-ASCII") })
.context(StrContext::Label("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<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
trace(
"oct-int",
preceded(
OCT_PREFIX,
cut_err((
one_of(DIGIT0_7),
repeat(
0..,
alt((
one_of(DIGIT0_7).void(),
(
one_of(b'_'),
cut_err(one_of(DIGIT0_7)).context(StrContext::Expected(
StrContextValue::Description("digit"),
)),
)
.void(),
)),
)
.map(|()| ()),
))
.take(),
)
.map(|b| unsafe { from_utf8_unchecked(b, "`DIGIT0_7` and `_` filter out non-ASCII") })
.context(StrContext::Label("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<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
trace(
"bin-int",
preceded(
BIN_PREFIX,
cut_err((
one_of(DIGIT0_1),
repeat(
0..,
alt((
one_of(DIGIT0_1).void(),
(
one_of(b'_'),
cut_err(one_of(DIGIT0_1)).context(StrContext::Expected(
StrContextValue::Description("digit"),
)),
)
.void(),
)),
)
.map(|()| ()),
))
.take(),
)
.map(|b| unsafe { from_utf8_unchecked(b, "`DIGIT0_1` and `_` filter out non-ASCII") })
.context(StrContext::Label("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: &mut Input<'_>) -> ModalResult<f64> {
trace(
"float",
alt((
float_.and_then(cut_err(
rest.try_map(|s: &str| s.replace('_', "").parse())
.verify(|f: &f64| *f != f64::INFINITY),
)),
special_float,
))
.context(StrContext::Label("floating-point number")),
)
.parse_next(input)
}
fn float_<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
(
dec_int,
alt((exp.void(), (frac.void(), opt(exp.void())).void())),
)
.take()
.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 ; .
fn frac<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
(
b'.',
cut_err(zero_prefixable_int)
.context(StrContext::Expected(StrContextValue::Description("digit"))),
)
.take()
.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 )
fn zero_prefixable_int<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
(
digit,
repeat(
0..,
alt((
digit.void(),
(
one_of(b'_'),
cut_err(digit)
.context(StrContext::Expected(StrContextValue::Description("digit"))),
)
.void(),
)),
)
.map(|()| ()),
)
.take()
.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
fn exp<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
(
one_of((b'e', b'E')),
opt(one_of([b'+', b'-'])),
cut_err(zero_prefixable_int),
)
.take()
.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 )
fn special_float(input: &mut Input<'_>) -> ModalResult<f64> {
(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: &mut Input<'_>) -> ModalResult<f64> {
INF.value(f64::INFINITY).parse_next(input)
}
const INF: &[u8] = b"inf";
// nan = %x6e.61.6e ; nan
pub(crate) fn nan(input: &mut Input<'_>) -> ModalResult<f64> {
NAN.value(f64::NAN.copysign(1.0)).parse_next(input)
}
const NAN: &[u8] = b"nan";
// DIGIT = %x30-39 ; 0-9
fn digit(input: &mut Input<'_>) -> ModalResult<u8> {
one_of(DIGIT).parse_next(input)
}
const DIGIT: RangeInclusive<u8> = b'0'..=b'9';
// HEXDIG = DIGIT / "A" / "B" / "C" / "D" / "E" / "F"
fn hexdig(input: &mut Input<'_>) -> ModalResult<u8> {
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)]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
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),
(&i64::MIN.to_string()[..], i64::MIN),
(&i64::MAX.to_string()[..], 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());
assert_eq!(expected.is_sign_positive(), actual.is_sign_positive());
} 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() < 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", f64::MIN),
("1.7976931348623157e+308", f64::MAX),
("nan", f64::NAN.copysign(1.0)),
("+nan", f64::NAN.copysign(1.0)),
("-nan", f64::NAN.copysign(-1.0)),
("inf", f64::INFINITY),
("+inf", f64::INFINITY),
("-inf", f64::NEG_INFINITY),
// ("1e+400", 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:?}");
}
}
}

View File

@@ -0,0 +1,320 @@
use crate::key::Key;
use crate::parser::error::CustomError;
use crate::repr::Decor;
use crate::{ArrayOfTables, ImDocument, Item, RawString, Table};
pub(crate) struct ParseState {
root: Table,
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 new() -> Self {
let mut root = Table::new();
root.span = Some(0..0);
Self {
root: Table::new(),
trailing: None,
current_table_position: 0,
current_table: root,
current_is_array: false,
current_table_path: Vec::new(),
}
}
pub(crate) fn into_document<S>(mut self, raw: S) -> Result<ImDocument<S>, CustomError> {
self.finalize_table()?;
let trailing = self.trailing.map(RawString::with_span).unwrap_or_default();
Ok(ImDocument {
root: Item::Table(self.root),
trailing,
raw,
})
}
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,
path: Vec<Key>,
(mut key, value): (Key, Item),
) -> Result<(), CustomError> {
{
let mut prefix = self.trailing.take();
let prefix = match (
prefix.take(),
key.leaf_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,
};
key.leaf_decor
.set_prefix(prefix.map(RawString::with_span).unwrap_or_default());
}
if let (Some(existing), Some(value)) = (self.current_table.span(), 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: key.get().into(),
table: None,
});
}
match table.items.entry(key) {
indexmap::map::Entry::Vacant(o) => {
o.insert(value);
}
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().get().into(),
table: Some(self.current_table_path.clone()),
});
}
}
Ok(())
}
pub(crate) fn start_array_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 = &mut self.root;
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 = &mut self.root;
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 = &mut self.root;
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>(
mut table: &'t mut Table,
path: &[Key],
dotted: bool,
) -> Result<&'t mut Table, CustomError> {
for (i, key) in path.iter().enumerate() {
table = match table.entry_format(key) {
crate::Entry::Vacant(entry) => {
let mut new_table = Table::new();
new_table.set_implicit(true);
new_table.set_dotted(dotted);
entry.insert(Item::Table(new_table)).as_table_mut().unwrap()
}
crate::Entry::Occupied(entry) => {
match entry.into_mut() {
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();
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,
});
}
sweet_child_of_mine
}
Item::None => 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_array_table(
path,
Decor::new(leading, RawString::with_span(trailing)),
span,
)?;
Ok(())
}
}

View File

@@ -0,0 +1,479 @@
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::empty;
use winnow::combinator::fail;
use winnow::combinator::opt;
use winnow::combinator::peek;
use winnow::combinator::preceded;
use winnow::combinator::repeat;
use winnow::combinator::terminated;
use winnow::combinator::trace;
use winnow::prelude::*;
use winnow::stream::Stream;
use winnow::token::any;
use winnow::token::none_of;
use winnow::token::one_of;
use winnow::token::take_while;
use crate::parser::error::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<'i>(input: &mut Input<'i>) -> ModalResult<Cow<'i, str>> {
trace(
"string",
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<'i>(input: &mut Input<'i>) -> ModalResult<Cow<'i, str>> {
trace("basic-string", |input: &mut Input<'i>| {
let _ = one_of(QUOTATION_MARK).parse_next(input)?;
let mut c = Cow::Borrowed("");
if let Some(ci) = opt(basic_chars).parse_next(input)? {
c = ci;
}
while let Some(ci) = opt(basic_chars).parse_next(input)? {
c.to_mut().push_str(&ci);
}
let _ = cut_err(one_of(QUOTATION_MARK))
.context(StrContext::Label("basic string"))
.parse_next(input)?;
Ok(c)
})
.parse_next(input)
}
// quotation-mark = %x22 ; "
pub(crate) const QUOTATION_MARK: u8 = b'"';
// basic-char = basic-unescaped / escaped
fn basic_chars<'i>(input: &mut Input<'i>) -> ModalResult<Cow<'i, str>> {
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
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: &mut Input<'_>) -> ModalResult<char> {
preceded(ESCAPE, escape_seq_char).parse_next(input)
}
// escape = %x5C ; \
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: &mut Input<'_>) -> ModalResult<char> {
dispatch! {any;
b'b' => empty.value('\u{8}'),
b'f' => empty.value('\u{c}'),
b'n' => empty.value('\n'),
b'r' => empty.value('\r'),
b't' => empty.value('\t'),
b'u' => cut_err(hexescape::<4>).context(StrContext::Label("unicode 4-digit hex code")),
b'U' => cut_err(hexescape::<8>).context(StrContext::Label("unicode 8-digit hex code")),
b'\\' => empty.value('\\'),
b'"' => empty.value('"'),
_ => {
cut_err(fail::<_, char, _>)
.context(StrContext::Label("escape sequence"))
.context(StrContext::Expected(StrContextValue::CharLiteral('b')))
.context(StrContext::Expected(StrContextValue::CharLiteral('f')))
.context(StrContext::Expected(StrContextValue::CharLiteral('n')))
.context(StrContext::Expected(StrContextValue::CharLiteral('r')))
.context(StrContext::Expected(StrContextValue::CharLiteral('t')))
.context(StrContext::Expected(StrContextValue::CharLiteral('u')))
.context(StrContext::Expected(StrContextValue::CharLiteral('U')))
.context(StrContext::Expected(StrContextValue::CharLiteral('\\')))
.context(StrContext::Expected(StrContextValue::CharLiteral('"')))
}
}
.parse_next(input)
}
fn hexescape<const N: usize>(input: &mut Input<'_>) -> ModalResult<char> {
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<'i>(input: &mut Input<'i>) -> ModalResult<Cow<'i, str>> {
trace(
"ml-basic-string",
delimited(
ML_BASIC_STRING_DELIM,
preceded(opt(newline), cut_err(ml_basic_body))
.context(StrContext::Label("multiline basic string")),
cut_err(ML_BASIC_STRING_DELIM).context(StrContext::Label("multiline basic string")),
),
)
.parse_next(input)
}
// ml-basic-string-delim = 3quotation-mark
const ML_BASIC_STRING_DELIM: &[u8] = b"\"\"\"";
// ml-basic-body = *mlb-content *( mlb-quotes 1*mlb-content ) [ mlb-quotes ]
fn ml_basic_body<'i>(input: &mut Input<'i>) -> ModalResult<Cow<'i, str>> {
let mut c = Cow::Borrowed("");
if let Some(ci) = opt(mlb_content).parse_next(input)? {
c = ci;
}
while let Some(ci) = opt(mlb_content).parse_next(input)? {
c.to_mut().push_str(&ci);
}
while let Some(qi) = opt(mlb_quotes(none_of(b'\"').value(()))).parse_next(input)? {
if let Some(ci) = opt(mlb_content).parse_next(input)? {
c.to_mut().push_str(qi);
c.to_mut().push_str(&ci);
while let Some(ci) = opt(mlb_content).parse_next(input)? {
c.to_mut().push_str(&ci);
}
} else {
break;
}
}
if let Some(qi) = opt(mlb_quotes(ML_BASIC_STRING_DELIM.void())).parse_next(input)? {
c.to_mut().push_str(qi);
}
Ok(c)
}
// mlb-content = mlb-char / newline / mlb-escaped-nl
// mlb-char = mlb-unescaped / escaped
fn mlb_content<'i>(input: &mut Input<'i>) -> ModalResult<Cow<'i, str>> {
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 ModalParser<Input<'i>, (), ContextError>,
) -> impl ModalParser<Input<'i>, &'i str, ContextError> {
move |input: &mut Input<'i>| {
let start = input.checkpoint();
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(_)) => {
input.reset(&start);
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
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: &mut Input<'_>) -> ModalResult<()> {
repeat(1.., (ESCAPE, ws, ws_newlines))
.map(|()| ())
.value(())
.parse_next(input)
}
// ;; Literal String
// literal-string = apostrophe *literal-char apostrophe
pub(crate) fn literal_string<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
trace(
"literal-string",
delimited(
APOSTROPHE,
cut_err(take_while(0.., LITERAL_CHAR)),
cut_err(APOSTROPHE),
)
.try_map(std::str::from_utf8)
.context(StrContext::Label("literal string")),
)
.parse_next(input)
}
// apostrophe = %x27 ; ' apostrophe
pub(crate) const APOSTROPHE: u8 = b'\'';
// literal-char = %x09 / %x20-26 / %x28-7E / non-ascii
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<'i>(input: &mut Input<'i>) -> ModalResult<Cow<'i, str>> {
trace(
"ml-literal-string",
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)
}
}))
.context(StrContext::Label("multiline literal string")),
cut_err(ML_LITERAL_STRING_DELIM).context(StrContext::Label("multiline literal string")),
),
)
.parse_next(input)
}
// ml-literal-string-delim = 3apostrophe
const ML_LITERAL_STRING_DELIM: &[u8] = b"'''";
// ml-literal-body = *mll-content *( mll-quotes 1*mll-content ) [ mll-quotes ]
fn ml_literal_body<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
(
repeat(0.., mll_content).map(|()| ()),
repeat(
0..,
(
mll_quotes(none_of(APOSTROPHE).value(())),
repeat(1.., mll_content).map(|()| ()),
),
)
.map(|()| ()),
opt(mll_quotes(ML_LITERAL_STRING_DELIM.void())),
)
.take()
.try_map(std::str::from_utf8)
.parse_next(input)
}
// mll-content = mll-char / newline
fn mll_content(input: &mut Input<'_>) -> ModalResult<u8> {
alt((one_of(MLL_CHAR), newline.value(b'\n'))).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 ModalParser<Input<'i>, (), ContextError>,
) -> impl ModalParser<Input<'i>, &'i str, ContextError> {
move |input: &mut Input<'i>| {
let start = input.checkpoint();
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(_)) => {
input.reset(&start);
terminated(b"'", peek(term.by_ref()))
.map(|b| unsafe { from_utf8_unchecked(b, "`bytes` out non-ASCII") })
.parse_next(input)
}
res => res,
}
}
}
#[cfg(test)]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
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:?}");
}
}

View File

@@ -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 square bracket
const ARRAY_TABLE_CLOSE: &[u8] = b"]]";
// ;; Standard Table
// std-table = std-table-open key *( table-key-sep key) std-table-close
fn std_table<'s, 'i>(
state: &'s RefCell<ParseState>,
) -> impl ModalParser<Input<'i>, (), ContextError> + 's {
move |i: &mut Input<'i>| {
(
delimited(
STD_TABLE_OPEN,
cut_err(key),
cut_err(STD_TABLE_CLOSE)
.context(StrContext::Expected(StrContextValue::CharLiteral('.')))
.context(StrContext::Expected(StrContextValue::StringLiteral("]"))),
)
.with_span(),
cut_err(line_trailing)
.context(StrContext::Expected(StrContextValue::CharLiteral('\n')))
.context(StrContext::Expected(StrContextValue::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
fn array_table<'s, 'i>(
state: &'s RefCell<ParseState>,
) -> impl ModalParser<Input<'i>, (), ContextError> + 's {
move |i: &mut Input<'i>| {
(
delimited(
ARRAY_TABLE_OPEN,
cut_err(key),
cut_err(ARRAY_TABLE_CLOSE)
.context(StrContext::Expected(StrContextValue::CharLiteral('.')))
.context(StrContext::Expected(StrContextValue::StringLiteral("]]"))),
)
.with_span(),
cut_err(line_trailing)
.context(StrContext::Expected(StrContextValue::CharLiteral('\n')))
.context(StrContext::Expected(StrContextValue::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 ModalParser<Input<'i>, (), ContextError> + 's {
move |i: &mut Input<'i>| {
dispatch!(peek::<_, &[u8],_,_>(take(2usize));
b"[[" => array_table(state),
_ => std_table(state),
)
.context(StrContext::Label("table header"))
.parse_next(i)
}
}

View File

@@ -0,0 +1,166 @@
use std::ops::RangeInclusive;
use winnow::combinator::alt;
use winnow::combinator::empty;
use winnow::combinator::eof;
use winnow::combinator::fail;
use winnow::combinator::opt;
use winnow::combinator::peek;
use winnow::combinator::repeat;
use winnow::combinator::terminated;
use winnow::prelude::*;
use winnow::token::any;
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 {
unsafe {
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<'i>(input: &mut Input<'i>) -> ModalResult<&'i str> {
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: &mut Input<'_>) -> ModalResult<()> {
(COMMENT_START_SYMBOL, take_while(0.., NON_EOL))
.void()
.parse_next(input)
}
// newline = ( %x0A / ; LF
// %x0D.0A ) ; CRLF
pub(crate) fn newline(input: &mut Input<'_>) -> ModalResult<()> {
dispatch! {any;
b'\n' => empty,
b'\r' => one_of(LF).void(),
_ => fail,
}
.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: &mut Input<'_>) -> ModalResult<()> {
repeat(
0..,
alt((newline.value(&b"\n"[..]), take_while(1.., WSCHAR))),
)
.map(|()| ())
.parse_next(input)
}
// ws-newlines = newline *( wschar / newline )
pub(crate) fn ws_newlines(input: &mut Input<'_>) -> ModalResult<()> {
(newline, ws_newline).void().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: &mut Input<'_>) -> ModalResult<()> {
let mut start = input.checkpoint();
loop {
let _ = ws.parse_next(input)?;
let next_token = opt(peek(any)).parse_next(input)?;
match next_token {
Some(b'#') => (comment, newline).void().parse_next(input)?,
Some(b'\n') => (newline).void().parse_next(input)?,
Some(b'\r') => (newline).void().parse_next(input)?,
_ => break,
}
let end = input.checkpoint();
if start == end {
break;
}
start = end;
}
Ok(())
}
// note: this rule is not present in the original grammar
// line-ending = newline / eof
pub(crate) fn line_ending(input: &mut Input<'_>) -> ModalResult<()> {
alt((newline.value("\n"), eof.value("")))
.void()
.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: &mut Input<'_>) -> ModalResult<std::ops::Range<usize>> {
terminated((ws, opt(comment)).span(), line_ending).parse_next(input)
}
#[cfg(test)]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
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.take().parse(new_input(input));
assert!(parsed.is_ok(), "{parsed:?}");
let parsed = parsed.unwrap();
assert_eq!(parsed, input.as_bytes());
}
}
}

View File

@@ -0,0 +1,154 @@
use winnow::combinator::alt;
use winnow::combinator::fail;
use winnow::combinator::peek;
use winnow::token::any;
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::RawString;
use crate::Value;
// val = string / boolean / array / inline-table / date-time / float / integer
pub(crate) fn value(input: &mut Input<'_>) -> ModalResult<Value> {
dispatch! {peek(any);
crate::parser::strings::QUOTATION_MARK |
crate::parser::strings::APOSTROPHE => string.map(|s| {
Value::String(Formatted::new(
s.into_owned()
))
}),
crate::parser::array::ARRAY_OPEN => check_recursion(array).map(Value::Array),
crate::parser::inline_table::INLINE_TABLE_OPEN => check_recursion(inline_table).map(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(Value::from),
float
.map(Value::from),
integer
.map(Value::from),
))
},
// Report as if they were numbers because its most likely a typo
b'_' => {
integer
.map(Value::from)
.context(StrContext::Expected(StrContextValue::Description("leading digit")))
},
// Report as if they were numbers because its most likely a typo
b'.' => {
float
.map(Value::from)
.context(StrContext::Expected(StrContextValue::Description("leading digit")))
},
b't' => {
crate::parser::numbers::true_.map(Value::from)
.context(StrContext::Label("string"))
.context(StrContext::Expected(StrContextValue::CharLiteral('"')))
.context(StrContext::Expected(StrContextValue::CharLiteral('\'')))
},
b'f' => {
crate::parser::numbers::false_.map(Value::from)
.context(StrContext::Label("string"))
.context(StrContext::Expected(StrContextValue::CharLiteral('"')))
.context(StrContext::Expected(StrContextValue::CharLiteral('\'')))
},
b'i' => {
crate::parser::numbers::inf.map(Value::from)
.context(StrContext::Label("string"))
.context(StrContext::Expected(StrContextValue::CharLiteral('"')))
.context(StrContext::Expected(StrContextValue::CharLiteral('\'')))
},
b'n' => {
crate::parser::numbers::nan.map(Value::from)
.context(StrContext::Label("string"))
.context(StrContext::Expected(StrContextValue::CharLiteral('"')))
.context(StrContext::Expected(StrContextValue::CharLiteral('\'')))
},
_ => {
fail
.context(StrContext::Label("string"))
.context(StrContext::Expected(StrContextValue::CharLiteral('"')))
.context(StrContext::Expected(StrContextValue::CharLiteral('\'')))
},
}
.with_span()
.map(|(value, span)| apply_raw(value, span))
.parse_next(input)
}
fn apply_raw(mut val: Value, span: std::ops::Range<usize>) -> Value {
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("", "");
val
}
#[cfg(test)]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
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.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()));
}
}
}

View File

@@ -0,0 +1,188 @@
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 {
RawString(RawStringInner::Spanned(span))
}
/// Access the underlying string
///
/// This generally requires a [`DocumentMut`][crate::DocumentMut].
pub fn as_str(&self) -> Option<&str> {
match &self.0 {
RawStringInner::Empty => Some(""),
RawStringInner::Explicit(s) => Some(s.as_str()),
RawStringInner::Spanned(_) => None,
}
}
/// The location within the original document
///
/// This generally requires an [`ImDocument`][crate::ImDocument].
pub 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 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 {span:?} should be in input:\n```\n{input}\n```")),
}
}
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 {span:?} should be in input:\n```\n{input}\n```")
})
} else {
default
}
}
}
}
pub(crate) fn despan(&mut self, input: &str) {
match &self.0 {
RawStringInner::Empty => {}
RawStringInner::Explicit(_) => {}
RawStringInner::Spanned(span) => {
if span.start == span.end {
*self = RawString(RawStringInner::Empty);
} else {
*self = Self::from(input.get(span.clone()).unwrap_or_else(|| {
panic!("span {span:?} should be in input:\n```\n{input}\n```")
}));
}
}
}
}
#[cfg(feature = "display")]
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(())
}
#[cfg(feature = "display")]
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()
}
}
}

276
vendor/toml_edit-0.22.27/src/repr.rs vendored Normal file
View File

@@ -0,0 +1,276 @@
use std::borrow::Cow;
use crate::RawString;
/// A scalar TOML [`Value`][crate::Value]'s logical value and its representation in a `&str`
///
/// This includes the surrounding whitespace 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.
#[cfg(feature = "display")]
pub fn default_repr(&self) -> Repr {
self.value.to_repr()
}
/// Returns a raw representation.
#[cfg(feature = "display")]
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())
})
}
/// The location within the original document
///
/// This generally requires an [`ImDocument`][crate::ImDocument].
pub 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 = None;
}
}
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()
}
}
#[cfg(feature = "display")]
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_formatted(self, f, None, ("", ""))
}
}
pub trait ValueRepr: crate::private::Sealed {
/// The TOML representation of the value
#[cfg(feature = "display")]
fn to_repr(&self) -> Repr;
}
#[cfg(not(feature = "display"))]
mod inner {
use super::ValueRepr;
impl ValueRepr for String {}
impl ValueRepr for i64 {}
impl ValueRepr for f64 {}
impl ValueRepr for bool {}
impl ValueRepr for toml_datetime::Datetime {}
}
/// A TOML [`Value`][crate::Value] encoded as a `&str`
#[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
}
/// The location within the original document
///
/// This generally requires an [`ImDocument`][crate::ImDocument].
pub 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);
}
#[cfg(feature = "display")]
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()
}
#[cfg(feature = "display")]
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()
}
#[cfg(feature = "display")]
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()
}
}

View File

@@ -0,0 +1,102 @@
use super::Error;
#[doc(hidden)]
pub struct SerializeValueArray {
values: Vec<crate::Item>,
}
impl SerializeValueArray {
pub(crate) fn seq(len: Option<usize>) -> Self {
let mut values = Vec::new();
if let Some(len) = len {
values.reserve(len);
}
Self { values }
}
}
impl serde::ser::SerializeSeq for SerializeValueArray {
type Ok = crate::Value;
type Error = Error;
fn serialize_element<T>(&mut self, value: &T) -> Result<(), Error>
where
T: serde::ser::Serialize + ?Sized,
{
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>(&mut self, value: &T) -> Result<(), Error>
where
T: serde::ser::Serialize + ?Sized,
{
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>(&mut self, value: &T) -> Result<(), Error>
where
T: serde::ser::Serialize + ?Sized,
{
serde::ser::SerializeSeq::serialize_element(self, value)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
serde::ser::SerializeSeq::end(self)
}
}
pub struct SerializeTupleVariant {
variant: &'static str,
inner: SerializeValueArray,
}
impl SerializeTupleVariant {
pub(crate) fn tuple(variant: &'static str, len: usize) -> Self {
Self {
variant,
inner: SerializeValueArray::seq(Some(len)),
}
}
}
impl serde::ser::SerializeTupleVariant for SerializeTupleVariant {
type Ok = crate::Value;
type Error = Error;
fn serialize_field<T>(&mut self, value: &T) -> Result<(), Error>
where
T: serde::ser::Serialize + ?Sized,
{
serde::ser::SerializeSeq::serialize_element(&mut self.inner, value)
}
fn end(self) -> Result<Self::Ok, Self::Error> {
let inner = serde::ser::SerializeSeq::end(self.inner)?;
let mut items = crate::table::KeyValuePairs::new();
let value = crate::Item::Value(inner);
items.insert(crate::Key::new(self.variant), value);
Ok(crate::Value::InlineTable(crate::InlineTable::with_pairs(
items,
)))
}
}

173
vendor/toml_edit-0.22.27/src/ser/key.rs vendored Normal file
View File

@@ -0,0 +1,173 @@
use crate::Key;
use super::Error;
pub(crate) struct KeySerializer;
impl serde::ser::Serializer for KeySerializer {
type Ok = Key;
type Error = Error;
type SerializeSeq = serde::ser::Impossible<Self::Ok, Error>;
type SerializeTuple = serde::ser::Impossible<Self::Ok, Error>;
type SerializeTupleStruct = serde::ser::Impossible<Self::Ok, Error>;
type SerializeTupleVariant = serde::ser::Impossible<Self::Ok, Error>;
type SerializeMap = serde::ser::Impossible<Self::Ok, Error>;
type SerializeStruct = serde::ser::Impossible<Self::Ok, Error>;
type SerializeStructVariant = serde::ser::Impossible<Self::Ok, Error>;
fn serialize_bool(self, _v: bool) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_i8(self, _v: i8) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_i16(self, _v: i16) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_i32(self, _v: i32) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_i64(self, _v: i64) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_u8(self, _v: u8) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_u16(self, _v: u16) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_u32(self, _v: u32) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_u64(self, _v: u64) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_f32(self, _v: f32) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_f64(self, _v: f64) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_char(self, _v: char) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_str(self, value: &str) -> Result<Self::Ok, Self::Error> {
Ok(Key::new(value))
}
fn serialize_bytes(self, _value: &[u8]) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_some<T>(self, _value: &T) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
Err(Error::key_not_string())
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
Ok(variant.into())
}
fn serialize_newtype_struct<T>(
self,
_name: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
value.serialize(self)
}
fn serialize_newtype_variant<T>(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
Err(Error::key_not_string())
}
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_tuple_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
Err(Error::key_not_string())
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
Err(Error::key_not_string())
}
}

608
vendor/toml_edit-0.22.27/src/ser/map.rs vendored Normal file
View File

@@ -0,0 +1,608 @@
use super::array::SerializeTupleVariant;
use super::array::SerializeValueArray;
use super::key::KeySerializer;
use super::value::ValueSerializer;
use super::Error;
#[doc(hidden)]
#[allow(clippy::large_enum_variant)]
pub enum SerializeMap {
Datetime(SerializeDatetime),
Table(SerializeInlineTable),
}
impl SerializeMap {
pub(crate) fn map(len: Option<usize>) -> Self {
Self::Table(SerializeInlineTable::map(len))
}
pub(crate) fn struct_(name: &'static str, len: Option<usize>) -> Self {
if name == toml_datetime::__unstable::NAME {
Self::Datetime(SerializeDatetime::new())
} else {
Self::map(len)
}
}
}
impl serde::ser::SerializeMap for SerializeMap {
type Ok = crate::Value;
type Error = Error;
fn serialize_key<T>(&mut self, input: &T) -> Result<(), Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
match self {
Self::Datetime(s) => s.serialize_key(input),
Self::Table(s) => s.serialize_key(input),
}
}
fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
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>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
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>(&mut self, _input: &T) -> Result<(), Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
unreachable!("datetimes should only be serialized as structs, not maps")
}
fn serialize_value<T>(&mut self, _value: &T) -> Result<(), Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
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>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
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::unsupported_none())
}
}
#[doc(hidden)]
pub struct SerializeInlineTable {
items: crate::table::KeyValuePairs,
key: Option<crate::Key>,
}
impl SerializeInlineTable {
pub(crate) fn map(len: Option<usize>) -> Self {
let mut items: crate::table::KeyValuePairs = Default::default();
let key = Default::default();
if let Some(len) = len {
items.reserve(len);
}
Self { items, key }
}
}
impl serde::ser::SerializeMap for SerializeInlineTable {
type Ok = crate::InlineTable;
type Error = Error;
fn serialize_key<T>(&mut self, input: &T) -> Result<(), Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
self.key = Some(input.serialize(KeySerializer)?);
Ok(())
}
fn serialize_value<T>(&mut self, value: &T) -> Result<(), Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
let mut is_none = false;
let value_serializer = MapValueSerializer::new(&mut is_none);
let res = value.serialize(value_serializer);
match res {
Ok(item) => {
let key = self.key.take().unwrap();
let item = crate::Item::Value(item);
self.items.insert(key, item);
}
Err(e) => {
if !(e == Error::unsupported_none() && is_none) {
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>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
let mut is_none = false;
let value_serializer = MapValueSerializer::new(&mut is_none);
let res = value.serialize(value_serializer);
match res {
Ok(item) => {
let item = crate::Item::Value(item);
self.items.insert(crate::Key::new(key), item);
}
Err(e) => {
if !(e == Error::unsupported_none() && is_none) {
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::date_invalid())
}
fn serialize_i8(self, _value: i8) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_i16(self, _value: i16) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_i32(self, _value: i32) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_i64(self, _value: i64) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_u8(self, _value: u8) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_u16(self, _value: u16) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_u32(self, _value: u32) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_u64(self, _value: u64) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_f32(self, _value: f32) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_f64(self, _value: f64) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_char(self, _value: char) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
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::date_invalid())
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_some<T>(self, _value: &T) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
Err(Error::date_invalid())
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_unit_struct(self, _name: &'static str) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_unit_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_newtype_struct<T>(
self,
_name: &'static str,
_value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
Err(Error::date_invalid())
}
fn serialize_newtype_variant<T>(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
Err(Error::date_invalid())
}
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_tuple(self, _len: usize) -> Result<Self::SerializeTuple, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_tuple_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_tuple_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_struct(
self,
_name: &'static str,
_len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
Err(Error::date_invalid())
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
_variant: &'static str,
_len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
Err(Error::date_invalid())
}
}
struct MapValueSerializer<'d> {
is_none: &'d mut bool,
}
impl<'d> MapValueSerializer<'d> {
fn new(is_none: &'d mut bool) -> Self {
Self { is_none }
}
}
impl serde::ser::Serializer for MapValueSerializer<'_> {
type Ok = crate::Value;
type Error = Error;
type SerializeSeq = SerializeValueArray;
type SerializeTuple = SerializeValueArray;
type SerializeTupleStruct = SerializeValueArray;
type SerializeTupleVariant = SerializeTupleVariant;
type SerializeMap = SerializeMap;
type SerializeStruct = SerializeMap;
type SerializeStructVariant = SerializeStructVariant;
fn serialize_bool(self, v: bool) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_bool(v)
}
fn serialize_i8(self, v: i8) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_i8(v)
}
fn serialize_i16(self, v: i16) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_i16(v)
}
fn serialize_i32(self, v: i32) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_i32(v)
}
fn serialize_i64(self, v: i64) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_i64(v)
}
fn serialize_u8(self, v: u8) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_u8(v)
}
fn serialize_u16(self, v: u16) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_u16(v)
}
fn serialize_u32(self, v: u32) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_u32(v)
}
fn serialize_u64(self, v: u64) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_u64(v)
}
fn serialize_f32(self, v: f32) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_f32(v)
}
fn serialize_f64(self, v: f64) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_f64(v)
}
fn serialize_char(self, v: char) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_char(v)
}
fn serialize_str(self, v: &str) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_str(v)
}
fn serialize_bytes(self, value: &[u8]) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_bytes(value)
}
fn serialize_none(self) -> Result<Self::Ok, Self::Error> {
*self.is_none = true;
Err(Error::unsupported_none())
}
fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
ValueSerializer::new().serialize_some(value)
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_unit()
}
fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_unit_struct(name)
}
fn serialize_unit_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
) -> Result<Self::Ok, Self::Error> {
ValueSerializer::new().serialize_unit_variant(name, variant_index, variant)
}
fn serialize_newtype_struct<T>(
self,
_name: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
value.serialize(self)
}
fn serialize_newtype_variant<T>(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
ValueSerializer::new().serialize_newtype_variant(name, variant_index, variant, value)
}
fn serialize_seq(self, len: Option<usize>) -> Result<Self::SerializeSeq, Self::Error> {
ValueSerializer::new().serialize_seq(len)
}
fn serialize_tuple(self, len: usize) -> Result<Self::SerializeTuple, Self::Error> {
ValueSerializer::new().serialize_tuple(len)
}
fn serialize_tuple_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeTupleStruct, Self::Error> {
ValueSerializer::new().serialize_tuple_struct(name, len)
}
fn serialize_tuple_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeTupleVariant, Self::Error> {
ValueSerializer::new().serialize_tuple_variant(name, variant_index, variant, len)
}
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
ValueSerializer::new().serialize_map(len)
}
fn serialize_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
ValueSerializer::new().serialize_struct(name, len)
}
fn serialize_struct_variant(
self,
name: &'static str,
variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
ValueSerializer::new().serialize_struct_variant(name, variant_index, variant, len)
}
}
pub struct SerializeStructVariant {
variant: &'static str,
inner: SerializeInlineTable,
}
impl SerializeStructVariant {
pub(crate) fn struct_(variant: &'static str, len: usize) -> Self {
Self {
variant,
inner: SerializeInlineTable::map(Some(len)),
}
}
}
impl serde::ser::SerializeStructVariant for SerializeStructVariant {
type Ok = crate::Value;
type Error = Error;
#[inline]
fn serialize_field<T>(&mut self, key: &'static str, value: &T) -> Result<(), Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
serde::ser::SerializeStruct::serialize_field(&mut self.inner, key, value)
}
#[inline]
fn end(self) -> Result<Self::Ok, Self::Error> {
let inner = serde::ser::SerializeStruct::end(self.inner)?.into();
let mut items = crate::table::KeyValuePairs::new();
let value = crate::Item::Value(inner);
items.insert(crate::Key::new(self.variant), value);
Ok(crate::Value::InlineTable(crate::InlineTable::with_pairs(
items,
)))
}
}

188
vendor/toml_edit-0.22.27/src/ser/mod.rs vendored Normal file
View File

@@ -0,0 +1,188 @@
//! 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;
use crate::visit_mut::VisitMut as _;
#[allow(clippy::wildcard_imports)]
use array::*;
#[allow(clippy::wildcard_imports)]
use map::*;
pub use value::ValueSerializer;
/// 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.
#[cfg(feature = "display")]
pub fn to_vec<T>(value: &T) -> Result<Vec<u8>, Error>
where
T: serde::ser::Serialize + ?Sized,
{
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)
/// ```
#[cfg(feature = "display")]
pub fn to_string<T>(value: &T) -> Result<String, Error>
where
T: serde::ser::Serialize + ?Sized,
{
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.
#[cfg(feature = "display")]
pub fn to_string_pretty<T>(value: &T) -> Result<String, Error>
where
T: serde::ser::Serialize + ?Sized,
{
let mut document = to_document(value)?;
pretty::Pretty::new().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>(value: &T) -> Result<crate::DocumentMut, Error>
where
T: serde::ser::Serialize + ?Sized,
{
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())
}
/// 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 convertible 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())
}
pub(crate) fn unsupported_type(t: Option<&'static str>) -> Self {
Error::UnsupportedType(t)
}
fn out_of_range(t: Option<&'static str>) -> Self {
Error::OutOfRange(t)
}
pub(crate) fn unsupported_none() -> Self {
Error::UnsupportedNone
}
pub(crate) fn key_not_string() -> Self {
Error::KeyNotString
}
fn date_invalid() -> Self {
Error::DateInvalid
}
}
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 {}

View File

@@ -0,0 +1,58 @@
pub(crate) struct Pretty {
in_value: bool,
}
impl Pretty {
pub(crate) fn new() -> Self {
Self { in_value: false }
}
}
impl crate::visit_mut::VisitMut for Pretty {
fn visit_document_mut(&mut self, node: &mut crate::DocumentMut) {
crate::visit_mut::visit_document_mut(self, node);
}
fn visit_item_mut(&mut self, node: &mut crate::Item) {
if !self.in_value {
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();
let old_in_value = self.in_value;
self.in_value = true;
crate::visit_mut::visit_value_mut(self, node);
self.in_value = old_in_value;
}
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);
}
}
}

View File

@@ -0,0 +1,249 @@
use super::Error;
use super::SerializeMap;
use super::SerializeStructVariant;
use super::SerializeTupleVariant;
use super::SerializeValueArray;
/// 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
///
/// ```
/// # #[cfg(feature = "parse")] {
/// # #[cfg(feature = "display")] {
/// 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 = SerializeValueArray;
type SerializeTuple = SerializeValueArray;
type SerializeTupleStruct = SerializeValueArray;
type SerializeTupleVariant = SerializeTupleVariant;
type SerializeMap = SerializeMap;
type SerializeStruct = SerializeMap;
type SerializeStructVariant = SerializeStructVariant;
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::out_of_range(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, mut v: f64) -> Result<Self::Ok, Self::Error> {
// Discard sign of NaN when serialized using Serde.
//
// In all likelihood the sign of NaNs is not meaningful in the user's
// program. Ending up with `-nan` in the TOML document would usually be
// surprising and undesirable, when the sign of the NaN was not
// intentionally controlled by the caller, or may even be
// nondeterministic if it comes from arithmetic operations or a cast.
if v.is_nan() {
v = v.copysign(1.0);
}
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::unsupported_none())
}
fn serialize_some<T>(self, value: &T) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
value.serialize(self)
}
fn serialize_unit(self) -> Result<Self::Ok, Self::Error> {
Err(Error::unsupported_type(Some("unit")))
}
fn serialize_unit_struct(self, name: &'static str) -> Result<Self::Ok, Self::Error> {
Err(Error::unsupported_type(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>(
self,
_name: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
value.serialize(self)
}
fn serialize_newtype_variant<T>(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
value: &T,
) -> Result<Self::Ok, Self::Error>
where
T: serde::ser::Serialize + ?Sized,
{
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> {
Ok(SerializeValueArray::seq(len))
}
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> {
Ok(SerializeTupleVariant::tuple(variant, len))
}
fn serialize_map(self, len: Option<usize>) -> Result<Self::SerializeMap, Self::Error> {
Ok(SerializeMap::map(len))
}
fn serialize_struct(
self,
name: &'static str,
len: usize,
) -> Result<Self::SerializeStruct, Self::Error> {
Ok(SerializeMap::struct_(name, Some(len)))
}
fn serialize_struct_variant(
self,
_name: &'static str,
_variant_index: u32,
variant: &'static str,
len: usize,
) -> Result<Self::SerializeStructVariant, Self::Error> {
Ok(SerializeStructVariant::struct_(variant, len))
}
}

818
vendor/toml_edit-0.22.27/src/table.rs vendored Normal file
View File

@@ -0,0 +1,818 @@
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};
/// A TOML table, a top-level collection of key/[`Value`] pairs under a header and logical
/// sub-tables
#[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 (_, value) in self.items.iter_mut() {
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>(
&'s self,
parent: &[&'s Key],
values: &mut Vec<(Vec<&'s Key>, &'s Value)>,
) {
for (key, value) in self.items.iter() {
let mut path = parent.to_vec();
path.push(key);
match 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
///
/// <div class="warning">
///
/// This sorts the syntactic table (everything under the `[header]`) and not the logical map of
/// key-value pairs.
/// This does not affect the order of [sub-tables][Table] or [sub-arrays][crate::ArrayOfTables].
/// This is not recursive.
///
/// </div>
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 value in self.items.values_mut() {
match 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).
///
/// <div class="warning">
///
/// This sorts the syntactic table (everything under the `[header]`) and not the logical map of
/// key-value pairs.
/// This does not affect the order of [sub-tables][Table] or [sub-arrays][crate::ArrayOfTables].
/// This is not recursive.
///
/// </div>
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 =
|key1: &Key, val1: &Item, key2: &Key, val2: &Item| -> std::cmp::Ordering {
compare(key1, val1, key2, val2)
};
self.items.sort_by(modified_cmp);
for value in self.items.values_mut() {
match 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.
///
/// ```
/// # #[cfg(feature = "parse")] {
/// # #[cfg(feature = "display")] {
/// use toml_edit::DocumentMut;
/// let mut doc = "[a]\n[a.b]\n".parse::<DocumentMut>().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 [`DocumentMut`][crate::DocumentMut].
pub fn set_position(&mut self, doc_position: usize) {
self.doc_position = Some(doc_position);
}
/// The position of the `Table` within the [`DocumentMut`][crate::DocumentMut].
///
/// 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 an accessor to a key's formatting
pub fn key(&self, key: &str) -> Option<&'_ Key> {
self.items.get_full(key).map(|(_, key, _)| key)
}
/// Returns an accessor to a key's formatting
pub fn key_mut(&mut self, key: &str) -> Option<KeyMut<'_>> {
use indexmap::map::MutableKeys;
self.items
.get_full_mut2(key)
.map(|(_, key, _)| key.as_mut())
}
/// Returns the decor associated with a given key of the table.
#[deprecated(since = "0.21.1", note = "Replaced with `key_mut`")]
pub fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> {
#![allow(deprecated)]
use indexmap::map::MutableKeys;
self.items
.get_full_mut2(key)
.map(|(_, key, _)| key.leaf_decor_mut())
}
/// Returns the decor associated with a given key of the table.
#[deprecated(since = "0.21.1", note = "Replaced with `key_mut`")]
pub fn key_decor(&self, key: &str) -> Option<&Decor> {
#![allow(deprecated)]
self.items.get_full(key).map(|(_, key, _)| key.leaf_decor())
}
/// The location within the original document
///
/// This generally requires an [`ImDocument`][crate::ImDocument].
pub fn span(&self) -> Option<std::ops::Range<usize>> {
self.span.clone()
}
pub(crate) fn despan(&mut self, input: &str) {
use indexmap::map::MutableKeys;
self.span = None;
self.decor.despan(input);
for (key, value) in self.items.iter_mut2() {
key.despan(input);
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(|(_, value)| !value.is_none())
.map(|(key, value)| (key.get(), value)),
)
}
/// Returns an mutable iterator over all key/value pairs, including empty.
pub fn iter_mut(&mut self) -> IterMut<'_> {
use indexmap::map::MutableKeys;
Box::new(
self.items
.iter_mut2()
.filter(|(_, value)| !value.is_none())
.map(|(key, value)| (key.as_mut(), value)),
)
}
/// Returns the number of non-empty items in the table.
pub fn len(&self) -> usize {
self.iter().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 }),
}
}
/// 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.clone()) {
indexmap::map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { entry }),
indexmap::map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { entry }),
}
}
/// 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(|value| if !value.is_none() { Some(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(|value| if !value.is_none() { Some(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_full(key).and_then(|(_, key, value)| {
if !value.is_none() {
Some((key, 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)> {
use indexmap::map::MutableKeys;
self.items.get_full_mut2(key).and_then(|(_, key, value)| {
if !value.is_none() {
Some((key.as_mut(), 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(value) = self.items.get(key) {
!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(value) = self.items.get(key) {
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(value) = self.items.get(key) {
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(value) = self.items.get(key) {
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> {
use indexmap::map::MutableEntryKey;
let key = Key::new(key);
match self.items.entry(key.clone()) {
indexmap::map::Entry::Occupied(mut entry) => {
entry.key_mut().fmt();
let old = std::mem::replace(entry.get_mut(), item);
Some(old)
}
indexmap::map::Entry::Vacant(entry) => {
entry.insert(item);
None
}
}
}
/// Inserts a key-value pair into the map.
pub fn insert_formatted(&mut self, key: &Key, item: Item) -> Option<Item> {
use indexmap::map::MutableEntryKey;
match self.items.entry(key.clone()) {
indexmap::map::Entry::Occupied(mut entry) => {
*entry.key_mut() = key.clone();
let old = std::mem::replace(entry.get_mut(), item);
Some(old)
}
indexmap::map::Entry::Vacant(entry) => {
entry.insert(item);
None
}
}
}
/// Removes an item given the key.
pub fn remove(&mut self, key: &str) -> Option<Item> {
self.items.shift_remove(key)
}
/// 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_entry(key)
}
/// Retains only the elements specified by the `keep` predicate.
///
/// In other words, remove all pairs `(key, item)` for which
/// `keep(&key, &mut item)` returns `false`.
///
/// The elements are visited in iteration order.
pub fn retain<F>(&mut self, mut keep: F)
where
F: FnMut(&str, &mut Item) -> bool,
{
self.items.retain(|key, value| keep(key, value));
}
}
#[cfg(feature = "display")]
impl std::fmt::Display for Table {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let children = self.get_values();
// print table body
for (key_path, value) in children {
crate::encode::encode_key_path_ref(&key_path, f, None, DEFAULT_KEY_DECOR)?;
write!(f, "=")?;
crate::encode::encode_value(value, f, None, DEFAULT_VALUE_DECOR)?;
writeln!(f)?;
}
Ok(())
}
}
impl<K: Into<Key>, V: Into<Item>> 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 = value.into();
self.items.insert(key, value);
}
}
}
impl<K: Into<Key>, V: Into<Item>> 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, value)| (k.into(), 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<Key, Item>;
fn decorate_table(table: &mut Table) {
use indexmap::map::MutableKeys;
for (mut key, value) in table
.items
.iter_mut2()
.filter(|(_, value)| value.is_value())
.map(|(key, value)| (key.as_mut(), value.as_value_mut().unwrap()))
{
key.leaf_decor_mut().clear();
key.dotted_decor_mut().clear();
value.decor_mut().clear();
}
}
// `key1 = value1`
pub(crate) const DEFAULT_ROOT_DECOR: (&str, &str) = ("", "");
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) = ("", "");
/// An owned iterator type over [`Table`]'s [`Key`]/[`Item`] pairs
pub type IntoIter = Box<dyn Iterator<Item = (InternalString, Item)>>;
/// An iterator type over [`Table`]'s [`Key`]/[`Item`] pairs
pub type Iter<'a> = Box<dyn Iterator<Item = (&'a str, &'a Item)> + 'a>;
/// A mutable iterator type over [`Table`]'s [`Key`]/[`Item`] 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
///
/// <div class="warning">
///
/// This sorts the syntactic table (everything under the `[header]`) and not the logical map of
/// key-value pairs.
/// This does not affect the order of [sub-tables][Table] or [sub-arrays][crate::ArrayOfTables].
/// This is not recursive.
///
/// </div>
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 an accessor to a key's formatting
fn key(&self, key: &str) -> Option<&'_ Key>;
/// Returns an accessor to a key's formatting
fn key_mut(&mut self, key: &str) -> Option<KeyMut<'_>>;
/// Returns the decor associated with a given key of the table.
#[deprecated(since = "0.21.1", note = "Replaced with `key_mut`")]
fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor>;
/// Returns the decor associated with a given key of the table.
#[deprecated(since = "0.21.1", note = "Replaced with `key_mut`")]
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(&self, key: &str) -> Option<&'_ Key> {
self.key(key)
}
fn key_mut(&mut self, key: &str) -> Option<KeyMut<'_>> {
self.key_mut(key)
}
fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> {
#![allow(deprecated)]
self.key_decor_mut(key)
}
fn key_decor(&self, key: &str) -> Option<&Decor> {
#![allow(deprecated)]
self.key_decor(key)
}
}
/// A view into a single location in a [`Table`], 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 [`Table`].
pub struct OccupiedEntry<'a> {
pub(crate) entry: indexmap::map::OccupiedEntry<'a, Key, Item>,
}
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().get()
}
/// Gets a mutable reference to the entry key
pub fn key_mut(&mut self) -> KeyMut<'_> {
use indexmap::map::MutableEntryKey;
self.entry.key_mut().as_mut()
}
/// Gets a reference to the value in the entry.
pub fn get(&self) -> &Item {
self.entry.get()
}
/// Gets a mutable reference to the value in the entry.
pub fn get_mut(&mut self) -> &mut Item {
self.entry.get_mut()
}
/// 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 {
self.entry.into_mut()
}
/// Sets the value of the entry, and returns the entry's old value
pub fn insert(&mut self, value: Item) -> Item {
self.entry.insert(value)
}
/// Takes the value out of the entry, and returns it
pub fn remove(self) -> Item {
self.entry.shift_remove()
}
}
/// A view into a single empty location in a [`Table`].
pub struct VacantEntry<'a> {
pub(crate) entry: indexmap::map::VacantEntry<'a, Key, Item>,
}
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().get()
}
/// 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;
entry.insert(value)
}
}

392
vendor/toml_edit-0.22.27/src/value.rs vendored Normal file
View File

@@ -0,0 +1,392 @@
use std::iter::FromIterator;
use std::str::FromStr;
use toml_datetime::{Date, Datetime, Time};
use crate::key::Key;
use crate::repr::{Decor, Formatted};
use crate::{Array, InlineTable, InternalString, RawString};
/// For [`Key`]/Value pairs under a [`Table`][crate::Table] header or inside another
/// Value
#[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 if `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 if `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 if `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 if `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 if `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 if `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 if `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
/// # #[cfg(feature = "display")] {
/// 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);
}
/// The location within the original document
///
/// This generally requires an [`ImDocument`][crate::ImDocument].
pub 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),
}
}
}
#[cfg(feature = "parse")]
impl FromStr for Value {
type Err = crate::TomlError;
/// Parses a value from a &str
fn from_str(s: &str) -> Result<Self, Self::Err> {
let mut value = crate::parser::parse_value(s)?;
// Only take the repr and not decor, as its probably not intended
value.decor_mut().clear();
value.despan(s);
Ok(value)
}
}
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 {
// Preserve sign of NaN. It may get written to TOML as `-nan`.
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)
}
}
#[cfg(feature = "display")]
impl std::fmt::Display for Value {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
crate::encode::encode_value(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)]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
mod tests {
use super::*;
#[test]
fn from_iter_formatting() {
let features = ["node".to_owned(), "mouth".to_owned()];
let features: Value = features.iter().cloned().collect();
assert_eq!(features.to_string(), r#"["node", "mouth"]"#);
}
}
#[test]
#[cfg(feature = "parse")]
#[cfg(feature = "display")]
fn string_roundtrip() {
Value::from("hello").to_string().parse::<Value>().unwrap();
}

239
vendor/toml_edit-0.22.27/src/visit.rs vendored Normal file
View File

@@ -0,0 +1,239 @@
#![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.
//!
//! ```
//! # #[cfg(feature = "parse")] {
//! # 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: DocumentMut = 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/toml-rs/toml/blob/main/crates/toml_edit/examples/visit.rs).
use crate::{
Array, ArrayOfTables, Datetime, DocumentMut, 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 DocumentMut) {
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 DocumentMut)
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>);

View File

@@ -0,0 +1,256 @@
#![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.
//!
//! ```
//! # #[cfg(feature = "parse")] {
//! # #[cfg(feature = "display")] {
//! # 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: DocumentMut = 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/toml-rs/toml/blob/main/crates/toml_edit/examples/visit.rs).
use crate::{
Array, ArrayOfTables, Datetime, DocumentMut, 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 DocumentMut) {
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 DocumentMut)
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>);