use std::iter::FromIterator; use crate::key::Key; use crate::repr::Decor; use crate::table::{Iter, IterMut, KeyValuePairs, TableKeyValue, TableLike}; use crate::{InternalString, Item, KeyMut, RawString, Table, Value}; /// Type representing a TOML inline table, /// payload of the `Value::InlineTable` variant #[derive(Debug, Default, Clone)] pub struct InlineTable { // `preamble` represents whitespaces in an empty table preamble: RawString, // prefix before `{` and suffix after `}` decor: Decor, pub(crate) span: Option>, // whether this is a proxy for dotted keys dotted: bool, pub(crate) items: KeyValuePairs, } /// Constructors /// /// See also `FromIterator` impl InlineTable { /// Creates an empty table. pub fn new() -> Self { Default::default() } pub(crate) fn with_pairs(items: KeyValuePairs) -> Self { Self { items, ..Default::default() } } /// Convert to a table pub fn into_table(self) -> Table { let mut t = Table::with_pairs(self.items); t.fmt(); t } } /// Formatting impl InlineTable { /// Get key/values for values that are visually children of this table /// /// For example, this will return dotted keys pub fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> { let mut values = Vec::new(); let root = Vec::new(); self.append_values(&root, &mut values); values } pub(crate) fn append_values<'s, 'c>( &'s self, parent: &[&'s Key], values: &'c mut Vec<(Vec<&'s Key>, &'s Value)>, ) { for value in self.items.values() { let mut path = parent.to_vec(); path.push(&value.key); match &value.value { Item::Value(Value::InlineTable(table)) if table.is_dotted() => { table.append_values(&path, values); } Item::Value(value) => { values.push((path, value)); } _ => {} } } } /// Auto formats the table. pub fn fmt(&mut self) { decorate_inline_table(self); } /// Sorts the key/value pairs by key. pub fn sort_values(&mut self) { // Assuming standard tables have their position set and this won't negatively impact them self.items.sort_keys(); for kv in self.items.values_mut() { match &mut kv.value { Item::Value(Value::InlineTable(table)) if table.is_dotted() => { table.sort_values(); } _ => {} } } } /// Sort Key/Value Pairs of the table using the using the comparison function `compare`. /// /// The comparison function receives two key and value pairs to compare (you can sort by keys or /// values or their combination as needed). pub fn sort_values_by(&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(&mut self, compare: &mut F) where F: FnMut(&Key, &Value, &Key, &Value) -> std::cmp::Ordering, { let modified_cmp = |_: &InternalString, val1: &TableKeyValue, _: &InternalString, val2: &TableKeyValue| -> std::cmp::Ordering { match (val1.value.as_value(), val2.value.as_value()) { (Some(v1), Some(v2)) => compare(&val1.key, v1, &val2.key, v2), (Some(_), None) => std::cmp::Ordering::Greater, (None, Some(_)) => std::cmp::Ordering::Less, (None, None) => std::cmp::Ordering::Equal, } }; self.items.sort_by(modified_cmp); for kv in self.items.values_mut() { match &mut kv.value { Item::Value(Value::InlineTable(table)) if table.is_dotted() => { table.sort_values_by_internal(compare); } _ => {} } } } /// Change this table's dotted status pub fn set_dotted(&mut self, yes: bool) { self.dotted = yes; } /// Check if this is a wrapper for dotted keys, rather than a standard table pub fn is_dotted(&self) -> bool { self.dotted } /// Returns the surrounding whitespace pub fn decor_mut(&mut self) -> &mut Decor { &mut self.decor } /// Returns the surrounding whitespace pub fn decor(&self) -> &Decor { &self.decor } /// Returns the decor associated with a given key of the table. pub fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> { self.items.get_mut(key).map(|kv| &mut kv.key.decor) } /// Returns the decor associated with a given key of the table. pub fn key_decor(&self, key: &str) -> Option<&Decor> { self.items.get(key).map(|kv| &kv.key.decor) } /// Set whitespace after before element pub fn set_preamble(&mut self, preamble: impl Into) { self.preamble = preamble.into(); } /// Whitespace after before element pub fn preamble(&self) -> &RawString { &self.preamble } /// Returns the location within the original document pub(crate) fn span(&self) -> Option> { self.span.clone() } pub(crate) fn despan(&mut self, input: &str) { self.span = None; self.decor.despan(input); self.preamble.despan(input); for kv in self.items.values_mut() { kv.key.despan(input); kv.value.despan(input); } } } impl InlineTable { /// Returns an iterator over key/value pairs. pub fn iter(&self) -> InlineTableIter<'_> { Box::new( self.items .iter() .filter(|&(_, kv)| kv.value.is_value()) .map(|(k, kv)| (&k[..], kv.value.as_value().unwrap())), ) } /// Returns an iterator over key/value pairs. pub fn iter_mut(&mut self) -> InlineTableIterMut<'_> { Box::new( self.items .iter_mut() .filter(|(_, kv)| kv.value.is_value()) .map(|(_, kv)| (kv.key.as_mut(), kv.value.as_value_mut().unwrap())), ) } /// Returns the number of key/value pairs. pub fn len(&self) -> usize { self.iter().count() } /// Returns true iff the table is empty. pub fn is_empty(&self) -> bool { self.len() == 0 } /// Clears the table, removing all key-value pairs. Keeps the allocated memory for reuse. pub fn clear(&mut self) { self.items.clear() } /// Gets the given key's corresponding entry in the Table for in-place manipulation. pub fn entry(&'_ mut self, key: impl Into) -> InlineEntry<'_> { match self.items.entry(key.into()) { indexmap::map::Entry::Occupied(mut entry) => { // Ensure it is a `Value` to simplify `InlineOccupiedEntry`'s code. let scratch = std::mem::take(&mut entry.get_mut().value); let scratch = Item::Value( scratch .into_value() // HACK: `Item::None` is a corner case of a corner case, let's just pick a // "safe" value .unwrap_or_else(|_| Value::InlineTable(Default::default())), ); entry.get_mut().value = scratch; InlineEntry::Occupied(InlineOccupiedEntry { entry }) } indexmap::map::Entry::Vacant(entry) => { InlineEntry::Vacant(InlineVacantEntry { entry, key: None }) } } } /// Gets the given key's corresponding entry in the Table for in-place manipulation. pub fn entry_format<'a>(&'a mut self, key: &Key) -> InlineEntry<'a> { // Accept a `&Key` to be consistent with `entry` match self.items.entry(key.get().into()) { indexmap::map::Entry::Occupied(mut entry) => { // Ensure it is a `Value` to simplify `InlineOccupiedEntry`'s code. let scratch = std::mem::take(&mut entry.get_mut().value); let scratch = Item::Value( scratch .into_value() // HACK: `Item::None` is a corner case of a corner case, let's just pick a // "safe" value .unwrap_or_else(|_| Value::InlineTable(Default::default())), ); entry.get_mut().value = scratch; InlineEntry::Occupied(InlineOccupiedEntry { entry }) } indexmap::map::Entry::Vacant(entry) => InlineEntry::Vacant(InlineVacantEntry { entry, key: Some(key.clone()), }), } } /// Return an optional reference to the value at the given the key. pub fn get(&self, key: &str) -> Option<&Value> { self.items.get(key).and_then(|kv| kv.value.as_value()) } /// Return an optional mutable reference to the value at the given the key. pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> { self.items .get_mut(key) .and_then(|kv| kv.value.as_value_mut()) } /// Return references to the key-value pair stored for key, if it is present, else None. pub fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> { self.items.get(key).and_then(|kv| { if !kv.value.is_none() { Some((&kv.key, &kv.value)) } else { None } }) } /// Return mutable references to the key-value pair stored for key, if it is present, else None. pub fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> { self.items.get_mut(key).and_then(|kv| { if !kv.value.is_none() { Some((kv.key.as_mut(), &mut kv.value)) } else { None } }) } /// Returns true iff the table contains given key. pub fn contains_key(&self, key: &str) -> bool { if let Some(kv) = self.items.get(key) { kv.value.is_value() } else { false } } /// Inserts a key/value pair if the table does not contain the key. /// Returns a mutable reference to the corresponding value. pub fn get_or_insert>( &mut self, key: impl Into, value: V, ) -> &mut Value { let key = key.into(); self.items .entry(key.clone()) .or_insert(TableKeyValue::new(Key::new(key), Item::Value(value.into()))) .value .as_value_mut() .expect("non-value type in inline table") } /// Inserts a key-value pair into the map. pub fn insert(&mut self, key: impl Into, value: Value) -> Option { let key = key.into(); let kv = TableKeyValue::new(Key::new(key.clone()), Item::Value(value)); self.items .insert(key, kv) .and_then(|kv| kv.value.into_value().ok()) } /// Inserts a key-value pair into the map. pub fn insert_formatted(&mut self, key: &Key, value: Value) -> Option { let kv = TableKeyValue::new(key.to_owned(), Item::Value(value)); self.items .insert(InternalString::from(key.get()), kv) .filter(|kv| kv.value.is_value()) .map(|kv| kv.value.into_value().unwrap()) } /// Removes an item given the key. pub fn remove(&mut self, key: &str) -> Option { self.items .shift_remove(key) .and_then(|kv| kv.value.into_value().ok()) } /// Removes a key from the map, returning the stored key and value if the key was previously in the map. pub fn remove_entry(&mut self, key: &str) -> Option<(Key, Value)> { self.items.shift_remove(key).and_then(|kv| { let key = kv.key; kv.value.into_value().ok().map(|value| (key, value)) }) } } impl std::fmt::Display for InlineTable { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { crate::encode::Encode::encode(self, f, None, ("", "")) } } impl, V: Into> Extend<(K, V)> for InlineTable { fn extend>(&mut self, iter: T) { for (key, value) in iter { let key = key.into(); let value = Item::Value(value.into()); let value = TableKeyValue::new(key, value); self.items .insert(InternalString::from(value.key.get()), value); } } } impl, V: Into> FromIterator<(K, V)> for InlineTable { fn from_iter(iter: I) -> Self where I: IntoIterator, { let mut table = InlineTable::new(); table.extend(iter); table } } impl IntoIterator for InlineTable { type Item = (InternalString, Value); type IntoIter = InlineTableIntoIter; fn into_iter(self) -> Self::IntoIter { Box::new( self.items .into_iter() .filter(|(_, kv)| kv.value.is_value()) .map(|(k, kv)| (k, kv.value.into_value().unwrap())), ) } } impl<'s> IntoIterator for &'s InlineTable { type Item = (&'s str, &'s Value); type IntoIter = InlineTableIter<'s>; fn into_iter(self) -> Self::IntoIter { self.iter() } } fn decorate_inline_table(table: &mut InlineTable) { for (key_decor, value) in table .items .iter_mut() .filter(|&(_, ref kv)| kv.value.is_value()) .map(|(_, kv)| (&mut kv.key.decor, kv.value.as_value_mut().unwrap())) { key_decor.clear(); value.decor_mut().clear(); } } /// An owned iterator type over key/value pairs of an inline table. pub type InlineTableIntoIter = Box>; /// An iterator type over key/value pairs of an inline table. pub type InlineTableIter<'a> = Box + 'a>; /// A mutable iterator type over key/value pairs of an inline table. pub type InlineTableIterMut<'a> = Box, &'a mut Value)> + 'a>; impl TableLike for InlineTable { fn iter(&self) -> Iter<'_> { Box::new(self.items.iter().map(|(key, kv)| (&key[..], &kv.value))) } fn iter_mut(&mut self) -> IterMut<'_> { Box::new( self.items .iter_mut() .map(|(_, kv)| (kv.key.as_mut(), &mut kv.value)), ) } fn clear(&mut self) { self.clear(); } fn entry<'a>(&'a mut self, key: &str) -> crate::Entry<'a> { // Accept a `&str` rather than an owned type to keep `InternalString`, well, internal match self.items.entry(key.into()) { indexmap::map::Entry::Occupied(entry) => { crate::Entry::Occupied(crate::OccupiedEntry { entry }) } indexmap::map::Entry::Vacant(entry) => { crate::Entry::Vacant(crate::VacantEntry { entry, key: None }) } } } fn entry_format<'a>(&'a mut self, key: &Key) -> crate::Entry<'a> { // Accept a `&Key` to be consistent with `entry` match self.items.entry(key.get().into()) { indexmap::map::Entry::Occupied(entry) => { crate::Entry::Occupied(crate::OccupiedEntry { entry }) } indexmap::map::Entry::Vacant(entry) => crate::Entry::Vacant(crate::VacantEntry { entry, key: Some(key.to_owned()), }), } } fn get<'s>(&'s self, key: &str) -> Option<&'s Item> { self.items.get(key).map(|kv| &kv.value) } fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item> { self.items.get_mut(key).map(|kv| &mut kv.value) } fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> { self.get_key_value(key) } fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> { self.get_key_value_mut(key) } fn contains_key(&self, key: &str) -> bool { self.contains_key(key) } fn insert(&mut self, key: &str, value: Item) -> Option { self.insert(key, value.into_value().unwrap()) .map(Item::Value) } fn remove(&mut self, key: &str) -> Option { self.remove(key).map(Item::Value) } fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> { self.get_values() } fn fmt(&mut self) { self.fmt() } fn sort_values(&mut self) { self.sort_values() } fn set_dotted(&mut self, yes: bool) { self.set_dotted(yes) } fn is_dotted(&self) -> bool { self.is_dotted() } fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> { self.key_decor_mut(key) } fn key_decor(&self, key: &str) -> Option<&Decor> { self.key_decor(key) } } // `{ key1 = value1, ... }` pub(crate) const DEFAULT_INLINE_KEY_DECOR: (&str, &str) = (" ", " "); /// A view into a single location in a map, which may be vacant or occupied. pub enum InlineEntry<'a> { /// An occupied Entry. Occupied(InlineOccupiedEntry<'a>), /// A vacant Entry. Vacant(InlineVacantEntry<'a>), } impl<'a> InlineEntry<'a> { /// Returns the entry key /// /// # Examples /// /// ``` /// use toml_edit::Table; /// /// let mut map = Table::new(); /// /// assert_eq!("hello", map.entry("hello").key()); /// ``` pub fn key(&self) -> &str { match self { InlineEntry::Occupied(e) => e.key(), InlineEntry::Vacant(e) => e.key(), } } /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. pub fn or_insert(self, default: Value) -> &'a mut Value { match self { InlineEntry::Occupied(entry) => entry.into_mut(), InlineEntry::Vacant(entry) => entry.insert(default), } } /// Ensures a value is in the entry by inserting the result of the default function if empty, /// and returns a mutable reference to the value in the entry. pub fn or_insert_with Value>(self, default: F) -> &'a mut Value { match self { InlineEntry::Occupied(entry) => entry.into_mut(), InlineEntry::Vacant(entry) => entry.insert(default()), } } } /// A view into a single occupied location in a `IndexMap`. pub struct InlineOccupiedEntry<'a> { entry: indexmap::map::OccupiedEntry<'a, InternalString, TableKeyValue>, } impl<'a> InlineOccupiedEntry<'a> { /// Gets a reference to the entry key /// /// # Examples /// /// ``` /// use toml_edit::Table; /// /// let mut map = Table::new(); /// /// assert_eq!("foo", map.entry("foo").key()); /// ``` pub fn key(&self) -> &str { self.entry.key().as_str() } /// Gets a mutable reference to the entry key pub fn key_mut(&mut self) -> KeyMut<'_> { self.entry.get_mut().key.as_mut() } /// Gets a reference to the value in the entry. pub fn get(&self) -> &Value { self.entry.get().value.as_value().unwrap() } /// Gets a mutable reference to the value in the entry. pub fn get_mut(&mut self) -> &mut Value { self.entry.get_mut().value.as_value_mut().unwrap() } /// Converts the OccupiedEntry into a mutable reference to the value in the entry /// with a lifetime bound to the map itself pub fn into_mut(self) -> &'a mut Value { self.entry.into_mut().value.as_value_mut().unwrap() } /// Sets the value of the entry, and returns the entry's old value pub fn insert(&mut self, value: Value) -> Value { let mut value = Item::Value(value); std::mem::swap(&mut value, &mut self.entry.get_mut().value); value.into_value().unwrap() } /// Takes the value out of the entry, and returns it pub fn remove(self) -> Value { self.entry.shift_remove().value.into_value().unwrap() } } /// A view into a single empty location in a `IndexMap`. pub struct InlineVacantEntry<'a> { entry: indexmap::map::VacantEntry<'a, InternalString, TableKeyValue>, key: Option, } impl<'a> InlineVacantEntry<'a> { /// Gets a reference to the entry key /// /// # Examples /// /// ``` /// use toml_edit::Table; /// /// let mut map = Table::new(); /// /// assert_eq!("foo", map.entry("foo").key()); /// ``` pub fn key(&self) -> &str { self.entry.key().as_str() } /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it pub fn insert(self, value: Value) -> &'a mut Value { let entry = self.entry; let key = self.key.unwrap_or_else(|| Key::new(entry.key().as_str())); let value = Item::Value(value); entry .insert(TableKeyValue::new(key, value)) .value .as_value_mut() .unwrap() } }