1 use std::iter::FromIterator;
2 use std::mem;
3 
4 use crate::repr::Decor;
5 use crate::value::{DEFAULT_LEADING_VALUE_DECOR, DEFAULT_VALUE_DECOR};
6 use crate::{Item, RawString, Value};
7 
8 /// Type representing a TOML array,
9 /// payload of the `Value::Array` variant's value
10 #[derive(Debug, Default, Clone)]
11 pub struct Array {
12     // `trailing` represents whitespaces, newlines
13     // and comments in an empty array or after the trailing comma
14     trailing: RawString,
15     trailing_comma: bool,
16     // prefix before `[` and suffix after `]`
17     decor: Decor,
18     pub(crate) span: Option<std::ops::Range<usize>>,
19     // always Vec<Item::Value>
20     pub(crate) values: Vec<Item>,
21 }
22 
23 /// An owned iterator type over `Table`'s key/value pairs.
24 pub type ArrayIntoIter = Box<dyn Iterator<Item = Value>>;
25 /// An iterator type over `Array`'s values.
26 pub type ArrayIter<'a> = Box<dyn Iterator<Item = &'a Value> + 'a>;
27 /// An iterator type over `Array`'s values.
28 pub type ArrayIterMut<'a> = Box<dyn Iterator<Item = &'a mut Value> + 'a>;
29 
30 /// Constructors
31 ///
32 /// See also `FromIterator`
33 impl Array {
34     /// Create an empty `Array`
35     ///
36     /// # Examples
37     ///
38     /// ```rust
39     /// let mut arr = toml_edit::Array::new();
40     /// ```
new() -> Self41     pub fn new() -> Self {
42         Default::default()
43     }
44 
with_vec(values: Vec<Item>) -> Self45     pub(crate) fn with_vec(values: Vec<Item>) -> Self {
46         Self {
47             values,
48             ..Default::default()
49         }
50     }
51 }
52 
53 /// Formatting
54 impl Array {
55     /// Auto formats the array.
fmt(&mut self)56     pub fn fmt(&mut self) {
57         decorate_array(self);
58     }
59 
60     /// Set whether the array will use a trailing comma
set_trailing_comma(&mut self, yes: bool)61     pub fn set_trailing_comma(&mut self, yes: bool) {
62         self.trailing_comma = yes;
63     }
64 
65     /// Whether the array will use a trailing comma
trailing_comma(&self) -> bool66     pub fn trailing_comma(&self) -> bool {
67         self.trailing_comma
68     }
69 
70     /// Set whitespace after last element
set_trailing(&mut self, trailing: impl Into<RawString>)71     pub fn set_trailing(&mut self, trailing: impl Into<RawString>) {
72         self.trailing = trailing.into();
73     }
74 
75     /// Whitespace after last element
trailing(&self) -> &RawString76     pub fn trailing(&self) -> &RawString {
77         &self.trailing
78     }
79 
80     /// Returns the surrounding whitespace
decor_mut(&mut self) -> &mut Decor81     pub fn decor_mut(&mut self) -> &mut Decor {
82         &mut self.decor
83     }
84 
85     /// Returns the surrounding whitespace
decor(&self) -> &Decor86     pub fn decor(&self) -> &Decor {
87         &self.decor
88     }
89 
90     /// Returns the location within the original document
span(&self) -> Option<std::ops::Range<usize>>91     pub(crate) fn span(&self) -> Option<std::ops::Range<usize>> {
92         self.span.clone()
93     }
94 
despan(&mut self, input: &str)95     pub(crate) fn despan(&mut self, input: &str) {
96         self.span = None;
97         self.decor.despan(input);
98         self.trailing.despan(input);
99         for value in &mut self.values {
100             value.despan(input);
101         }
102     }
103 }
104 
105 impl Array {
106     /// Returns an iterator over all values.
iter(&self) -> ArrayIter<'_>107     pub fn iter(&self) -> ArrayIter<'_> {
108         Box::new(self.values.iter().filter_map(Item::as_value))
109     }
110 
111     /// Returns an iterator over all values.
iter_mut(&mut self) -> ArrayIterMut<'_>112     pub fn iter_mut(&mut self) -> ArrayIterMut<'_> {
113         Box::new(self.values.iter_mut().filter_map(Item::as_value_mut))
114     }
115 
116     /// Returns the length of the underlying Vec.
117     ///
118     /// In some rare cases, placeholder elements will exist.  For a more accurate count, call
119     /// `a.iter().count()`
120     ///
121     /// # Examples
122     ///
123     /// ```rust
124     /// let mut arr = toml_edit::Array::new();
125     /// arr.push(1);
126     /// arr.push("foo");
127     /// assert_eq!(arr.len(), 2);
128     /// ```
len(&self) -> usize129     pub fn len(&self) -> usize {
130         self.values.len()
131     }
132 
133     /// Return true iff `self.len() == 0`.
134     ///
135     /// # Examples
136     ///
137     /// ```rust
138     /// let mut arr = toml_edit::Array::new();
139     /// assert!(arr.is_empty());
140     ///
141     /// arr.push(1);
142     /// arr.push("foo");
143     /// assert!(! arr.is_empty());
144     /// ```
is_empty(&self) -> bool145     pub fn is_empty(&self) -> bool {
146         self.len() == 0
147     }
148 
149     /// Clears the array, removing all values. Keeps the allocated memory for reuse.
clear(&mut self)150     pub fn clear(&mut self) {
151         self.values.clear()
152     }
153 
154     /// Returns a reference to the value at the given index, or `None` if the index is out of
155     /// bounds.
get(&self, index: usize) -> Option<&Value>156     pub fn get(&self, index: usize) -> Option<&Value> {
157         self.values.get(index).and_then(Item::as_value)
158     }
159 
160     /// Returns a reference to the value at the given index, or `None` if the index is out of
161     /// bounds.
get_mut(&mut self, index: usize) -> Option<&mut Value>162     pub fn get_mut(&mut self, index: usize) -> Option<&mut Value> {
163         self.values.get_mut(index).and_then(Item::as_value_mut)
164     }
165 
166     /// Appends a new value to the end of the array, applying default formatting to it.
167     ///
168     /// # Examples
169     ///
170     /// ```rust
171     /// let mut arr = toml_edit::Array::new();
172     /// arr.push(1);
173     /// arr.push("foo");
174     /// ```
push<V: Into<Value>>(&mut self, v: V)175     pub fn push<V: Into<Value>>(&mut self, v: V) {
176         self.value_op(v.into(), true, |items, value| {
177             items.push(Item::Value(value))
178         })
179     }
180 
181     /// Appends a new, already formatted value to the end of the array.
182     ///
183     /// # Examples
184     ///
185     /// ```rust
186     /// # #[cfg(feature = "parse")] {
187     /// let formatted_value = "'literal'".parse::<toml_edit::Value>().unwrap();
188     /// let mut arr = toml_edit::Array::new();
189     /// arr.push_formatted(formatted_value);
190     /// # }
191     /// ```
push_formatted(&mut self, v: Value)192     pub fn push_formatted(&mut self, v: Value) {
193         self.values.push(Item::Value(v));
194     }
195 
196     /// Inserts an element at the given position within the array, applying default formatting to
197     /// it and shifting all values after it to the right.
198     ///
199     /// # Panics
200     ///
201     /// Panics if `index > len`.
202     ///
203     /// # Examples
204     ///
205     /// ```rust
206     /// let mut arr = toml_edit::Array::new();
207     /// arr.push(1);
208     /// arr.push("foo");
209     ///
210     /// arr.insert(0, "start");
211     /// ```
insert<V: Into<Value>>(&mut self, index: usize, v: V)212     pub fn insert<V: Into<Value>>(&mut self, index: usize, v: V) {
213         self.value_op(v.into(), true, |items, value| {
214             items.insert(index, Item::Value(value))
215         })
216     }
217 
218     /// Inserts an already formatted value at the given position within the array, shifting all
219     /// values after it to the right.
220     ///
221     /// # Panics
222     ///
223     /// Panics if `index > len`.
224     ///
225     /// # Examples
226     ///
227     /// ```rust
228     /// # #[cfg(feature = "parse")] {
229     /// let mut arr = toml_edit::Array::new();
230     /// arr.push(1);
231     /// arr.push("foo");
232     ///
233     /// let formatted_value = "'start'".parse::<toml_edit::Value>().unwrap();
234     /// arr.insert_formatted(0, formatted_value);
235     /// # }
236     /// ```
insert_formatted(&mut self, index: usize, v: Value)237     pub fn insert_formatted(&mut self, index: usize, v: Value) {
238         self.values.insert(index, Item::Value(v))
239     }
240 
241     /// Replaces the element at the given position within the array, preserving existing formatting.
242     ///
243     /// # Panics
244     ///
245     /// Panics if `index >= len`.
246     ///
247     /// # Examples
248     ///
249     /// ```rust
250     /// let mut arr = toml_edit::Array::new();
251     /// arr.push(1);
252     /// arr.push("foo");
253     ///
254     /// arr.replace(0, "start");
255     /// ```
replace<V: Into<Value>>(&mut self, index: usize, v: V) -> Value256     pub fn replace<V: Into<Value>>(&mut self, index: usize, v: V) -> Value {
257         // Read the existing value's decor and preserve it.
258         let existing_decor = self
259             .get(index)
260             .unwrap_or_else(|| panic!("index {} out of bounds (len = {})", index, self.len()))
261             .decor();
262         let mut value = v.into();
263         *value.decor_mut() = existing_decor.clone();
264         self.replace_formatted(index, value)
265     }
266 
267     /// Replaces the element at the given position within the array with an already formatted value.
268     ///
269     /// # Panics
270     ///
271     /// Panics if `index >= len`.
272     ///
273     /// # Examples
274     ///
275     /// ```rust
276     /// # #[cfg(feature = "parse")] {
277     /// let mut arr = toml_edit::Array::new();
278     /// arr.push(1);
279     /// arr.push("foo");
280     ///
281     /// let formatted_value = "'start'".parse::<toml_edit::Value>().unwrap();
282     /// arr.replace_formatted(0, formatted_value);
283     /// # }
284     /// ```
replace_formatted(&mut self, index: usize, v: Value) -> Value285     pub fn replace_formatted(&mut self, index: usize, v: Value) -> Value {
286         match mem::replace(&mut self.values[index], Item::Value(v)) {
287             Item::Value(old_value) => old_value,
288             x => panic!("non-value item {:?} in an array", x),
289         }
290     }
291 
292     /// Removes the value at the given index.
293     ///
294     /// # Examples
295     ///
296     /// ```rust
297     /// let mut arr = toml_edit::Array::new();
298     /// arr.push(1);
299     /// arr.push("foo");
300     ///
301     /// arr.remove(0);
302     /// assert_eq!(arr.len(), 1);
303     /// ```
remove(&mut self, index: usize) -> Value304     pub fn remove(&mut self, index: usize) -> Value {
305         let removed = self.values.remove(index);
306         match removed {
307             Item::Value(v) => v,
308             x => panic!("non-value item {:?} in an array", x),
309         }
310     }
311 
312     /// Retains only the values specified by the `keep` predicate.
313     ///
314     /// In other words, remove all values for which `keep(&value)` returns `false`.
315     ///
316     /// This method operates in place, visiting each element exactly once in the
317     /// original order, and preserves the order of the retained elements.
retain<F>(&mut self, mut keep: F) where F: FnMut(&Value) -> bool,318     pub fn retain<F>(&mut self, mut keep: F)
319     where
320         F: FnMut(&Value) -> bool,
321     {
322         self.values
323             .retain(|item| item.as_value().map(&mut keep).unwrap_or(false));
324     }
325 
326     /// Sorts the slice with a comparator function.
327     ///
328     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*n* \* log(*n*)) worst-case.
329     ///
330     /// The comparator function must define a total ordering for the elements in the slice. If
331     /// the ordering is not total, the order of the elements is unspecified. An order is a
332     /// total order if it is (for all `a`, `b` and `c`):
333     ///
334     /// * total and antisymmetric: exactly one of `a < b`, `a == b` or `a > b` is true, and
335     /// * transitive, `a < b` and `b < c` implies `a < c`. The same must hold for both `==` and `>`.
336     ///
337     /// For example, while [`f64`] doesn't implement [`Ord`] because `NaN != NaN`, we can use
338     /// `partial_cmp` as our sort function when we know the slice doesn't contain a `NaN`.
339     #[inline]
sort_by<F>(&mut self, mut compare: F) where F: FnMut(&Value, &Value) -> std::cmp::Ordering,340     pub fn sort_by<F>(&mut self, mut compare: F)
341     where
342         F: FnMut(&Value, &Value) -> std::cmp::Ordering,
343     {
344         self.values.sort_by(move |lhs, rhs| {
345             let lhs = lhs.as_value();
346             let rhs = rhs.as_value();
347             match (lhs, rhs) {
348                 (None, None) => std::cmp::Ordering::Equal,
349                 (Some(_), None) => std::cmp::Ordering::Greater,
350                 (None, Some(_)) => std::cmp::Ordering::Less,
351                 (Some(lhs), Some(rhs)) => compare(lhs, rhs),
352             }
353         })
354     }
355 
356     /// Sorts the array with a key extraction function.
357     ///
358     /// This sort is stable (i.e., does not reorder equal elements) and *O*(*m* \* *n* \* log(*n*))
359     /// worst-case, where the key function is *O*(*m*).
360     #[inline]
sort_by_key<K, F>(&mut self, mut f: F) where F: FnMut(&Value) -> K, K: Ord,361     pub fn sort_by_key<K, F>(&mut self, mut f: F)
362     where
363         F: FnMut(&Value) -> K,
364         K: Ord,
365     {
366         #[allow(clippy::manual_map)] // needed for lifetimes
367         self.values.sort_by_key(move |item| {
368             if let Some(value) = item.as_value() {
369                 Some(f(value))
370             } else {
371                 None
372             }
373         });
374     }
375 
value_op<T>( &mut self, v: Value, decorate: bool, op: impl FnOnce(&mut Vec<Item>, Value) -> T, ) -> T376     fn value_op<T>(
377         &mut self,
378         v: Value,
379         decorate: bool,
380         op: impl FnOnce(&mut Vec<Item>, Value) -> T,
381     ) -> T {
382         let mut value = v;
383         if !self.is_empty() && decorate {
384             value.decorate(" ", "");
385         } else if decorate {
386             value.decorate("", "");
387         }
388         op(&mut self.values, value)
389     }
390 }
391 
392 #[cfg(feature = "display")]
393 impl std::fmt::Display for Array {
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result394     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
395         crate::encode::encode_array(self, f, None, ("", ""))
396     }
397 }
398 
399 impl<V: Into<Value>> Extend<V> for Array {
extend<T: IntoIterator<Item = V>>(&mut self, iter: T)400     fn extend<T: IntoIterator<Item = V>>(&mut self, iter: T) {
401         for value in iter {
402             self.push_formatted(value.into());
403         }
404     }
405 }
406 
407 impl<V: Into<Value>> FromIterator<V> for Array {
from_iter<I>(iter: I) -> Self where I: IntoIterator<Item = V>,408     fn from_iter<I>(iter: I) -> Self
409     where
410         I: IntoIterator<Item = V>,
411     {
412         let v = iter.into_iter().map(|a| Item::Value(a.into()));
413         Array {
414             values: v.collect(),
415             ..Default::default()
416         }
417     }
418 }
419 
420 impl IntoIterator for Array {
421     type Item = Value;
422     type IntoIter = ArrayIntoIter;
423 
into_iter(self) -> Self::IntoIter424     fn into_iter(self) -> Self::IntoIter {
425         Box::new(
426             self.values
427                 .into_iter()
428                 .filter(|v| v.is_value())
429                 .map(|v| v.into_value().unwrap()),
430         )
431     }
432 }
433 
434 impl<'s> IntoIterator for &'s Array {
435     type Item = &'s Value;
436     type IntoIter = ArrayIter<'s>;
437 
into_iter(self) -> Self::IntoIter438     fn into_iter(self) -> Self::IntoIter {
439         self.iter()
440     }
441 }
442 
decorate_array(array: &mut Array)443 fn decorate_array(array: &mut Array) {
444     for (i, value) in array
445         .values
446         .iter_mut()
447         .filter_map(Item::as_value_mut)
448         .enumerate()
449     {
450         // [value1, value2, value3]
451         if i == 0 {
452             value.decorate(DEFAULT_LEADING_VALUE_DECOR.0, DEFAULT_LEADING_VALUE_DECOR.1);
453         } else {
454             value.decorate(DEFAULT_VALUE_DECOR.0, DEFAULT_VALUE_DECOR.1);
455         }
456     }
457     // Since everything is now on the same line, remove trailing commas and whitespace.
458     array.set_trailing_comma(false);
459     array.set_trailing("");
460 }
461