use std::iter::FromIterator; use indexmap::map::IndexMap; use crate::key::Key; use crate::repr::Decor; use crate::value::DEFAULT_VALUE_DECOR; use crate::{InlineTable, InternalString, Item, KeyMut, Value}; /// Type representing a TOML non-inline table #[derive(Clone, Debug, Default)] pub struct Table { // Comments/spaces before and after the header pub(crate) decor: Decor, // Whether to hide an empty table pub(crate) implicit: bool, // Whether this is a proxy for dotted keys pub(crate) dotted: bool, // Used for putting tables back in their original order when serialising. // // `None` for user created tables (can be overridden with `set_position`) doc_position: Option, pub(crate) span: Option>, 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) -> Self { Self { doc_position, ..Default::default() } } pub(crate) fn with_pairs(items: KeyValuePairs) -> Self { Self { items, ..Default::default() } } /// Convert to an inline table pub fn into_inline_table(mut self) -> InlineTable { for (_, kv) in self.items.iter_mut() { kv.value.make_value(); } let mut t = InlineTable::with_pairs(self.items); t.fmt(); t } } /// Formatting impl Table { /// Get key/values for values that are visually children of this table /// /// For example, this will return dotted keys pub fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> { let mut values = Vec::new(); let root = Vec::new(); self.append_values(&root, &mut values); values } fn append_values<'s, 'c>( &'s self, parent: &[&'s Key], values: &'c mut Vec<(Vec<&'s Key>, &'s Value)>, ) { for value in self.items.values() { let mut path = parent.to_vec(); path.push(&value.key); match &value.value { Item::Table(table) if table.is_dotted() => { table.append_values(&path, values); } Item::Value(value) => { if let Some(table) = value.as_inline_table() { if table.is_dotted() { table.append_values(&path, values); } else { values.push((path, value)); } } else { values.push((path, value)); } } _ => {} } } } /// Auto formats the table. pub fn fmt(&mut self) { decorate_table(self); } /// Sorts Key/Value Pairs of the table. /// /// Doesn't affect subtables or subarrays. pub fn sort_values(&mut self) { // Assuming standard tables have their doc_position set and this won't negatively impact them self.items.sort_keys(); for kv in self.items.values_mut() { match &mut kv.value { Item::Table(table) if table.is_dotted() => { table.sort_values(); } _ => {} } } } /// Sort Key/Value Pairs of the table using the using the comparison function `compare`. /// /// The comparison function receives two key and value pairs to compare (you can sort by keys or /// values or their combination as needed). pub fn sort_values_by(&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(&mut self, compare: &mut F) where F: FnMut(&Key, &Item, &Key, &Item) -> std::cmp::Ordering, { let modified_cmp = |_: &InternalString, val1: &TableKeyValue, _: &InternalString, val2: &TableKeyValue| -> std::cmp::Ordering { compare(&val1.key, &val1.value, &val2.key, &val2.value) }; self.items.sort_by(modified_cmp); for kv in self.items.values_mut() { match &mut kv.value { Item::Table(table) if table.is_dotted() => { table.sort_values_by_internal(compare); } _ => {} } } } /// If a table has no key/value pairs and implicit, it will not be displayed. /// /// # Examples /// /// ```notrust /// [target."x86_64/windows.json".dependencies] /// ``` /// /// In the document above, tables `target` and `target."x86_64/windows.json"` are implicit. /// /// ``` /// use toml_edit::Document; /// let mut doc = "[a]\n[a.b]\n".parse::().expect("invalid toml"); /// /// doc["a"].as_table_mut().unwrap().set_implicit(true); /// assert_eq!(doc.to_string(), "[a.b]\n"); /// ``` pub fn set_implicit(&mut self, implicit: bool) { self.implicit = implicit; } /// If a table has no key/value pairs and implicit, it will not be displayed. pub fn is_implicit(&self) -> bool { self.implicit } /// Change this table's dotted status pub fn set_dotted(&mut self, yes: bool) { self.dotted = yes; } /// Check if this is a wrapper for dotted keys, rather than a standard table pub fn is_dotted(&self) -> bool { self.dotted } /// Sets the position of the `Table` within the `Document`. pub fn set_position(&mut self, doc_position: usize) { self.doc_position = Some(doc_position); } /// The position of the `Table` within the `Document`. /// /// Returns `None` if the `Table` was created manually (i.e. not via parsing) /// in which case its position is set automatically. This can be overridden with /// [`Table::set_position`]. pub fn position(&self) -> Option { self.doc_position } /// Returns the surrounding whitespace pub fn decor_mut(&mut self) -> &mut Decor { &mut self.decor } /// Returns the decor associated with a given key of the table. pub fn decor(&self) -> &Decor { &self.decor } /// Returns the decor associated with a given key of the table. pub fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> { self.items.get_mut(key).map(|kv| &mut kv.key.decor) } /// Returns the decor associated with a given key of the table. pub fn key_decor(&self, key: &str) -> Option<&Decor> { self.items.get(key).map(|kv| &kv.key.decor) } /// Returns the location within the original document pub(crate) fn span(&self) -> Option> { self.span.clone() } pub(crate) fn despan(&mut self, input: &str) { self.span = None; self.decor.despan(input); for kv in self.items.values_mut() { kv.key.despan(input); kv.value.despan(input); } } } impl Table { /// Returns an iterator over all key/value pairs, including empty. pub fn iter(&self) -> Iter<'_> { Box::new( self.items .iter() .filter(|(_, kv)| !kv.value.is_none()) .map(|(key, kv)| (&key[..], &kv.value)), ) } /// Returns an mutable iterator over all key/value pairs, including empty. pub fn iter_mut(&mut self) -> IterMut<'_> { Box::new( self.items .iter_mut() .filter(|(_, kv)| !kv.value.is_none()) .map(|(_, kv)| (kv.key.as_mut(), &mut kv.value)), ) } /// Returns the number of non-empty items in the table. pub fn len(&self) -> usize { self.items.iter().filter(|i| !(i.1).value.is_none()).count() } /// Returns true if the table is empty. pub fn is_empty(&self) -> bool { self.len() == 0 } /// Clears the table, removing all key-value pairs. Keeps the allocated memory for reuse. pub fn clear(&mut self) { self.items.clear() } /// Gets the given key's corresponding entry in the Table for in-place manipulation. pub fn entry<'a>(&'a mut self, key: &str) -> Entry<'a> { // Accept a `&str` rather than an owned type to keep `InternalString`, well, internal match self.items.entry(key.into()) { indexmap::map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { entry }), indexmap::map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { entry, key: None }), } } /// Gets the given key's corresponding entry in the Table for in-place manipulation. pub fn entry_format<'a>(&'a mut self, key: &Key) -> Entry<'a> { // Accept a `&Key` to be consistent with `entry` match self.items.entry(key.get().into()) { indexmap::map::Entry::Occupied(entry) => Entry::Occupied(OccupiedEntry { entry }), indexmap::map::Entry::Vacant(entry) => Entry::Vacant(VacantEntry { entry, key: Some(key.to_owned()), }), } } /// Returns an optional reference to an item given the key. pub fn get<'a>(&'a self, key: &str) -> Option<&'a Item> { self.items.get(key).and_then(|kv| { if !kv.value.is_none() { Some(&kv.value) } else { None } }) } /// Returns an optional mutable reference to an item given the key. pub fn get_mut<'a>(&'a mut self, key: &str) -> Option<&'a mut Item> { self.items.get_mut(key).and_then(|kv| { if !kv.value.is_none() { Some(&mut kv.value) } else { None } }) } /// Return references to the key-value pair stored for key, if it is present, else None. pub fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> { self.items.get(key).and_then(|kv| { if !kv.value.is_none() { Some((&kv.key, &kv.value)) } else { None } }) } /// Return mutable references to the key-value pair stored for key, if it is present, else None. pub fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> { self.items.get_mut(key).and_then(|kv| { if !kv.value.is_none() { Some((kv.key.as_mut(), &mut kv.value)) } else { None } }) } /// Returns true if the table contains an item with the given key. pub fn contains_key(&self, key: &str) -> bool { if let Some(kv) = self.items.get(key) { !kv.value.is_none() } else { false } } /// Returns true if the table contains a table with the given key. pub fn contains_table(&self, key: &str) -> bool { if let Some(kv) = self.items.get(key) { kv.value.is_table() } else { false } } /// Returns true if the table contains a value with the given key. pub fn contains_value(&self, key: &str) -> bool { if let Some(kv) = self.items.get(key) { kv.value.is_value() } else { false } } /// Returns true if the table contains an array of tables with the given key. pub fn contains_array_of_tables(&self, key: &str) -> bool { if let Some(kv) = self.items.get(key) { kv.value.is_array_of_tables() } else { false } } /// Inserts a key-value pair into the map. pub fn insert(&mut self, key: &str, item: Item) -> Option { let kv = TableKeyValue::new(Key::new(key), item); self.items.insert(key.into(), kv).map(|kv| kv.value) } /// Inserts a key-value pair into the map. pub fn insert_formatted(&mut self, key: &Key, item: Item) -> Option { let kv = TableKeyValue::new(key.to_owned(), item); self.items.insert(key.get().into(), kv).map(|kv| kv.value) } /// Removes an item given the key. pub fn remove(&mut self, key: &str) -> Option { self.items.shift_remove(key).map(|kv| kv.value) } /// Removes a key from the map, returning the stored key and value if the key was previously in the map. pub fn remove_entry(&mut self, key: &str) -> Option<(Key, Item)> { self.items.shift_remove(key).map(|kv| (kv.key, kv.value)) } /// 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(&mut self, mut keep: F) where F: FnMut(&str, &mut Item) -> bool, { self.items .retain(|key, key_value| keep(key, &mut key_value.value)); } } impl std::fmt::Display for Table { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { use crate::encode::Encode; let children = self.get_values(); // print table body for (key_path, value) in children { key_path.as_slice().encode(f, None, DEFAULT_KEY_DECOR)?; write!(f, "=")?; value.encode(f, None, DEFAULT_VALUE_DECOR)?; writeln!(f)?; } Ok(()) } } impl, V: Into> Extend<(K, V)> for Table { 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(value.key.get().into(), value); } } } impl, V: Into> FromIterator<(K, V)> for Table { fn from_iter(iter: I) -> Self where I: IntoIterator, { let mut table = Table::new(); table.extend(iter); table } } impl IntoIterator for Table { type Item = (InternalString, Item); type IntoIter = IntoIter; fn into_iter(self) -> Self::IntoIter { Box::new(self.items.into_iter().map(|(k, kv)| (k, kv.value))) } } impl<'s> IntoIterator for &'s Table { type Item = (&'s str, &'s Item); type IntoIter = Iter<'s>; fn into_iter(self) -> Self::IntoIter { self.iter() } } pub(crate) type KeyValuePairs = IndexMap; fn decorate_table(table: &mut Table) { for (key_decor, value) in table .items .iter_mut() .filter(|&(_, ref kv)| kv.value.is_value()) .map(|(_, kv)| (&mut kv.key.decor, kv.value.as_value_mut().unwrap())) { key_decor.clear(); value.decor_mut().clear(); } } // `key1 = value1` pub(crate) const DEFAULT_KEY_DECOR: (&str, &str) = ("", " "); pub(crate) const DEFAULT_TABLE_DECOR: (&str, &str) = ("\n", ""); pub(crate) const DEFAULT_KEY_PATH_DECOR: (&str, &str) = ("", ""); #[derive(Debug, Clone)] pub(crate) struct TableKeyValue { pub(crate) key: Key, pub(crate) value: Item, } impl TableKeyValue { pub(crate) fn new(key: Key, value: Item) -> Self { TableKeyValue { key, value } } } /// An owned iterator type over `Table`'s key/value pairs. pub type IntoIter = Box>; /// An iterator type over `Table`'s key/value pairs. pub type Iter<'a> = Box + 'a>; /// A mutable iterator type over `Table`'s key/value pairs. pub type IterMut<'a> = Box, &'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; /// Removes an item given the key. fn remove(&mut self, key: &str) -> Option; /// Get key/values for values that are visually children of this table /// /// For example, this will return dotted keys fn get_values(&self) -> Vec<(Vec<&Key>, &Value)>; /// Auto formats the table. fn fmt(&mut self); /// Sorts Key/Value Pairs of the table. /// /// Doesn't affect subtables or subarrays. fn sort_values(&mut self); /// Change this table's dotted status fn set_dotted(&mut self, yes: bool); /// Check if this is a wrapper for dotted keys, rather than a standard table fn is_dotted(&self) -> bool; /// Returns the decor associated with a given key of the table. fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor>; /// Returns the decor associated with a given key of the table. fn key_decor(&self, key: &str) -> Option<&Decor>; } impl TableLike for Table { fn iter(&self) -> Iter<'_> { self.iter() } fn iter_mut(&mut self) -> IterMut<'_> { self.iter_mut() } fn clear(&mut self) { self.clear(); } fn entry<'a>(&'a mut self, key: &str) -> Entry<'a> { self.entry(key) } fn entry_format<'a>(&'a mut self, key: &Key) -> Entry<'a> { self.entry_format(key) } fn get<'s>(&'s self, key: &str) -> Option<&'s Item> { self.get(key) } fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item> { self.get_mut(key) } fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> { self.get_key_value(key) } fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> { self.get_key_value_mut(key) } fn contains_key(&self, key: &str) -> bool { self.contains_key(key) } fn insert(&mut self, key: &str, value: Item) -> Option { self.insert(key, value) } fn remove(&mut self, key: &str) -> Option { self.remove(key) } fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> { self.get_values() } fn fmt(&mut self) { self.fmt() } fn sort_values(&mut self) { self.sort_values() } fn is_dotted(&self) -> bool { self.is_dotted() } fn set_dotted(&mut self, yes: bool) { self.set_dotted(yes) } fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> { self.key_decor_mut(key) } fn key_decor(&self, key: &str) -> Option<&Decor> { self.key_decor(key) } } /// A view into a single location in a map, which may be vacant or occupied. pub enum Entry<'a> { /// An occupied Entry. Occupied(OccupiedEntry<'a>), /// A vacant Entry. Vacant(VacantEntry<'a>), } impl<'a> Entry<'a> { /// Returns the entry key /// /// # Examples /// /// ``` /// use toml_edit::Table; /// /// let mut map = Table::new(); /// /// assert_eq!("hello", map.entry("hello").key()); /// ``` pub fn key(&self) -> &str { match self { Entry::Occupied(e) => e.key(), Entry::Vacant(e) => e.key(), } } /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. pub fn or_insert(self, default: Item) -> &'a mut Item { match self { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => entry.insert(default), } } /// Ensures a value is in the entry by inserting the result of the default function if empty, /// and returns a mutable reference to the value in the entry. pub fn or_insert_with Item>(self, default: F) -> &'a mut Item { match self { Entry::Occupied(entry) => entry.into_mut(), Entry::Vacant(entry) => entry.insert(default()), } } } /// A view into a single occupied location in a `IndexMap`. pub struct OccupiedEntry<'a> { pub(crate) entry: indexmap::map::OccupiedEntry<'a, InternalString, TableKeyValue>, } impl<'a> OccupiedEntry<'a> { /// Gets a reference to the entry key /// /// # Examples /// /// ``` /// use toml_edit::Table; /// /// let mut map = Table::new(); /// /// assert_eq!("foo", map.entry("foo").key()); /// ``` pub fn key(&self) -> &str { self.entry.key().as_str() } /// Gets a mutable reference to the entry key pub fn key_mut(&mut self) -> KeyMut<'_> { self.entry.get_mut().key.as_mut() } /// Gets a reference to the value in the entry. pub fn get(&self) -> &Item { &self.entry.get().value } /// Gets a mutable reference to the value in the entry. pub fn get_mut(&mut self) -> &mut Item { &mut self.entry.get_mut().value } /// Converts the OccupiedEntry into a mutable reference to the value in the entry /// with a lifetime bound to the map itself pub fn into_mut(self) -> &'a mut Item { &mut self.entry.into_mut().value } /// Sets the value of the entry, and returns the entry's old value pub fn insert(&mut self, mut value: Item) -> Item { std::mem::swap(&mut value, &mut self.entry.get_mut().value); value } /// Takes the value out of the entry, and returns it pub fn remove(self) -> Item { self.entry.shift_remove().value } } /// A view into a single empty location in a `IndexMap`. pub struct VacantEntry<'a> { pub(crate) entry: indexmap::map::VacantEntry<'a, InternalString, TableKeyValue>, pub(crate) key: Option, } impl<'a> VacantEntry<'a> { /// Gets a reference to the entry key /// /// # Examples /// /// ``` /// use toml_edit::Table; /// /// let mut map = Table::new(); /// /// assert_eq!("foo", map.entry("foo").key()); /// ``` pub fn key(&self) -> &str { self.entry.key().as_str() } /// Sets the value of the entry with the VacantEntry's key, /// and returns a mutable reference to it pub fn insert(self, value: Item) -> &'a mut Item { let entry = self.entry; let key = self.key.unwrap_or_else(|| Key::new(entry.key().as_str())); &mut entry.insert(TableKeyValue::new(key, value)).value } }