toml_edit/
inline_table.rs

1use std::iter::FromIterator;
2
3use crate::key::Key;
4use crate::repr::Decor;
5use crate::table::{Iter, IterMut, KeyValuePairs, TableKeyValue, TableLike};
6use crate::{InternalString, Item, KeyMut, RawString, Table, Value};
7
8/// Type representing a TOML inline table,
9/// payload of the `Value::InlineTable` variant
10#[derive(Debug, Default, Clone)]
11pub struct InlineTable {
12    // `preamble` represents whitespaces in an empty table
13    preamble: RawString,
14    // prefix before `{` and suffix after `}`
15    decor: Decor,
16    pub(crate) span: Option<std::ops::Range<usize>>,
17    // whether this is a proxy for dotted keys
18    dotted: bool,
19    pub(crate) items: KeyValuePairs,
20}
21
22/// Constructors
23///
24/// See also `FromIterator`
25impl InlineTable {
26    /// Creates an empty table.
27    pub fn new() -> Self {
28        Default::default()
29    }
30
31    pub(crate) fn with_pairs(items: KeyValuePairs) -> Self {
32        Self {
33            items,
34            ..Default::default()
35        }
36    }
37
38    /// Convert to a table
39    pub fn into_table(self) -> Table {
40        let mut t = Table::with_pairs(self.items);
41        t.fmt();
42        t
43    }
44}
45
46/// Formatting
47impl InlineTable {
48    /// Get key/values for values that are visually children of this table
49    ///
50    /// For example, this will return dotted keys
51    pub fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> {
52        let mut values = Vec::new();
53        let root = Vec::new();
54        self.append_values(&root, &mut values);
55        values
56    }
57
58    pub(crate) fn append_values<'s, 'c>(
59        &'s self,
60        parent: &[&'s Key],
61        values: &'c mut Vec<(Vec<&'s Key>, &'s Value)>,
62    ) {
63        for value in self.items.values() {
64            let mut path = parent.to_vec();
65            path.push(&value.key);
66            match &value.value {
67                Item::Value(Value::InlineTable(table)) if table.is_dotted() => {
68                    table.append_values(&path, values);
69                }
70                Item::Value(value) => {
71                    values.push((path, value));
72                }
73                _ => {}
74            }
75        }
76    }
77
78    /// Auto formats the table.
79    pub fn fmt(&mut self) {
80        decorate_inline_table(self);
81    }
82
83    /// Sorts the key/value pairs by key.
84    pub fn sort_values(&mut self) {
85        // Assuming standard tables have their position set and this won't negatively impact them
86        self.items.sort_keys();
87        for kv in self.items.values_mut() {
88            match &mut kv.value {
89                Item::Value(Value::InlineTable(table)) if table.is_dotted() => {
90                    table.sort_values();
91                }
92                _ => {}
93            }
94        }
95    }
96
97    /// Sort Key/Value Pairs of the table using the using the comparison function `compare`.
98    ///
99    /// The comparison function receives two key and value pairs to compare (you can sort by keys or
100    /// values or their combination as needed).
101    pub fn sort_values_by<F>(&mut self, mut compare: F)
102    where
103        F: FnMut(&Key, &Value, &Key, &Value) -> std::cmp::Ordering,
104    {
105        self.sort_values_by_internal(&mut compare);
106    }
107
108    fn sort_values_by_internal<F>(&mut self, compare: &mut F)
109    where
110        F: FnMut(&Key, &Value, &Key, &Value) -> std::cmp::Ordering,
111    {
112        let modified_cmp = |_: &InternalString,
113                            val1: &TableKeyValue,
114                            _: &InternalString,
115                            val2: &TableKeyValue|
116         -> std::cmp::Ordering {
117            match (val1.value.as_value(), val2.value.as_value()) {
118                (Some(v1), Some(v2)) => compare(&val1.key, v1, &val2.key, v2),
119                (Some(_), None) => std::cmp::Ordering::Greater,
120                (None, Some(_)) => std::cmp::Ordering::Less,
121                (None, None) => std::cmp::Ordering::Equal,
122            }
123        };
124
125        self.items.sort_by(modified_cmp);
126        for kv in self.items.values_mut() {
127            match &mut kv.value {
128                Item::Value(Value::InlineTable(table)) if table.is_dotted() => {
129                    table.sort_values_by_internal(compare);
130                }
131                _ => {}
132            }
133        }
134    }
135
136    /// Change this table's dotted status
137    pub fn set_dotted(&mut self, yes: bool) {
138        self.dotted = yes;
139    }
140
141    /// Check if this is a wrapper for dotted keys, rather than a standard table
142    pub fn is_dotted(&self) -> bool {
143        self.dotted
144    }
145
146    /// Returns the surrounding whitespace
147    pub fn decor_mut(&mut self) -> &mut Decor {
148        &mut self.decor
149    }
150
151    /// Returns the surrounding whitespace
152    pub fn decor(&self) -> &Decor {
153        &self.decor
154    }
155
156    /// Returns the decor associated with a given key of the table.
157    pub fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> {
158        self.items.get_mut(key).map(|kv| &mut kv.key.decor)
159    }
160
161    /// Returns the decor associated with a given key of the table.
162    pub fn key_decor(&self, key: &str) -> Option<&Decor> {
163        self.items.get(key).map(|kv| &kv.key.decor)
164    }
165
166    /// Set whitespace after before element
167    pub fn set_preamble(&mut self, preamble: impl Into<RawString>) {
168        self.preamble = preamble.into();
169    }
170
171    /// Whitespace after before element
172    pub fn preamble(&self) -> &RawString {
173        &self.preamble
174    }
175
176    /// Returns the location within the original document
177    pub(crate) fn span(&self) -> Option<std::ops::Range<usize>> {
178        self.span.clone()
179    }
180
181    pub(crate) fn despan(&mut self, input: &str) {
182        self.span = None;
183        self.decor.despan(input);
184        self.preamble.despan(input);
185        for kv in self.items.values_mut() {
186            kv.key.despan(input);
187            kv.value.despan(input);
188        }
189    }
190}
191
192impl InlineTable {
193    /// Returns an iterator over key/value pairs.
194    pub fn iter(&self) -> InlineTableIter<'_> {
195        Box::new(
196            self.items
197                .iter()
198                .filter(|&(_, kv)| kv.value.is_value())
199                .map(|(k, kv)| (&k[..], kv.value.as_value().unwrap())),
200        )
201    }
202
203    /// Returns an iterator over key/value pairs.
204    pub fn iter_mut(&mut self) -> InlineTableIterMut<'_> {
205        Box::new(
206            self.items
207                .iter_mut()
208                .filter(|(_, kv)| kv.value.is_value())
209                .map(|(_, kv)| (kv.key.as_mut(), kv.value.as_value_mut().unwrap())),
210        )
211    }
212
213    /// Returns the number of key/value pairs.
214    pub fn len(&self) -> usize {
215        self.iter().count()
216    }
217
218    /// Returns true iff the table is empty.
219    pub fn is_empty(&self) -> bool {
220        self.len() == 0
221    }
222
223    /// Clears the table, removing all key-value pairs. Keeps the allocated memory for reuse.
224    pub fn clear(&mut self) {
225        self.items.clear()
226    }
227
228    /// Gets the given key's corresponding entry in the Table for in-place manipulation.
229    pub fn entry(&'_ mut self, key: impl Into<InternalString>) -> InlineEntry<'_> {
230        match self.items.entry(key.into()) {
231            indexmap::map::Entry::Occupied(mut entry) => {
232                // Ensure it is a `Value` to simplify `InlineOccupiedEntry`'s code.
233                let scratch = std::mem::take(&mut entry.get_mut().value);
234                let scratch = Item::Value(
235                    scratch
236                        .into_value()
237                        // HACK: `Item::None` is a corner case of a corner case, let's just pick a
238                        // "safe" value
239                        .unwrap_or_else(|_| Value::InlineTable(Default::default())),
240                );
241                entry.get_mut().value = scratch;
242
243                InlineEntry::Occupied(InlineOccupiedEntry { entry })
244            }
245            indexmap::map::Entry::Vacant(entry) => {
246                InlineEntry::Vacant(InlineVacantEntry { entry, key: None })
247            }
248        }
249    }
250
251    /// Gets the given key's corresponding entry in the Table for in-place manipulation.
252    pub fn entry_format<'a>(&'a mut self, key: &Key) -> InlineEntry<'a> {
253        // Accept a `&Key` to be consistent with `entry`
254        match self.items.entry(key.get().into()) {
255            indexmap::map::Entry::Occupied(mut entry) => {
256                // Ensure it is a `Value` to simplify `InlineOccupiedEntry`'s code.
257                let scratch = std::mem::take(&mut entry.get_mut().value);
258                let scratch = Item::Value(
259                    scratch
260                        .into_value()
261                        // HACK: `Item::None` is a corner case of a corner case, let's just pick a
262                        // "safe" value
263                        .unwrap_or_else(|_| Value::InlineTable(Default::default())),
264                );
265                entry.get_mut().value = scratch;
266
267                InlineEntry::Occupied(InlineOccupiedEntry { entry })
268            }
269            indexmap::map::Entry::Vacant(entry) => InlineEntry::Vacant(InlineVacantEntry {
270                entry,
271                key: Some(key.clone()),
272            }),
273        }
274    }
275    /// Return an optional reference to the value at the given the key.
276    pub fn get(&self, key: &str) -> Option<&Value> {
277        self.items.get(key).and_then(|kv| kv.value.as_value())
278    }
279
280    /// Return an optional mutable reference to the value at the given the key.
281    pub fn get_mut(&mut self, key: &str) -> Option<&mut Value> {
282        self.items
283            .get_mut(key)
284            .and_then(|kv| kv.value.as_value_mut())
285    }
286
287    /// Return references to the key-value pair stored for key, if it is present, else None.
288    pub fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> {
289        self.items.get(key).and_then(|kv| {
290            if !kv.value.is_none() {
291                Some((&kv.key, &kv.value))
292            } else {
293                None
294            }
295        })
296    }
297
298    /// Return mutable references to the key-value pair stored for key, if it is present, else None.
299    pub fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> {
300        self.items.get_mut(key).and_then(|kv| {
301            if !kv.value.is_none() {
302                Some((kv.key.as_mut(), &mut kv.value))
303            } else {
304                None
305            }
306        })
307    }
308
309    /// Returns true iff the table contains given key.
310    pub fn contains_key(&self, key: &str) -> bool {
311        if let Some(kv) = self.items.get(key) {
312            kv.value.is_value()
313        } else {
314            false
315        }
316    }
317
318    /// Inserts a key/value pair if the table does not contain the key.
319    /// Returns a mutable reference to the corresponding value.
320    pub fn get_or_insert<V: Into<Value>>(
321        &mut self,
322        key: impl Into<InternalString>,
323        value: V,
324    ) -> &mut Value {
325        let key = key.into();
326        self.items
327            .entry(key.clone())
328            .or_insert(TableKeyValue::new(Key::new(key), Item::Value(value.into())))
329            .value
330            .as_value_mut()
331            .expect("non-value type in inline table")
332    }
333
334    /// Inserts a key-value pair into the map.
335    pub fn insert(&mut self, key: impl Into<InternalString>, value: Value) -> Option<Value> {
336        let key = key.into();
337        let kv = TableKeyValue::new(Key::new(key.clone()), Item::Value(value));
338        self.items
339            .insert(key, kv)
340            .and_then(|kv| kv.value.into_value().ok())
341    }
342
343    /// Inserts a key-value pair into the map.
344    pub fn insert_formatted(&mut self, key: &Key, value: Value) -> Option<Value> {
345        let kv = TableKeyValue::new(key.to_owned(), Item::Value(value));
346        self.items
347            .insert(InternalString::from(key.get()), kv)
348            .filter(|kv| kv.value.is_value())
349            .map(|kv| kv.value.into_value().unwrap())
350    }
351
352    /// Removes an item given the key.
353    pub fn remove(&mut self, key: &str) -> Option<Value> {
354        self.items
355            .shift_remove(key)
356            .and_then(|kv| kv.value.into_value().ok())
357    }
358
359    /// Removes a key from the map, returning the stored key and value if the key was previously in the map.
360    pub fn remove_entry(&mut self, key: &str) -> Option<(Key, Value)> {
361        self.items.shift_remove(key).and_then(|kv| {
362            let key = kv.key;
363            kv.value.into_value().ok().map(|value| (key, value))
364        })
365    }
366
367    /// Retains only the elements specified by the `keep` predicate.
368    ///
369    /// In other words, remove all pairs `(key, value)` for which
370    /// `keep(&key, &mut value)` returns `false`.
371    ///
372    /// The elements are visited in iteration order.
373    pub fn retain<F>(&mut self, mut keep: F)
374    where
375        F: FnMut(&str, &mut Value) -> bool,
376    {
377        self.items.retain(|key, item| {
378            item.value
379                .as_value_mut()
380                .map(|value| keep(key, value))
381                .unwrap_or(false)
382        });
383    }
384}
385
386impl std::fmt::Display for InlineTable {
387    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
388        crate::encode::Encode::encode(self, f, None, ("", ""))
389    }
390}
391
392impl<K: Into<Key>, V: Into<Value>> Extend<(K, V)> for InlineTable {
393    fn extend<T: IntoIterator<Item = (K, V)>>(&mut self, iter: T) {
394        for (key, value) in iter {
395            let key = key.into();
396            let value = Item::Value(value.into());
397            let value = TableKeyValue::new(key, value);
398            self.items
399                .insert(InternalString::from(value.key.get()), value);
400        }
401    }
402}
403
404impl<K: Into<Key>, V: Into<Value>> FromIterator<(K, V)> for InlineTable {
405    fn from_iter<I>(iter: I) -> Self
406    where
407        I: IntoIterator<Item = (K, V)>,
408    {
409        let mut table = InlineTable::new();
410        table.extend(iter);
411        table
412    }
413}
414
415impl IntoIterator for InlineTable {
416    type Item = (InternalString, Value);
417    type IntoIter = InlineTableIntoIter;
418
419    fn into_iter(self) -> Self::IntoIter {
420        Box::new(
421            self.items
422                .into_iter()
423                .filter(|(_, kv)| kv.value.is_value())
424                .map(|(k, kv)| (k, kv.value.into_value().unwrap())),
425        )
426    }
427}
428
429impl<'s> IntoIterator for &'s InlineTable {
430    type Item = (&'s str, &'s Value);
431    type IntoIter = InlineTableIter<'s>;
432
433    fn into_iter(self) -> Self::IntoIter {
434        self.iter()
435    }
436}
437
438fn decorate_inline_table(table: &mut InlineTable) {
439    for (key_decor, value) in table
440        .items
441        .iter_mut()
442        .filter(|&(_, ref kv)| kv.value.is_value())
443        .map(|(_, kv)| (&mut kv.key.decor, kv.value.as_value_mut().unwrap()))
444    {
445        key_decor.clear();
446        value.decor_mut().clear();
447    }
448}
449
450/// An owned iterator type over key/value pairs of an inline table.
451pub type InlineTableIntoIter = Box<dyn Iterator<Item = (InternalString, Value)>>;
452/// An iterator type over key/value pairs of an inline table.
453pub type InlineTableIter<'a> = Box<dyn Iterator<Item = (&'a str, &'a Value)> + 'a>;
454/// A mutable iterator type over key/value pairs of an inline table.
455pub type InlineTableIterMut<'a> = Box<dyn Iterator<Item = (KeyMut<'a>, &'a mut Value)> + 'a>;
456
457impl TableLike for InlineTable {
458    fn iter(&self) -> Iter<'_> {
459        Box::new(self.items.iter().map(|(key, kv)| (&key[..], &kv.value)))
460    }
461    fn iter_mut(&mut self) -> IterMut<'_> {
462        Box::new(
463            self.items
464                .iter_mut()
465                .map(|(_, kv)| (kv.key.as_mut(), &mut kv.value)),
466        )
467    }
468    fn clear(&mut self) {
469        self.clear();
470    }
471    fn entry<'a>(&'a mut self, key: &str) -> crate::Entry<'a> {
472        // Accept a `&str` rather than an owned type to keep `InternalString`, well, internal
473        match self.items.entry(key.into()) {
474            indexmap::map::Entry::Occupied(entry) => {
475                crate::Entry::Occupied(crate::OccupiedEntry { entry })
476            }
477            indexmap::map::Entry::Vacant(entry) => {
478                crate::Entry::Vacant(crate::VacantEntry { entry, key: None })
479            }
480        }
481    }
482    fn entry_format<'a>(&'a mut self, key: &Key) -> crate::Entry<'a> {
483        // Accept a `&Key` to be consistent with `entry`
484        match self.items.entry(key.get().into()) {
485            indexmap::map::Entry::Occupied(entry) => {
486                crate::Entry::Occupied(crate::OccupiedEntry { entry })
487            }
488            indexmap::map::Entry::Vacant(entry) => crate::Entry::Vacant(crate::VacantEntry {
489                entry,
490                key: Some(key.to_owned()),
491            }),
492        }
493    }
494    fn get<'s>(&'s self, key: &str) -> Option<&'s Item> {
495        self.items.get(key).map(|kv| &kv.value)
496    }
497    fn get_mut<'s>(&'s mut self, key: &str) -> Option<&'s mut Item> {
498        self.items.get_mut(key).map(|kv| &mut kv.value)
499    }
500    fn get_key_value<'a>(&'a self, key: &str) -> Option<(&'a Key, &'a Item)> {
501        self.get_key_value(key)
502    }
503    fn get_key_value_mut<'a>(&'a mut self, key: &str) -> Option<(KeyMut<'a>, &'a mut Item)> {
504        self.get_key_value_mut(key)
505    }
506    fn contains_key(&self, key: &str) -> bool {
507        self.contains_key(key)
508    }
509    fn insert(&mut self, key: &str, value: Item) -> Option<Item> {
510        self.insert(key, value.into_value().unwrap())
511            .map(Item::Value)
512    }
513    fn remove(&mut self, key: &str) -> Option<Item> {
514        self.remove(key).map(Item::Value)
515    }
516
517    fn get_values(&self) -> Vec<(Vec<&Key>, &Value)> {
518        self.get_values()
519    }
520    fn fmt(&mut self) {
521        self.fmt()
522    }
523    fn sort_values(&mut self) {
524        self.sort_values()
525    }
526    fn set_dotted(&mut self, yes: bool) {
527        self.set_dotted(yes)
528    }
529    fn is_dotted(&self) -> bool {
530        self.is_dotted()
531    }
532
533    fn key_decor_mut(&mut self, key: &str) -> Option<&mut Decor> {
534        self.key_decor_mut(key)
535    }
536    fn key_decor(&self, key: &str) -> Option<&Decor> {
537        self.key_decor(key)
538    }
539}
540
541// `{ key1 = value1, ... }`
542pub(crate) const DEFAULT_INLINE_KEY_DECOR: (&str, &str) = (" ", " ");
543
544/// A view into a single location in a map, which may be vacant or occupied.
545pub enum InlineEntry<'a> {
546    /// An occupied Entry.
547    Occupied(InlineOccupiedEntry<'a>),
548    /// A vacant Entry.
549    Vacant(InlineVacantEntry<'a>),
550}
551
552impl<'a> InlineEntry<'a> {
553    /// Returns the entry key
554    ///
555    /// # Examples
556    ///
557    /// ```
558    /// use toml_edit::Table;
559    ///
560    /// let mut map = Table::new();
561    ///
562    /// assert_eq!("hello", map.entry("hello").key());
563    /// ```
564    pub fn key(&self) -> &str {
565        match self {
566            InlineEntry::Occupied(e) => e.key(),
567            InlineEntry::Vacant(e) => e.key(),
568        }
569    }
570
571    /// Ensures a value is in the entry by inserting the default if empty, and returns
572    /// a mutable reference to the value in the entry.
573    pub fn or_insert(self, default: Value) -> &'a mut Value {
574        match self {
575            InlineEntry::Occupied(entry) => entry.into_mut(),
576            InlineEntry::Vacant(entry) => entry.insert(default),
577        }
578    }
579
580    /// Ensures a value is in the entry by inserting the result of the default function if empty,
581    /// and returns a mutable reference to the value in the entry.
582    pub fn or_insert_with<F: FnOnce() -> Value>(self, default: F) -> &'a mut Value {
583        match self {
584            InlineEntry::Occupied(entry) => entry.into_mut(),
585            InlineEntry::Vacant(entry) => entry.insert(default()),
586        }
587    }
588}
589
590/// A view into a single occupied location in a `IndexMap`.
591pub struct InlineOccupiedEntry<'a> {
592    entry: indexmap::map::OccupiedEntry<'a, InternalString, TableKeyValue>,
593}
594
595impl<'a> InlineOccupiedEntry<'a> {
596    /// Gets a reference to the entry key
597    ///
598    /// # Examples
599    ///
600    /// ```
601    /// use toml_edit::Table;
602    ///
603    /// let mut map = Table::new();
604    ///
605    /// assert_eq!("foo", map.entry("foo").key());
606    /// ```
607    pub fn key(&self) -> &str {
608        self.entry.key().as_str()
609    }
610
611    /// Gets a mutable reference to the entry key
612    pub fn key_mut(&mut self) -> KeyMut<'_> {
613        self.entry.get_mut().key.as_mut()
614    }
615
616    /// Gets a reference to the value in the entry.
617    pub fn get(&self) -> &Value {
618        self.entry.get().value.as_value().unwrap()
619    }
620
621    /// Gets a mutable reference to the value in the entry.
622    pub fn get_mut(&mut self) -> &mut Value {
623        self.entry.get_mut().value.as_value_mut().unwrap()
624    }
625
626    /// Converts the OccupiedEntry into a mutable reference to the value in the entry
627    /// with a lifetime bound to the map itself
628    pub fn into_mut(self) -> &'a mut Value {
629        self.entry.into_mut().value.as_value_mut().unwrap()
630    }
631
632    /// Sets the value of the entry, and returns the entry's old value
633    pub fn insert(&mut self, value: Value) -> Value {
634        let mut value = Item::Value(value);
635        std::mem::swap(&mut value, &mut self.entry.get_mut().value);
636        value.into_value().unwrap()
637    }
638
639    /// Takes the value out of the entry, and returns it
640    pub fn remove(self) -> Value {
641        self.entry.shift_remove().value.into_value().unwrap()
642    }
643}
644
645/// A view into a single empty location in a `IndexMap`.
646pub struct InlineVacantEntry<'a> {
647    entry: indexmap::map::VacantEntry<'a, InternalString, TableKeyValue>,
648    key: Option<Key>,
649}
650
651impl<'a> InlineVacantEntry<'a> {
652    /// Gets a reference to the entry key
653    ///
654    /// # Examples
655    ///
656    /// ```
657    /// use toml_edit::Table;
658    ///
659    /// let mut map = Table::new();
660    ///
661    /// assert_eq!("foo", map.entry("foo").key());
662    /// ```
663    pub fn key(&self) -> &str {
664        self.entry.key().as_str()
665    }
666
667    /// Sets the value of the entry with the VacantEntry's key,
668    /// and returns a mutable reference to it
669    pub fn insert(self, value: Value) -> &'a mut Value {
670        let entry = self.entry;
671        let key = self.key.unwrap_or_else(|| Key::new(entry.key().as_str()));
672        let value = Item::Value(value);
673        entry
674            .insert(TableKeyValue::new(key, value))
675            .value
676            .as_value_mut()
677            .unwrap()
678    }
679}