typst_library/foundations/
array.rs

1use std::cmp::Ordering;
2use std::fmt::{Debug, Formatter};
3use std::num::{NonZeroI64, NonZeroUsize};
4use std::ops::{Add, AddAssign};
5
6use comemo::Tracked;
7use ecow::{eco_format, EcoString, EcoVec};
8use serde::{Deserialize, Serialize};
9use smallvec::SmallVec;
10use typst_syntax::{Span, Spanned};
11
12use crate::diag::{
13    bail, At, DeprecationSink, HintedStrResult, SourceDiagnostic, SourceResult, StrResult,
14};
15use crate::engine::Engine;
16use crate::foundations::{
17    cast, func, ops, repr, scope, ty, Args, Bytes, CastInfo, Context, Dict, FromValue,
18    Func, IntoValue, Reflect, Repr, Str, Value, Version,
19};
20
21/// Create a new [`Array`] from values.
22#[macro_export]
23#[doc(hidden)]
24macro_rules! __array {
25    ($value:expr; $count:expr) => {
26        $crate::foundations::Array::from($crate::foundations::eco_vec![
27            $crate::foundations::IntoValue::into_value($value);
28            $count
29        ])
30    };
31
32    ($($value:expr),* $(,)?) => {
33        $crate::foundations::Array::from($crate::foundations::eco_vec![$(
34            $crate::foundations::IntoValue::into_value($value)
35        ),*])
36    };
37}
38
39#[doc(inline)]
40pub use crate::__array as array;
41
42/// A sequence of values.
43///
44/// You can construct an array by enclosing a comma-separated sequence of values
45/// in parentheses. The values do not have to be of the same type.
46///
47/// You can access and update array items with the `.at()` method. Indices are
48/// zero-based and negative indices wrap around to the end of the array. You can
49/// iterate over an array using a [for loop]($scripting/#loops). Arrays can be
50/// added together with the `+` operator, [joined together]($scripting/#blocks)
51/// and multiplied with integers.
52///
53/// **Note:** An array of length one needs a trailing comma, as in `{(1,)}`.
54/// This is to disambiguate from a simple parenthesized expressions like `{(1 +
55/// 2) * 3}`. An empty array is written as `{()}`.
56///
57/// # Example
58/// ```example
59/// #let values = (1, 7, 4, -3, 2)
60///
61/// #values.at(0) \
62/// #(values.at(0) = 3)
63/// #values.at(-1) \
64/// #values.find(calc.even) \
65/// #values.filter(calc.odd) \
66/// #values.map(calc.abs) \
67/// #values.rev() \
68/// #(1, (2, 3)).flatten() \
69/// #(("A", "B", "C")
70///     .join(", ", last: " and "))
71/// ```
72#[ty(scope, cast)]
73#[derive(Default, Clone, PartialEq, Hash, Serialize, Deserialize)]
74#[serde(transparent)]
75pub struct Array(EcoVec<Value>);
76
77impl Array {
78    /// Create a new, empty array.
79    pub fn new() -> Self {
80        Self::default()
81    }
82
83    /// Creates a new vec, with a known capacity.
84    pub fn with_capacity(capacity: usize) -> Self {
85        Self(EcoVec::with_capacity(capacity))
86    }
87
88    /// Return `true` if the length is 0.
89    pub fn is_empty(&self) -> bool {
90        self.0.is_empty()
91    }
92
93    /// Extract a slice of the whole array.
94    pub fn as_slice(&self) -> &[Value] {
95        self.0.as_slice()
96    }
97
98    /// Iterate over references to the contained values.
99    pub fn iter(&self) -> std::slice::Iter<Value> {
100        self.0.iter()
101    }
102
103    /// Mutably borrow the first value in the array.
104    pub fn first_mut(&mut self) -> StrResult<&mut Value> {
105        self.0.make_mut().first_mut().ok_or_else(array_is_empty)
106    }
107
108    /// Mutably borrow the last value in the array.
109    pub fn last_mut(&mut self) -> StrResult<&mut Value> {
110        self.0.make_mut().last_mut().ok_or_else(array_is_empty)
111    }
112
113    /// Mutably borrow the value at the given index.
114    pub fn at_mut(&mut self, index: i64) -> StrResult<&mut Value> {
115        let len = self.len();
116        self.locate_opt(index, false)
117            .and_then(move |i| self.0.make_mut().get_mut(i))
118            .ok_or_else(|| out_of_bounds(index, len))
119    }
120
121    /// Resolve an index or throw an out of bounds error.
122    fn locate(&self, index: i64, end_ok: bool) -> StrResult<usize> {
123        self.locate_opt(index, end_ok)
124            .ok_or_else(|| out_of_bounds(index, self.len()))
125    }
126
127    /// Resolve an index, if it is within bounds.
128    ///
129    /// `index == len` is considered in bounds if and only if `end_ok` is true.
130    fn locate_opt(&self, index: i64, end_ok: bool) -> Option<usize> {
131        let wrapped =
132            if index >= 0 { Some(index) } else { (self.len() as i64).checked_add(index) };
133
134        wrapped
135            .and_then(|v| usize::try_from(v).ok())
136            .filter(|&v| v < self.0.len() + end_ok as usize)
137    }
138
139    /// Repeat this array `n` times.
140    pub fn repeat(&self, n: usize) -> StrResult<Self> {
141        let count = self
142            .len()
143            .checked_mul(n)
144            .ok_or_else(|| format!("cannot repeat this array {n} times"))?;
145
146        Ok(self.iter().cloned().cycle().take(count).collect())
147    }
148
149    /// The internal implementation of [`Array::contains`].
150    pub fn contains_impl(&self, value: &Value, sink: &mut dyn DeprecationSink) -> bool {
151        self.0.iter().any(|v| ops::equal(v, value, sink))
152    }
153}
154
155#[scope]
156impl Array {
157    /// Converts a value to an array.
158    ///
159    /// Note that this function is only intended for conversion of a collection-like
160    /// value to an array, not for creation of an array from individual items. Use
161    /// the array syntax `(1, 2, 3)` (or `(1,)` for a single-element array) instead.
162    ///
163    /// ```example
164    /// #let hi = "Hello 😃"
165    /// #array(bytes(hi))
166    /// ```
167    #[func(constructor)]
168    pub fn construct(
169        /// The value that should be converted to an array.
170        value: ToArray,
171    ) -> Array {
172        value.0
173    }
174
175    /// The number of values in the array.
176    #[func(title = "Length")]
177    pub fn len(&self) -> usize {
178        self.0.len()
179    }
180
181    /// Returns the first item in the array. May be used on the left-hand side
182    /// of an assignment. Fails with an error if the array is empty.
183    #[func]
184    pub fn first(&self) -> StrResult<Value> {
185        self.0.first().cloned().ok_or_else(array_is_empty)
186    }
187
188    /// Returns the last item in the array. May be used on the left-hand side of
189    /// an assignment. Fails with an error if the array is empty.
190    #[func]
191    pub fn last(&self) -> StrResult<Value> {
192        self.0.last().cloned().ok_or_else(array_is_empty)
193    }
194
195    /// Returns the item at the specified index in the array. May be used on the
196    /// left-hand side of an assignment. Returns the default value if the index
197    /// is out of bounds or fails with an error if no default value was
198    /// specified.
199    #[func]
200    pub fn at(
201        &self,
202        /// The index at which to retrieve the item. If negative, indexes from
203        /// the back.
204        index: i64,
205        /// A default value to return if the index is out of bounds.
206        #[named]
207        default: Option<Value>,
208    ) -> StrResult<Value> {
209        self.locate_opt(index, false)
210            .and_then(|i| self.0.get(i).cloned())
211            .or(default)
212            .ok_or_else(|| out_of_bounds_no_default(index, self.len()))
213    }
214
215    /// Adds a value to the end of the array.
216    #[func]
217    pub fn push(
218        &mut self,
219        /// The value to insert at the end of the array.
220        value: Value,
221    ) {
222        self.0.push(value);
223    }
224
225    /// Removes the last item from the array and returns it. Fails with an error
226    /// if the array is empty.
227    #[func]
228    pub fn pop(&mut self) -> StrResult<Value> {
229        self.0.pop().ok_or_else(array_is_empty)
230    }
231
232    /// Inserts a value into the array at the specified index, shifting all
233    /// subsequent elements to the right. Fails with an error if the index is
234    /// out of bounds.
235    ///
236    /// To replace an element of an array, use [`at`]($array.at).
237    #[func]
238    pub fn insert(
239        &mut self,
240        /// The index at which to insert the item. If negative, indexes from
241        /// the back.
242        index: i64,
243        /// The value to insert into the array.
244        value: Value,
245    ) -> StrResult<()> {
246        let i = self.locate(index, true)?;
247        self.0.insert(i, value);
248        Ok(())
249    }
250
251    /// Removes the value at the specified index from the array and return it.
252    #[func]
253    pub fn remove(
254        &mut self,
255        /// The index at which to remove the item. If negative, indexes from
256        /// the back.
257        index: i64,
258        /// A default value to return if the index is out of bounds.
259        #[named]
260        default: Option<Value>,
261    ) -> StrResult<Value> {
262        self.locate_opt(index, false)
263            .map(|i| self.0.remove(i))
264            .or(default)
265            .ok_or_else(|| out_of_bounds_no_default(index, self.len()))
266    }
267
268    /// Extracts a subslice of the array. Fails with an error if the start or end
269    /// index is out of bounds.
270    #[func]
271    pub fn slice(
272        &self,
273        /// The start index (inclusive). If negative, indexes from the back.
274        start: i64,
275        /// The end index (exclusive). If omitted, the whole slice until the end
276        /// of the array is extracted. If negative, indexes from the back.
277        #[default]
278        end: Option<i64>,
279        /// The number of items to extract. This is equivalent to passing
280        /// `start + count` as the `end` position. Mutually exclusive with `end`.
281        #[named]
282        count: Option<i64>,
283    ) -> StrResult<Array> {
284        let mut end = end;
285        if end.is_none() {
286            end = count.map(|c: i64| start + c);
287        }
288        let start = self.locate(start, true)?;
289        let end = self.locate(end.unwrap_or(self.len() as i64), true)?.max(start);
290        Ok(self.0[start..end].into())
291    }
292
293    /// Whether the array contains the specified value.
294    ///
295    /// This method also has dedicated syntax: You can write `{2 in (1, 2, 3)}`
296    /// instead of `{(1, 2, 3).contains(2)}`.
297    #[func]
298    pub fn contains(
299        &self,
300        engine: &mut Engine,
301        span: Span,
302        /// The value to search for.
303        value: Value,
304    ) -> bool {
305        self.contains_impl(&value, &mut (engine, span))
306    }
307
308    /// Searches for an item for which the given function returns `{true}` and
309    /// returns the first match or `{none}` if there is no match.
310    #[func]
311    pub fn find(
312        &self,
313        engine: &mut Engine,
314        context: Tracked<Context>,
315        /// The function to apply to each item. Must return a boolean.
316        searcher: Func,
317    ) -> SourceResult<Option<Value>> {
318        for item in self.iter() {
319            if searcher
320                .call(engine, context, [item.clone()])?
321                .cast::<bool>()
322                .at(searcher.span())?
323            {
324                return Ok(Some(item.clone()));
325            }
326        }
327        Ok(None)
328    }
329
330    /// Searches for an item for which the given function returns `{true}` and
331    /// returns the index of the first match or `{none}` if there is no match.
332    #[func]
333    pub fn position(
334        &self,
335        engine: &mut Engine,
336        context: Tracked<Context>,
337        /// The function to apply to each item. Must return a boolean.
338        searcher: Func,
339    ) -> SourceResult<Option<i64>> {
340        for (i, item) in self.iter().enumerate() {
341            if searcher
342                .call(engine, context, [item.clone()])?
343                .cast::<bool>()
344                .at(searcher.span())?
345            {
346                return Ok(Some(i as i64));
347            }
348        }
349
350        Ok(None)
351    }
352
353    /// Create an array consisting of a sequence of numbers.
354    ///
355    /// If you pass just one positional parameter, it is interpreted as the
356    /// `end` of the range. If you pass two, they describe the `start` and `end`
357    /// of the range.
358    ///
359    /// This function is available both in the array function's scope and
360    /// globally.
361    ///
362    /// ```example
363    /// #range(5) \
364    /// #range(2, 5) \
365    /// #range(20, step: 4) \
366    /// #range(21, step: 4) \
367    /// #range(5, 2, step: -1)
368    /// ```
369    #[func]
370    pub fn range(
371        args: &mut Args,
372        /// The start of the range (inclusive).
373        #[external]
374        #[default]
375        start: i64,
376        /// The end of the range (exclusive).
377        #[external]
378        end: i64,
379        /// The distance between the generated numbers.
380        #[named]
381        #[default(NonZeroI64::new(1).unwrap())]
382        step: NonZeroI64,
383    ) -> SourceResult<Array> {
384        let first = args.expect::<i64>("end")?;
385        let (start, end) = match args.eat::<i64>()? {
386            Some(second) => (first, second),
387            None => (0, first),
388        };
389
390        let step = step.get();
391
392        let mut x = start;
393        let mut array = Self::new();
394
395        while x.cmp(&end) == 0.cmp(&step) {
396            array.push(x.into_value());
397            x += step;
398        }
399
400        Ok(array)
401    }
402
403    /// Produces a new array with only the items from the original one for which
404    /// the given function returns true.
405    #[func]
406    pub fn filter(
407        &self,
408        engine: &mut Engine,
409        context: Tracked<Context>,
410        /// The function to apply to each item. Must return a boolean.
411        test: Func,
412    ) -> SourceResult<Array> {
413        let mut kept = EcoVec::new();
414        for item in self.iter() {
415            if test
416                .call(engine, context, [item.clone()])?
417                .cast::<bool>()
418                .at(test.span())?
419            {
420                kept.push(item.clone())
421            }
422        }
423        Ok(kept.into())
424    }
425
426    /// Produces a new array in which all items from the original one were
427    /// transformed with the given function.
428    #[func]
429    pub fn map(
430        self,
431        engine: &mut Engine,
432        context: Tracked<Context>,
433        /// The function to apply to each item.
434        mapper: Func,
435    ) -> SourceResult<Array> {
436        self.into_iter()
437            .map(|item| mapper.call(engine, context, [item]))
438            .collect()
439    }
440
441    /// Returns a new array with the values alongside their indices.
442    ///
443    /// The returned array consists of `(index, value)` pairs in the form of
444    /// length-2 arrays. These can be [destructured]($scripting/#bindings) with
445    /// a let binding or for loop.
446    #[func]
447    pub fn enumerate(
448        self,
449        /// The index returned for the first pair of the returned list.
450        #[named]
451        #[default(0)]
452        start: i64,
453    ) -> StrResult<Array> {
454        self.into_iter()
455            .enumerate()
456            .map(|(i, value)| {
457                Ok(array![
458                    start
459                        .checked_add_unsigned(i as u64)
460                        .ok_or("array index is too large")?,
461                    value
462                ]
463                .into_value())
464            })
465            .collect()
466    }
467
468    /// Zips the array with other arrays.
469    ///
470    /// Returns an array of arrays, where the `i`th inner array contains all the
471    /// `i`th elements from each original array.
472    ///
473    /// If the arrays to be zipped have different lengths, they are zipped up to
474    /// the last element of the shortest array and all remaining elements are
475    /// ignored.
476    ///
477    /// This function is variadic, meaning that you can zip multiple arrays
478    /// together at once: `{(1, 2).zip(("A", "B"), (10, 20))}` yields
479    /// `{((1, "A", 10), (2, "B", 20))}`.
480    #[func]
481    pub fn zip(
482        self,
483        args: &mut Args,
484        /// Whether all arrays have to have the same length.
485        /// For example, `{(1, 2).zip((1, 2, 3), exact: true)}` produces an
486        /// error.
487        #[named]
488        #[default(false)]
489        exact: bool,
490        /// The arrays to zip with.
491        #[external]
492        #[variadic]
493        others: Vec<Array>,
494    ) -> SourceResult<Array> {
495        let remaining = args.remaining();
496
497        // Fast path for one array.
498        if remaining == 0 {
499            return Ok(self.into_iter().map(|item| array![item].into_value()).collect());
500        }
501
502        // Fast path for just two arrays.
503        if remaining == 1 {
504            let Spanned { v: other, span: other_span } =
505                args.expect::<Spanned<Array>>("others")?;
506            if exact && self.len() != other.len() {
507                bail!(
508                    other_span,
509                    "second array has different length ({}) from first array ({})",
510                    other.len(),
511                    self.len()
512                );
513            }
514            return Ok(self
515                .into_iter()
516                .zip(other)
517                .map(|(first, second)| array![first, second].into_value())
518                .collect());
519        }
520
521        // If there is more than one array, we use the manual method.
522        let mut out = Self::with_capacity(self.len());
523        let arrays = args.all::<Spanned<Array>>()?;
524        if exact {
525            let errs = arrays
526                .iter()
527                .filter(|sp| sp.v.len() != self.len())
528                .map(|Spanned { v, span }| {
529                    SourceDiagnostic::error(
530                        *span,
531                        eco_format!(
532                            "array has different length ({}) from first array ({})",
533                            v.len(),
534                            self.len()
535                        ),
536                    )
537                })
538                .collect::<EcoVec<_>>();
539            if !errs.is_empty() {
540                return Err(errs);
541            }
542        }
543
544        let mut iterators =
545            arrays.into_iter().map(|i| i.v.into_iter()).collect::<Vec<_>>();
546
547        for this in self {
548            let mut row = Self::with_capacity(1 + iterators.len());
549            row.push(this.clone());
550
551            for iterator in &mut iterators {
552                let Some(item) = iterator.next() else {
553                    return Ok(out);
554                };
555
556                row.push(item);
557            }
558
559            out.push(row.into_value());
560        }
561
562        Ok(out)
563    }
564
565    /// Folds all items into a single value using an accumulator function.
566    #[func]
567    pub fn fold(
568        self,
569        engine: &mut Engine,
570        context: Tracked<Context>,
571        /// The initial value to start with.
572        init: Value,
573        /// The folding function. Must have two parameters: One for the
574        /// accumulated value and one for an item.
575        folder: Func,
576    ) -> SourceResult<Value> {
577        let mut acc = init;
578        for item in self {
579            acc = folder.call(engine, context, [acc, item])?;
580        }
581        Ok(acc)
582    }
583
584    /// Sums all items (works for all types that can be added).
585    #[func]
586    pub fn sum(
587        self,
588        engine: &mut Engine,
589        span: Span,
590        /// What to return if the array is empty. Must be set if the array can
591        /// be empty.
592        #[named]
593        default: Option<Value>,
594    ) -> HintedStrResult<Value> {
595        let mut iter = self.into_iter();
596        let mut acc = iter
597            .next()
598            .or(default)
599            .ok_or("cannot calculate sum of empty array with no default")?;
600        for item in iter {
601            acc = ops::add(acc, item, &mut (&mut *engine, span))?;
602        }
603        Ok(acc)
604    }
605
606    /// Calculates the product all items (works for all types that can be
607    /// multiplied).
608    #[func]
609    pub fn product(
610        self,
611        /// What to return if the array is empty. Must be set if the array can
612        /// be empty.
613        #[named]
614        default: Option<Value>,
615    ) -> HintedStrResult<Value> {
616        let mut iter = self.into_iter();
617        let mut acc = iter
618            .next()
619            .or(default)
620            .ok_or("cannot calculate product of empty array with no default")?;
621        for item in iter {
622            acc = ops::mul(acc, item)?;
623        }
624        Ok(acc)
625    }
626
627    /// Whether the given function returns `{true}` for any item in the array.
628    #[func]
629    pub fn any(
630        self,
631        engine: &mut Engine,
632        context: Tracked<Context>,
633        /// The function to apply to each item. Must return a boolean.
634        test: Func,
635    ) -> SourceResult<bool> {
636        for item in self {
637            if test.call(engine, context, [item])?.cast::<bool>().at(test.span())? {
638                return Ok(true);
639            }
640        }
641
642        Ok(false)
643    }
644
645    /// Whether the given function returns `{true}` for all items in the array.
646    #[func]
647    pub fn all(
648        self,
649        engine: &mut Engine,
650        context: Tracked<Context>,
651        /// The function to apply to each item. Must return a boolean.
652        test: Func,
653    ) -> SourceResult<bool> {
654        for item in self {
655            if !test.call(engine, context, [item])?.cast::<bool>().at(test.span())? {
656                return Ok(false);
657            }
658        }
659
660        Ok(true)
661    }
662
663    /// Combine all nested arrays into a single flat one.
664    #[func]
665    pub fn flatten(self) -> Array {
666        let mut flat = EcoVec::with_capacity(self.0.len());
667        for item in self {
668            if let Value::Array(nested) = item {
669                flat.extend(nested.flatten());
670            } else {
671                flat.push(item);
672            }
673        }
674        flat.into()
675    }
676
677    /// Return a new array with the same items, but in reverse order.
678    #[func(title = "Reverse")]
679    pub fn rev(self) -> Array {
680        self.into_iter().rev().collect()
681    }
682
683    /// Split the array at occurrences of the specified value.
684    #[func]
685    pub fn split(
686        &self,
687        /// The value to split at.
688        at: Value,
689    ) -> Array {
690        self.as_slice()
691            .split(|value| *value == at)
692            .map(|subslice| Value::Array(subslice.iter().cloned().collect()))
693            .collect()
694    }
695
696    /// Combine all items in the array into one.
697    #[func]
698    pub fn join(
699        self,
700        engine: &mut Engine,
701        span: Span,
702        /// A value to insert between each item of the array.
703        #[default]
704        separator: Option<Value>,
705        /// An alternative separator between the last two items.
706        #[named]
707        last: Option<Value>,
708    ) -> StrResult<Value> {
709        let len = self.0.len();
710        let separator = separator.unwrap_or(Value::None);
711
712        let mut last = last;
713        let mut result = Value::None;
714        for (i, value) in self.into_iter().enumerate() {
715            if i > 0 {
716                if i + 1 == len && last.is_some() {
717                    result = ops::join(
718                        result,
719                        last.take().unwrap(),
720                        &mut (&mut *engine, span),
721                    )?;
722                } else {
723                    result =
724                        ops::join(result, separator.clone(), &mut (&mut *engine, span))?;
725                }
726            }
727
728            result = ops::join(result, value, &mut (&mut *engine, span))?;
729        }
730
731        Ok(result)
732    }
733
734    /// Returns an array with a copy of the separator value placed between
735    /// adjacent elements.
736    #[func]
737    pub fn intersperse(
738        self,
739        /// The value that will be placed between each adjacent element.
740        separator: Value,
741    ) -> Array {
742        // TODO: Use once stabilized:
743        // https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.intersperse
744        let size = match self.len() {
745            0 => return Array::new(),
746            n => (2 * n) - 1,
747        };
748        let mut vec = EcoVec::with_capacity(size);
749        let mut iter = self.into_iter();
750
751        if let Some(first) = iter.next() {
752            vec.push(first);
753        }
754
755        for value in iter {
756            vec.push(separator.clone());
757            vec.push(value);
758        }
759
760        Array(vec)
761    }
762
763    /// Splits an array into non-overlapping chunks, starting at the beginning,
764    /// ending with a single remainder chunk.
765    ///
766    /// All chunks but the last have `chunk-size` elements.
767    /// If `exact` is set to `{true}`, the remainder is dropped if it
768    /// contains less than `chunk-size` elements.
769    ///
770    /// ```example
771    /// #let array = (1, 2, 3, 4, 5, 6, 7, 8)
772    /// #array.chunks(3) \
773    /// #array.chunks(3, exact: true)
774    /// ```
775    #[func]
776    pub fn chunks(
777        self,
778        /// How many elements each chunk may at most contain.
779        chunk_size: NonZeroUsize,
780        /// Whether to keep the remainder if its size is less than `chunk-size`.
781        #[named]
782        #[default(false)]
783        exact: bool,
784    ) -> Array {
785        let to_array = |chunk| Array::from(chunk).into_value();
786        if exact {
787            self.0.chunks_exact(chunk_size.get()).map(to_array).collect()
788        } else {
789            self.0.chunks(chunk_size.get()).map(to_array).collect()
790        }
791    }
792
793    /// Returns sliding windows of `window-size` elements over an array.
794    ///
795    /// If the array length is less than `window-size`, this will return an empty array.
796    ///
797    /// ```example
798    /// #let array = (1, 2, 3, 4, 5, 6, 7, 8)
799    /// #array.windows(5)
800    /// ```
801    #[func]
802    pub fn windows(
803        self,
804        /// How many elements each window will contain.
805        window_size: NonZeroUsize,
806    ) -> Array {
807        self.0
808            .windows(window_size.get())
809            .map(|window| Array::from(window).into_value())
810            .collect()
811    }
812
813    /// Return a sorted version of this array, optionally by a given key
814    /// function. The sorting algorithm used is stable.
815    ///
816    /// Returns an error if two values could not be compared or if the key
817    /// function (if given) yields an error.
818    ///
819    /// To sort according to multiple criteria at once, e.g. in case of equality
820    /// between some criteria, the key function can return an array. The results
821    /// are in lexicographic order.
822    ///
823    /// ```example
824    /// #let array = (
825    ///   (a: 2, b: 4),
826    ///   (a: 1, b: 5),
827    ///   (a: 2, b: 3),
828    /// )
829    /// #array.sorted(key: it => (it.a, it.b))
830    /// ```
831    #[func]
832    pub fn sorted(
833        self,
834        engine: &mut Engine,
835        context: Tracked<Context>,
836        span: Span,
837        /// If given, applies this function to the elements in the array to
838        /// determine the keys to sort by.
839        #[named]
840        key: Option<Func>,
841    ) -> SourceResult<Array> {
842        let mut result = Ok(());
843        let mut vec = self.0;
844        let mut key_of = |x: Value| match &key {
845            // NOTE: We are relying on `comemo`'s memoization of function
846            // evaluation to not excessively reevaluate the `key`.
847            Some(f) => f.call(engine, context, [x]),
848            None => Ok(x),
849        };
850        vec.make_mut().sort_by(|a, b| {
851            // Until we get `try` blocks :)
852            match (key_of(a.clone()), key_of(b.clone())) {
853                (Ok(a), Ok(b)) => ops::compare(&a, &b).unwrap_or_else(|err| {
854                    if result.is_ok() {
855                        result = Err(err).at(span);
856                    }
857                    Ordering::Equal
858                }),
859                (Err(e), _) | (_, Err(e)) => {
860                    if result.is_ok() {
861                        result = Err(e);
862                    }
863                    Ordering::Equal
864                }
865            }
866        });
867        result.map(|_| vec.into())
868    }
869
870    /// Deduplicates all items in the array.
871    ///
872    /// Returns a new array with all duplicate items removed. Only the first
873    /// element of each duplicate is kept.
874    ///
875    /// ```example
876    /// #(1, 1, 2, 3, 1).dedup()
877    /// ```
878    #[func(title = "Deduplicate")]
879    pub fn dedup(
880        self,
881        engine: &mut Engine,
882        context: Tracked<Context>,
883        span: Span,
884        /// If given, applies this function to the elements in the array to
885        /// determine the keys to deduplicate by.
886        #[named]
887        key: Option<Func>,
888    ) -> SourceResult<Array> {
889        let mut out = EcoVec::with_capacity(self.0.len());
890        let key_of = |engine: &mut Engine, x: Value| match &key {
891            // NOTE: We are relying on `comemo`'s memoization of function
892            // evaluation to not excessively reevaluate the `key`.
893            Some(f) => f.call(engine, context, [x]),
894            None => Ok(x),
895        };
896
897        // This algorithm is O(N^2) because we cannot rely on `HashSet` since:
898        // 1. We would like to preserve the order of the elements.
899        // 2. We cannot hash arbitrary `Value`.
900        'outer: for value in self {
901            let key = key_of(&mut *engine, value.clone())?;
902            if out.is_empty() {
903                out.push(value);
904                continue;
905            }
906
907            for second in out.iter() {
908                if ops::equal(
909                    &key,
910                    &key_of(&mut *engine, second.clone())?,
911                    &mut (&mut *engine, span),
912                ) {
913                    continue 'outer;
914                }
915            }
916
917            out.push(value);
918        }
919
920        Ok(Self(out))
921    }
922
923    /// Converts an array of pairs into a dictionary.
924    /// The first value of each pair is the key, the second the value.
925    ///
926    /// If the same key occurs multiple times, the last value is selected.
927    ///
928    /// ```example
929    /// #(
930    ///   ("apples", 2),
931    ///   ("peaches", 3),
932    ///   ("apples", 5),
933    /// ).to-dict()
934    /// ```
935    #[func]
936    pub fn to_dict(self) -> StrResult<Dict> {
937        self.into_iter()
938            .map(|value| {
939                let value_ty = value.ty();
940                let pair = value.cast::<Array>().map_err(|_| {
941                    eco_format!("expected (str, any) pairs, found {}", value_ty)
942                })?;
943                if let [key, value] = pair.as_slice() {
944                    let key = key.clone().cast::<Str>().map_err(|_| {
945                        eco_format!("expected key of type str, found {}", value.ty())
946                    })?;
947                    Ok((key, value.clone()))
948                } else {
949                    bail!("expected pairs of length 2, found length {}", pair.len());
950                }
951            })
952            .collect()
953    }
954
955    /// Reduces the elements to a single one, by repeatedly applying a reducing
956    /// operation.
957    ///
958    /// If the array is empty, returns `{none}`, otherwise, returns the result
959    /// of the reduction.
960    ///
961    /// The reducing function is a closure with two arguments: an "accumulator",
962    /// and an element.
963    ///
964    /// For arrays with at least one element, this is the same as [`array.fold`]
965    /// with the first element of the array as the initial accumulator value,
966    /// folding every subsequent element into it.
967    #[func]
968    pub fn reduce(
969        self,
970        engine: &mut Engine,
971        context: Tracked<Context>,
972        /// The reducing function. Must have two parameters: One for the
973        /// accumulated value and one for an item.
974        reducer: Func,
975    ) -> SourceResult<Value> {
976        let mut iter = self.into_iter();
977        let mut acc = iter.next().unwrap_or_default();
978        for item in iter {
979            acc = reducer.call(engine, context, [acc, item])?;
980        }
981        Ok(acc)
982    }
983}
984
985/// A value that can be cast to bytes.
986pub struct ToArray(Array);
987
988cast! {
989    ToArray,
990    v: Array => Self(v),
991    v: Bytes => Self(v.iter().map(|&b| Value::Int(b.into())).collect()),
992    v: Version => Self(v.values().iter().map(|&v| Value::Int(v as i64)).collect())
993}
994
995impl Debug for Array {
996    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
997        f.debug_list().entries(&self.0).finish()
998    }
999}
1000
1001impl Repr for Array {
1002    fn repr(&self) -> EcoString {
1003        let max = 40;
1004        let mut pieces: Vec<_> = self
1005            .iter()
1006            .take(max)
1007            .map(|value| eco_format!("{}", value.repr()))
1008            .collect();
1009        if self.len() > max {
1010            pieces.push(eco_format!(".. ({} items omitted)", self.len() - max));
1011        }
1012        repr::pretty_array_like(&pieces, self.len() == 1).into()
1013    }
1014}
1015
1016impl Add for Array {
1017    type Output = Self;
1018
1019    fn add(mut self, rhs: Array) -> Self::Output {
1020        self += rhs;
1021        self
1022    }
1023}
1024
1025impl AddAssign for Array {
1026    fn add_assign(&mut self, rhs: Self) {
1027        self.0.extend(rhs.0);
1028    }
1029}
1030
1031impl Extend<Value> for Array {
1032    fn extend<T: IntoIterator<Item = Value>>(&mut self, iter: T) {
1033        self.0.extend(iter);
1034    }
1035}
1036
1037impl FromIterator<Value> for Array {
1038    fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
1039        Self(iter.into_iter().collect())
1040    }
1041}
1042
1043impl IntoIterator for Array {
1044    type Item = Value;
1045    type IntoIter = ecow::vec::IntoIter<Value>;
1046
1047    fn into_iter(self) -> Self::IntoIter {
1048        self.0.into_iter()
1049    }
1050}
1051
1052impl<'a> IntoIterator for &'a Array {
1053    type Item = &'a Value;
1054    type IntoIter = std::slice::Iter<'a, Value>;
1055
1056    fn into_iter(self) -> Self::IntoIter {
1057        self.iter()
1058    }
1059}
1060
1061impl From<EcoVec<Value>> for Array {
1062    fn from(v: EcoVec<Value>) -> Self {
1063        Array(v)
1064    }
1065}
1066
1067impl From<&[Value]> for Array {
1068    fn from(v: &[Value]) -> Self {
1069        Array(v.into())
1070    }
1071}
1072
1073impl<T> Reflect for Vec<T> {
1074    fn input() -> CastInfo {
1075        Array::input()
1076    }
1077
1078    fn output() -> CastInfo {
1079        Array::output()
1080    }
1081
1082    fn castable(value: &Value) -> bool {
1083        Array::castable(value)
1084    }
1085}
1086
1087impl<T: Reflect, const N: usize> Reflect for SmallVec<[T; N]> {
1088    fn input() -> CastInfo {
1089        Array::input()
1090    }
1091
1092    fn output() -> CastInfo {
1093        Array::output()
1094    }
1095
1096    fn castable(value: &Value) -> bool {
1097        Array::castable(value)
1098    }
1099}
1100
1101impl<T: IntoValue> IntoValue for Vec<T> {
1102    fn into_value(self) -> Value {
1103        Value::Array(self.into_iter().map(IntoValue::into_value).collect())
1104    }
1105}
1106
1107impl<T: IntoValue, const N: usize> IntoValue for SmallVec<[T; N]> {
1108    fn into_value(self) -> Value {
1109        Value::Array(self.into_iter().map(IntoValue::into_value).collect())
1110    }
1111}
1112
1113impl<T: FromValue> FromValue for Vec<T> {
1114    fn from_value(value: Value) -> HintedStrResult<Self> {
1115        value.cast::<Array>()?.into_iter().map(Value::cast).collect()
1116    }
1117}
1118
1119impl<T: FromValue, const N: usize> FromValue for SmallVec<[T; N]> {
1120    fn from_value(value: Value) -> HintedStrResult<Self> {
1121        value.cast::<Array>()?.into_iter().map(Value::cast).collect()
1122    }
1123}
1124
1125/// One element, or multiple provided as an array.
1126#[derive(Debug, Clone, PartialEq, Hash)]
1127pub struct OneOrMultiple<T>(pub Vec<T>);
1128
1129impl<T: Reflect> Reflect for OneOrMultiple<T> {
1130    fn input() -> CastInfo {
1131        T::input() + Array::input()
1132    }
1133
1134    fn output() -> CastInfo {
1135        T::output() + Array::output()
1136    }
1137
1138    fn castable(value: &Value) -> bool {
1139        Array::castable(value) || T::castable(value)
1140    }
1141}
1142
1143impl<T: IntoValue + Clone> IntoValue for OneOrMultiple<T> {
1144    fn into_value(self) -> Value {
1145        self.0.into_value()
1146    }
1147}
1148
1149impl<T: FromValue> FromValue for OneOrMultiple<T> {
1150    fn from_value(value: Value) -> HintedStrResult<Self> {
1151        if T::castable(&value) {
1152            return Ok(Self(vec![T::from_value(value)?]));
1153        }
1154        if Array::castable(&value) {
1155            return Ok(Self(
1156                Array::from_value(value)?
1157                    .into_iter()
1158                    .map(|value| T::from_value(value))
1159                    .collect::<HintedStrResult<_>>()?,
1160            ));
1161        }
1162        Err(Self::error(&value))
1163    }
1164}
1165
1166impl<T> Default for OneOrMultiple<T> {
1167    fn default() -> Self {
1168        Self(vec![])
1169    }
1170}
1171
1172/// The error message when the array is empty.
1173#[cold]
1174fn array_is_empty() -> EcoString {
1175    "array is empty".into()
1176}
1177
1178/// The out of bounds access error message.
1179#[cold]
1180fn out_of_bounds(index: i64, len: usize) -> EcoString {
1181    eco_format!("array index out of bounds (index: {index}, len: {len})")
1182}
1183
1184/// The out of bounds access error message when no default value was given.
1185#[cold]
1186fn out_of_bounds_no_default(index: i64, len: usize) -> EcoString {
1187    eco_format!(
1188        "array index out of bounds (index: {index}, len: {len}) \
1189         and no default value was specified",
1190    )
1191}