Skip to main content

toml_edit/
array_of_tables.rs

1use std::iter::FromIterator;
2
3use crate::{Array, Item, Table};
4
5/// A top-level sequence of [`Table`]s, each under their own header
6#[derive(Clone, Debug, Default)]
7pub struct ArrayOfTables {
8    // Always Vec<Item::Table>, just `Item` to make `Index` work
9    pub(crate) span: Option<std::ops::Range<usize>>,
10    pub(crate) values: Vec<Item>,
11}
12
13/// Constructors
14///
15/// See also `FromIterator`
16impl ArrayOfTables {
17    /// Creates an empty array of tables.
18    pub fn new() -> Self {
19        Default::default()
20    }
21}
22
23/// Formatting
24impl ArrayOfTables {
25    /// Convert to an inline array
26    pub fn into_array(mut self) -> Array {
27        for value in self.values.iter_mut() {
28            value.make_value();
29        }
30        let mut a = Array::with_vec(self.values);
31        a.fmt();
32        a
33    }
34
35    /// The location within the original document
36    ///
37    /// This generally requires a [`Document`][crate::Document].
38    pub fn span(&self) -> Option<std::ops::Range<usize>> {
39        self.span.clone()
40    }
41
42    pub(crate) fn despan(&mut self, input: &str) {
43        self.span = None;
44        for value in &mut self.values {
45            value.despan(input);
46        }
47    }
48}
49
50impl ArrayOfTables {
51    /// Returns an iterator over tables.
52    pub fn iter(&self) -> ArrayOfTablesIter<'_> {
53        Box::new(self.iter_tables())
54    }
55
56    pub(crate) fn iter_tables(&self) -> impl Iterator<Item = &Table> {
57        self.values.iter().filter_map(Item::as_table)
58    }
59
60    /// Returns an iterator over tables.
61    pub fn iter_mut(&mut self) -> ArrayOfTablesIterMut<'_> {
62        Box::new(self.values.iter_mut().filter_map(Item::as_table_mut))
63    }
64
65    /// Returns the length of the underlying Vec.
66    /// To get the actual number of items use `a.iter().count()`.
67    pub fn len(&self) -> usize {
68        self.values.len()
69    }
70
71    /// Returns true if `self.len() == 0`.
72    pub fn is_empty(&self) -> bool {
73        self.len() == 0
74    }
75
76    /// Removes all the tables.
77    pub fn clear(&mut self) {
78        self.values.clear();
79    }
80
81    /// Returns an optional reference to the table.
82    pub fn get(&self, index: usize) -> Option<&Table> {
83        self.values.get(index).and_then(Item::as_table)
84    }
85
86    /// Returns an optional mutable reference to the table.
87    pub fn get_mut(&mut self, index: usize) -> Option<&mut Table> {
88        self.values.get_mut(index).and_then(Item::as_table_mut)
89    }
90
91    /// Appends a table to the array.
92    pub fn push(&mut self, table: Table) {
93        self.values.push(Item::Table(table));
94    }
95
96    /// Inserts a table at the given index within the array, shifting all
97    /// tables after it to the right.
98    ///
99    /// # Panics
100    ///
101    /// Panics if `index > len`.
102    pub fn insert(&mut self, index: usize, table: Table) {
103        self.values.insert(index, Item::Table(table));
104    }
105
106    /// Replaces a table at the given index within the array, returning the old table.
107    ///
108    /// # Panics
109    ///
110    /// Panics if `index >= len`.
111    ///
112    /// # Examples
113    ///
114    /// ```rust
115    /// use toml_edit::{ArrayOfTables, Table, value};
116    ///
117    /// let mut arr = ArrayOfTables::new();
118    /// arr.push(Table::from_iter([("name", value("apple"))]));
119    ///
120    /// arr.replace(0, Table::from_iter([("name", value("banana"))]));
121    /// ```
122    pub fn replace(&mut self, index: usize, table: Table) -> Table {
123        match std::mem::replace(&mut self.values[index], Item::Table(table)) {
124            Item::Table(old) => old,
125            x => panic!("non-table item {x:?} in an array of tables"),
126        }
127    }
128
129    /// Removes a table with the given index.
130    pub fn remove(&mut self, index: usize) -> Table {
131        self.values
132            .remove(index)
133            .into_table()
134            .expect("cannot have any other item in an array-of-tables")
135    }
136
137    /// Retains only the elements specified by the `keep` predicate.
138    ///
139    /// In other words, remove all tables for which `keep(&table)` returns `false`.
140    ///
141    /// This method operates in place, visiting each element exactly once in the
142    /// original order, and preserves the order of the retained elements.
143    pub fn retain<F>(&mut self, mut keep: F)
144    where
145        F: FnMut(&Table) -> bool,
146    {
147        self.values
148            .retain(|item| item.as_table().map(&mut keep).unwrap_or(false));
149    }
150}
151
152/// An iterator type over [`ArrayOfTables`]'s [`Table`]s
153pub type ArrayOfTablesIter<'a> = Box<dyn Iterator<Item = &'a Table> + 'a>;
154/// An iterator type over [`ArrayOfTables`]'s [`Table`]s
155pub type ArrayOfTablesIterMut<'a> = Box<dyn Iterator<Item = &'a mut Table> + 'a>;
156/// An iterator type over [`ArrayOfTables`]'s [`Table`]s
157pub type ArrayOfTablesIntoIter = Box<dyn Iterator<Item = Table>>;
158
159impl Extend<Table> for ArrayOfTables {
160    fn extend<T: IntoIterator<Item = Table>>(&mut self, iter: T) {
161        for value in iter {
162            self.push(value);
163        }
164    }
165}
166
167impl FromIterator<Table> for ArrayOfTables {
168    fn from_iter<I>(iter: I) -> Self
169    where
170        I: IntoIterator<Item = Table>,
171    {
172        let v = iter.into_iter().map(Item::Table);
173        Self {
174            values: v.collect(),
175            span: None,
176        }
177    }
178}
179
180impl IntoIterator for ArrayOfTables {
181    type Item = Table;
182    type IntoIter = ArrayOfTablesIntoIter;
183
184    fn into_iter(self) -> Self::IntoIter {
185        Box::new(
186            self.values
187                .into_iter()
188                .filter(|v| v.is_table())
189                .map(|v| v.into_table().unwrap()),
190        )
191    }
192}
193
194impl<'s> IntoIterator for &'s ArrayOfTables {
195    type Item = &'s Table;
196    type IntoIter = ArrayOfTablesIter<'s>;
197
198    fn into_iter(self) -> Self::IntoIter {
199        self.iter()
200    }
201}
202
203#[cfg(feature = "display")]
204impl std::fmt::Display for ArrayOfTables {
205    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
206        // HACK: Without the header, we don't really have a proper way of printing this
207        self.clone().into_array().fmt(f)
208    }
209}