Skip to main content

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::{EcoString, EcoVec, eco_format};
8use serde::{Deserialize, Serialize};
9use smallvec::SmallVec;
10use typst_syntax::{Span, Spanned};
11
12use crate::diag::{
13    At, HintedStrResult, HintedString, SourceDiagnostic, SourceResult, StrResult, bail,
14};
15use crate::engine::Engine;
16use crate::foundations::{
17    Args, Bytes, CastInfo, Context, Dict, FromValue, Func, IntoValue, Reflect, Repr, Str,
18    Value, Version, cast, func, ops, repr, scope, ty,
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 @reference:scripting:loops[for loop]. Arrays
50/// can be added together with the `+` operator,
51/// @reference:scripting:blocks[joined together] and multiplied with integers.
52///
53/// *Note:* An array of length one needs a trailing comma, as in `{(1,)}`. This
54/// is to disambiguate from a simple parenthesized expressions like
55/// `{(1 + 2) * 3}`. An empty array is written as `{()}`.
56///
57/// = Example <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
150#[scope]
151impl Array {
152    /// Converts a value to an array.
153    ///
154    /// Note that this function is only intended for conversion of a
155    /// collection-like value to an array, not for creation of an array from
156    /// individual items. Use the array syntax `(1, 2, 3)` (or `(1,)` for a
157    /// single-element array) instead.
158    ///
159    /// ```example
160    /// #let hi = "Hello 😃"
161    /// #array(bytes(hi))
162    /// ```
163    #[func(constructor)]
164    pub fn construct(
165        /// The value that should be converted to an array.
166        value: ToArray,
167    ) -> Array {
168        value.0
169    }
170
171    /// The number of values in the array.
172    #[func(title = "Length")]
173    pub fn len(&self) -> usize {
174        self.0.len()
175    }
176
177    /// Returns the first item in the array. May be used on the left-hand side
178    /// an assignment. Returns the default value if the array is empty or fails
179    /// with an error is no default value was specified.
180    #[func]
181    pub fn first(
182        &self,
183        /// A default value to return if the array is empty.
184        #[named]
185        default: Option<Value>,
186    ) -> StrResult<Value> {
187        self.0.first().cloned().or(default).ok_or_else(array_is_empty)
188    }
189
190    /// Returns the last item in the array. May be used on the left-hand side of
191    /// an assignment. Returns the default value if the array is empty or fails
192    /// with an error is no default value was specified.
193    #[func]
194    pub fn last(
195        &self,
196        /// A default value to return if the array is empty.
197        #[named]
198        default: Option<Value>,
199    ) -> StrResult<Value> {
200        self.0.last().cloned().or(default).ok_or_else(array_is_empty)
201    }
202
203    /// Returns the item at the specified index in the array. May be used on the
204    /// left-hand side of an assignment. Returns the default value if the index
205    /// is out of bounds or fails with an error if no default value was
206    /// specified.
207    #[func]
208    pub fn at(
209        &self,
210        /// The index at which to retrieve the item. If negative, indexes from
211        /// the back.
212        index: i64,
213        /// A default value to return if the index is out of bounds.
214        #[named]
215        default: Option<Value>,
216    ) -> StrResult<Value> {
217        self.locate_opt(index, false)
218            .and_then(|i| self.0.get(i).cloned())
219            .or(default)
220            .ok_or_else(|| out_of_bounds_no_default(index, self.len()))
221    }
222
223    /// Adds a value to the end of the array.
224    #[func]
225    pub fn push(
226        &mut self,
227        /// The value to insert at the end of the array.
228        value: Value,
229    ) {
230        self.0.push(value);
231    }
232
233    /// Removes the last item from the array and returns it. Fails with an error
234    /// if the array is empty.
235    #[func]
236    pub fn pop(&mut self) -> StrResult<Value> {
237        self.0.pop().ok_or_else(array_is_empty)
238    }
239
240    /// Inserts a value into the array at the specified index, shifting all
241    /// subsequent elements to the right. Fails with an error if the index is
242    /// out of bounds.
243    ///
244    /// To replace an element of an array, use @array.at[`at`].
245    #[func]
246    pub fn insert(
247        &mut self,
248        /// The index at which to insert the item. If negative, indexes from the
249        /// back.
250        index: i64,
251        /// The value to insert into the array.
252        value: Value,
253    ) -> StrResult<()> {
254        let i = self.locate(index, true)?;
255        self.0.insert(i, value);
256        Ok(())
257    }
258
259    /// Removes the value at the specified index from the array and return it.
260    #[func]
261    pub fn remove(
262        &mut self,
263        /// The index at which to remove the item. If negative, indexes from the
264        /// back.
265        index: i64,
266        /// A default value to return if the index is out of bounds.
267        #[named]
268        default: Option<Value>,
269    ) -> StrResult<Value> {
270        self.locate_opt(index, false)
271            .map(|i| self.0.remove(i))
272            .or(default)
273            .ok_or_else(|| out_of_bounds_no_default(index, self.len()))
274    }
275
276    /// Extracts a subslice of the array. Fails with an error if the start or
277    /// end index is out of bounds.
278    #[func]
279    pub fn slice(
280        &self,
281        /// The start index (inclusive). If negative, indexes from the back.
282        start: i64,
283        /// The end index (exclusive). If omitted, the whole slice until the end
284        /// of the array is extracted. If negative, indexes from the back.
285        #[default]
286        end: Option<i64>,
287        /// The number of items to extract. This is equivalent to passing
288        /// `start + count` as the `end` position. Mutually exclusive with
289        /// `end`.
290        #[named]
291        count: Option<i64>,
292    ) -> StrResult<Array> {
293        if end.is_some() && count.is_some() {
294            bail!("`end` and `count` are mutually exclusive");
295        }
296        let start = self.locate(start, true)?;
297        let end = end.or(count.map(|c| start as i64 + c));
298        let end = self.locate(end.unwrap_or(self.len() as i64), true)?.max(start);
299        Ok(self.0[start..end].into())
300    }
301
302    /// Whether the array contains the specified value.
303    ///
304    /// This method also has dedicated syntax: You can write `{2 in (1, 2, 3)}`
305    /// instead of `{(1, 2, 3).contains(2)}`.
306    #[func]
307    pub fn contains(
308        &self,
309        /// The value to search for.
310        value: Value,
311    ) -> bool {
312        self.0.contains(&value)
313    }
314
315    /// Searches for an item for which the given function returns `{true}` and
316    /// returns the first match or `{none}` if there is no match.
317    #[func]
318    pub fn find(
319        &self,
320        engine: &mut Engine,
321        context: Tracked<Context>,
322        /// The function to apply to each item. Must return a boolean.
323        searcher: Func,
324    ) -> SourceResult<Option<Value>> {
325        for item in self.iter() {
326            if searcher
327                .call(engine, context, [item.clone()])?
328                .cast::<bool>()
329                .at(searcher.span())?
330            {
331                return Ok(Some(item.clone()));
332            }
333        }
334        Ok(None)
335    }
336
337    /// Searches for an item for which the given function returns `{true}` and
338    /// returns the index of the first match or `{none}` if there is no match.
339    #[func]
340    pub fn position(
341        &self,
342        engine: &mut Engine,
343        context: Tracked<Context>,
344        /// The function to apply to each item. Must return a boolean.
345        ///
346        /// ```example
347        /// #let values = (1, 7, 4, 6, 9)
348        /// #values.position(x => calc.even(x)) \
349        /// // Or equivalently:
350        /// #values.position(calc.even)
351        /// ```
352        searcher: Func,
353    ) -> SourceResult<Option<i64>> {
354        for (i, item) in self.iter().enumerate() {
355            if searcher
356                .call(engine, context, [item.clone()])?
357                .cast::<bool>()
358                .at(searcher.span())?
359            {
360                return Ok(Some(i as i64));
361            }
362        }
363
364        Ok(None)
365    }
366
367    /// Create an array consisting of a sequence of numbers.
368    ///
369    /// If you pass just one positional parameter, it is interpreted as the
370    /// `end` of the range. If you pass two, they describe the `start` and `end`
371    /// of the range.
372    ///
373    /// This function is available both in the array function's scope and
374    /// globally.
375    ///
376    /// ```example
377    /// #range(5) \
378    /// #range(2, 5) \
379    /// #range(20, step: 4) \
380    /// #range(21, step: 4) \
381    /// #range(5, 2, step: -1)
382    /// ```
383    #[func]
384    pub fn range(
385        args: &mut Args,
386        /// The start of the range (inclusive).
387        #[external]
388        #[default]
389        start: i64,
390        /// The end of the range.
391        #[external]
392        end: i64,
393        /// Whether `end` is inclusive.
394        ///
395        /// ```example
396        /// #range(0, inclusive: true) \
397        /// #range(7, 10, inclusive: true) \
398        /// #range(-8, -4, inclusive: true) \
399        /// #range(-6, step: -2, inclusive: true)
400        /// ```
401        #[named]
402        #[default(false)]
403        inclusive: bool,
404        /// The distance between the generated numbers.
405        #[named]
406        #[default(NonZeroI64::new(1).unwrap())]
407        step: NonZeroI64,
408    ) -> SourceResult<Array> {
409        let first = args.expect::<i64>("end")?;
410        let (start, end) = match args.eat::<i64>()? {
411            Some(second) => (first, second),
412            None => (0, first),
413        };
414
415        let step = step.get();
416        let step_dir = 0.cmp(&step);
417
418        let mut x = start;
419        let mut array = Self::new();
420
421        let in_bounds = |x: i64| {
422            if inclusive {
423                // `x` must not exceed `end`.
424                x.cmp(&end) != step_dir.reverse()
425            } else {
426                // `x` must stay strictly before `end`.
427                x.cmp(&end) == step_dir
428            }
429        };
430
431        while in_bounds(x) {
432            array.push(x.into_value());
433
434            if let Some(next) = x.checked_add(step) {
435                x = next;
436            } else {
437                // `end` must have been exceeded this iteration, so we yield.
438                break;
439            }
440        }
441
442        Ok(array)
443    }
444
445    /// Produces a new array with only the items from the original one for which
446    /// the given function returns `{true}`.
447    #[func]
448    pub fn filter(
449        &self,
450        engine: &mut Engine,
451        context: Tracked<Context>,
452        /// The function to apply to each item. Must return a boolean.
453        test: Func,
454    ) -> SourceResult<Array> {
455        let mut kept = EcoVec::new();
456        for item in self.iter() {
457            if test
458                .call(engine, context, [item.clone()])?
459                .cast::<bool>()
460                .at(test.span())?
461            {
462                kept.push(item.clone())
463            }
464        }
465        Ok(kept.into())
466    }
467
468    /// Produces a new array in which all items from the original one were
469    /// transformed with the given function.
470    #[func]
471    pub fn map(
472        self,
473        engine: &mut Engine,
474        context: Tracked<Context>,
475        /// The function to apply to each item.
476        mapper: Func,
477    ) -> SourceResult<Array> {
478        self.into_iter()
479            .map(|item| mapper.call(engine, context, [item]))
480            .collect()
481    }
482
483    /// Returns a new array with the values alongside their indices.
484    ///
485    /// The returned array consists of `(index, value)` pairs in the form of
486    /// length-2 arrays. These can be
487    /// @reference:scripting:bindings[destructured] with a let binding or for
488    /// loop.
489    ///
490    /// ```example
491    /// #for (i, value) in ("A", "B", "C").enumerate() {
492    ///   [#i: #value \ ]
493    /// }
494    ///
495    /// #("A", "B", "C").enumerate(start: 1)
496    /// ```
497    #[func]
498    pub fn enumerate(
499        self,
500        /// The index returned for the first pair of the returned list.
501        #[named]
502        #[default(0)]
503        start: i64,
504    ) -> StrResult<Array> {
505        self.into_iter()
506            .enumerate()
507            .map(|(i, value)| {
508                Ok(array![
509                    start
510                        .checked_add_unsigned(i as u64)
511                        .ok_or("array index is too large")?,
512                    value
513                ]
514                .into_value())
515            })
516            .collect()
517    }
518
519    /// Zips the array with other arrays.
520    ///
521    /// Returns an array of arrays, where the `i`th inner array contains all the
522    /// `i`th elements from each original array.
523    ///
524    /// If the arrays to be zipped have different lengths, they are zipped up to
525    /// the last element of the shortest array and all remaining elements are
526    /// ignored.
527    ///
528    /// This function is variadic, meaning that you can zip multiple arrays
529    /// together at once: `{(1, 2).zip(("A", "B"), (10, 20))}` yields
530    /// `{((1, "A", 10), (2, "B", 20))}`.
531    #[func]
532    pub fn zip(
533        self,
534        args: &mut Args,
535        /// Whether all arrays have to have the same length. For example,
536        /// `{(1, 2).zip((1, 2, 3), exact: true)}` produces an error.
537        #[named]
538        #[default(false)]
539        exact: bool,
540        /// The arrays to zip with.
541        #[external]
542        #[variadic]
543        others: Vec<Array>,
544    ) -> SourceResult<Array> {
545        let remaining = args.remaining();
546
547        // Fast path for one array.
548        if remaining == 0 {
549            return Ok(self.into_iter().map(|item| array![item].into_value()).collect());
550        }
551
552        // Fast path for just two arrays.
553        if remaining == 1 {
554            let Spanned { v: other, span: other_span } =
555                args.expect::<Spanned<Array>>("others")?;
556            if exact && self.len() != other.len() {
557                bail!(
558                    other_span,
559                    "second array has different length ({}) from first array ({})",
560                    other.len(),
561                    self.len(),
562                );
563            }
564            return Ok(self
565                .into_iter()
566                .zip(other)
567                .map(|(first, second)| array![first, second].into_value())
568                .collect());
569        }
570
571        // If there is more than one array, we use the manual method.
572        let mut out = Self::with_capacity(self.len());
573        let arrays = args.all::<Spanned<Array>>()?;
574        if exact {
575            let errs = arrays
576                .iter()
577                .filter(|sp| sp.v.len() != self.len())
578                .map(|Spanned { v, span }| {
579                    SourceDiagnostic::error(
580                        *span,
581                        eco_format!(
582                            "array has different length ({}) from first array ({})",
583                            v.len(),
584                            self.len()
585                        ),
586                    )
587                })
588                .collect::<EcoVec<_>>();
589            if !errs.is_empty() {
590                return Err(errs);
591            }
592        }
593
594        let mut iterators =
595            arrays.into_iter().map(|i| i.v.into_iter()).collect::<Vec<_>>();
596
597        for this in self {
598            let mut row = Self::with_capacity(1 + iterators.len());
599            row.push(this.clone());
600
601            for iterator in &mut iterators {
602                let Some(item) = iterator.next() else {
603                    return Ok(out);
604                };
605
606                row.push(item);
607            }
608
609            out.push(row.into_value());
610        }
611
612        Ok(out)
613    }
614
615    /// Folds all items into a single value using an accumulator function.
616    ///
617    /// ```example
618    /// #let array = (1, 2, 3, 4)
619    /// #array.fold(0, (acc, x) => acc + x)
620    /// ```
621    #[func]
622    pub fn fold(
623        self,
624        engine: &mut Engine,
625        context: Tracked<Context>,
626        /// The initial value to start with.
627        init: Value,
628        /// The folding function. Must have two parameters: One for the
629        /// accumulated value and one for an item.
630        folder: Func,
631    ) -> SourceResult<Value> {
632        let mut acc = init;
633        for item in self {
634            acc = folder.call(engine, context, [acc, item])?;
635        }
636        Ok(acc)
637    }
638
639    /// Sums all items (works for all types that can be added).
640    #[func]
641    pub fn sum(
642        self,
643        /// What to return if the array is empty. Must be set if the array can
644        /// be empty.
645        #[named]
646        default: Option<Value>,
647    ) -> HintedStrResult<Value> {
648        let mut iter = self.into_iter();
649        let mut acc = iter
650            .next()
651            .or(default)
652            .ok_or("cannot calculate sum of empty array with no default")?;
653        for item in iter {
654            acc = ops::add(acc, item)?;
655        }
656        Ok(acc)
657    }
658
659    /// Calculates the product of all items (works for all types that can be
660    /// multiplied).
661    #[func]
662    pub fn product(
663        self,
664        /// What to return if the array is empty. Must be set if the array can
665        /// be empty.
666        #[named]
667        default: Option<Value>,
668    ) -> HintedStrResult<Value> {
669        let mut iter = self.into_iter();
670        let mut acc = iter
671            .next()
672            .or(default)
673            .ok_or("cannot calculate product of empty array with no default")?;
674        for item in iter {
675            acc = ops::mul(acc, item)?;
676        }
677        Ok(acc)
678    }
679
680    /// Whether the given function returns `{true}` for any item in the array.
681    #[func]
682    pub fn any(
683        self,
684        engine: &mut Engine,
685        context: Tracked<Context>,
686        /// The function to apply to each item. Must return a boolean.
687        test: Func,
688    ) -> SourceResult<bool> {
689        for item in self {
690            if test.call(engine, context, [item])?.cast::<bool>().at(test.span())? {
691                return Ok(true);
692            }
693        }
694
695        Ok(false)
696    }
697
698    /// Whether the given function returns `{true}` for all items in the array.
699    #[func]
700    pub fn all(
701        self,
702        engine: &mut Engine,
703        context: Tracked<Context>,
704        /// The function to apply to each item. Must return a boolean.
705        test: Func,
706    ) -> SourceResult<bool> {
707        for item in self {
708            if !test.call(engine, context, [item])?.cast::<bool>().at(test.span())? {
709                return Ok(false);
710            }
711        }
712
713        Ok(true)
714    }
715
716    /// Combine all nested arrays into a single flat one.
717    #[func]
718    pub fn flatten(self) -> Array {
719        let mut flat = EcoVec::with_capacity(self.0.len());
720        for item in self {
721            if let Value::Array(nested) = item {
722                flat.extend(nested.flatten());
723            } else {
724                flat.push(item);
725            }
726        }
727        flat.into()
728    }
729
730    /// Return a new array with the same items, but in reverse order.
731    #[func(title = "Reverse")]
732    pub fn rev(self) -> Array {
733        self.into_iter().rev().collect()
734    }
735
736    /// Split the array at occurrences of the specified value.
737    ///
738    /// ```example
739    /// #(1, 1, 2, 3, 2, 4, 5).split(2)
740    /// ```
741    #[func]
742    pub fn split(
743        &self,
744        /// The value to split at.
745        at: Value,
746    ) -> Array {
747        self.as_slice()
748            .split(|value| *value == at)
749            .map(|subslice| Value::Array(subslice.iter().cloned().collect()))
750            .collect()
751    }
752
753    /// Combine all items in the array into one.
754    #[func]
755    pub fn join(
756        self,
757        /// A value to insert between each item of the array.
758        #[default]
759        separator: Option<Value>,
760        /// An alternative separator between the last two items.
761        #[named]
762        last: Option<Value>,
763        /// What to return if the array is empty.
764        #[named]
765        #[default]
766        default: Option<Value>,
767    ) -> StrResult<Value> {
768        let len = self.0.len();
769
770        if let Some(result) = default
771            && len == 0
772        {
773            return Ok(result);
774        }
775
776        let separator = separator.unwrap_or(Value::None);
777
778        let mut last = last;
779        let mut result = Value::None;
780        for (i, value) in self.into_iter().enumerate() {
781            if i > 0 {
782                if i + 1 == len && last.is_some() {
783                    result = ops::join(result, last.take().unwrap())?;
784                } else {
785                    result = ops::join(result, separator.clone())?;
786                }
787            }
788
789            result = ops::join(result, value)?;
790        }
791
792        Ok(result)
793    }
794
795    /// Returns an array with a copy of the separator value placed between
796    /// adjacent elements.
797    ///
798    /// ```example
799    /// #("A", "B", "C").intersperse("-")
800    /// ```
801    #[func]
802    pub fn intersperse(
803        self,
804        /// The value that will be placed between each adjacent element.
805        separator: Value,
806    ) -> Array {
807        // TODO: Use once stabilized:
808        // https://doc.rust-lang.org/std/iter/trait.Iterator.html#method.intersperse
809        let size = match self.len() {
810            0 => return Array::new(),
811            n => (2 * n) - 1,
812        };
813        let mut vec = EcoVec::with_capacity(size);
814        let mut iter = self.into_iter();
815
816        if let Some(first) = iter.next() {
817            vec.push(first);
818        }
819
820        for value in iter {
821            vec.push(separator.clone());
822            vec.push(value);
823        }
824
825        Array(vec)
826    }
827
828    /// Splits an array into non-overlapping chunks, starting at the beginning,
829    /// ending with a single remainder chunk.
830    ///
831    /// All chunks but the last have `chunk-size` elements. If `exact` is set to
832    /// `{true}`, the remainder is dropped if it contains less than `chunk-size`
833    /// elements.
834    ///
835    /// ```example
836    /// #let array = (1, 2, 3, 4, 5, 6, 7, 8)
837    /// #array.chunks(3) \
838    /// #array.chunks(3, exact: true)
839    /// ```
840    #[func]
841    pub fn chunks(
842        self,
843        /// How many elements each chunk may at most contain.
844        chunk_size: NonZeroUsize,
845        /// Whether to discard the remainder if its size is less than
846        /// `chunk-size`.
847        #[named]
848        #[default(false)]
849        exact: bool,
850    ) -> Array {
851        let to_array = |chunk| Array::from(chunk).into_value();
852        if exact {
853            self.0.chunks_exact(chunk_size.get()).map(to_array).collect()
854        } else {
855            self.0.chunks(chunk_size.get()).map(to_array).collect()
856        }
857    }
858
859    /// Returns sliding windows of `window-size` elements over an array.
860    ///
861    /// If the array length is less than `window-size`, this will return an
862    /// empty array.
863    ///
864    /// ```example
865    /// #let array = (1, 2, 3, 4, 5, 6, 7, 8)
866    /// #array.windows(5)
867    /// ```
868    #[func]
869    pub fn windows(
870        self,
871        /// How many elements each window will contain.
872        window_size: NonZeroUsize,
873    ) -> Array {
874        self.0
875            .windows(window_size.get())
876            .map(|window| Array::from(window).into_value())
877            .collect()
878    }
879
880    /// Return a sorted version of this array, optionally by a given key
881    /// function. The sorting algorithm used is stable.
882    ///
883    /// Returns an error if a pair of values selected for comparison could not
884    /// be compared, or if the key or comparison function (if given) yield an
885    /// error.
886    ///
887    /// To sort according to multiple criteria at once, e.g. in case of equality
888    /// between some criteria, the key function can return an array. The results
889    /// are in lexicographic order.
890    ///
891    /// ```example
892    /// #let array = (
893    ///   (a: 2, b: 4),
894    ///   (a: 1, b: 5),
895    ///   (a: 2, b: 3),
896    /// )
897    /// #array.sorted(key: it => (it.a, it.b))
898    /// ```
899    #[func]
900    pub fn sorted(
901        self,
902        engine: &mut Engine,
903        context: Tracked<Context>,
904        span: Span,
905        /// If given, applies this function to each element in the array to
906        /// determine the keys to sort by.
907        #[named]
908        key: Option<Func>,
909        /// If given, uses this function to compare every two elements in the
910        /// array.
911        ///
912        /// The function will receive two elements in the array for comparison,
913        /// and should return a boolean indicating their order: `{true}`
914        /// indicates that the elements are in order, while `{false}` indicates
915        /// that they should be swapped. To keep the sort stable, if the two
916        /// elements are equal, the function should return `{true}`.
917        ///
918        /// If this function does not order the elements properly (e.g., by
919        /// returning `{false}` for both `{(x, y)}` and `{(y, x)}`, or for
920        /// `{(x, x)}`), the resulting array will be in unspecified order.
921        ///
922        /// When used together with `key`, `by` will be passed the keys instead
923        /// of the elements.
924        ///
925        /// ```example
926        /// #(
927        ///   "sorted",
928        ///   "by",
929        ///   "decreasing",
930        ///   "length",
931        /// ).sorted(
932        ///   key: s => s.len(),
933        ///   by: (l, r) => l >= r,
934        /// )
935        /// ```
936        #[named]
937        by: Option<Func>,
938    ) -> SourceResult<Array> {
939        // We use `glidesort` instead of the standard library sorting algorithm
940        // to prevent panics in case the comparison function does not define a
941        // valid order (see https://github.com/typst/typst/pull/5627 and
942        // https://github.com/typst/typst/issues/6285).
943        match by {
944            Some(by) => {
945                let mut are_in_order = |mut x, mut y| {
946                    if let Some(f) = &key {
947                        // We rely on `comemo`'s memoization of function
948                        // evaluation to not excessively reevaluate the key.
949                        x = f.call(engine, context, [x])?;
950                        y = f.call(engine, context, [y])?;
951                    }
952                    match by.call(engine, context, [x, y])? {
953                        Value::Bool(b) => Ok(b),
954                        x => {
955                            bail!(
956                                span,
957                                "expected boolean from `by` function, got {}",
958                                x.ty(),
959                            )
960                        }
961                    }
962                };
963
964                let mut result = Ok(());
965                let mut vec = self.0.into_iter().enumerate().collect::<Vec<_>>();
966                glidesort::sort_by(&mut vec, |(i, x), (j, y)| {
967                    // Because we use booleans for the comparison function, in
968                    // order to keep the sort stable, we need to compare in the
969                    // right order.
970                    if i == j {
971                        Ordering::Equal
972                    } else if i < j {
973                        // If `x` and `y` appear in this order in the original
974                        // array, then we should change their order (i.e.,
975                        // return `Ordering::Greater`) iff `y` is strictly less
976                        // than `x` (i.e., `compare(x, y)` returns `false`).
977                        // Otherwise, we should keep them in the same order
978                        // (i.e., return `Ordering::Less`).
979                        match are_in_order(x.clone(), y.clone()) {
980                            Ok(false) => Ordering::Greater,
981                            Ok(true) => Ordering::Less,
982                            Err(err) => {
983                                if result.is_ok() {
984                                    result = Err(err);
985                                }
986                                Ordering::Equal
987                            }
988                        }
989                    } else {
990                        // If `x` and `y` appear in the opposite order in the
991                        // original array, then we should change their order
992                        // (i.e., return `Ordering::Less`) iff `x` is strictly
993                        // less than `y` (i.e., `compare(y, x)` returns
994                        // `false`). Otherwise, we should keep them in the same
995                        // order (i.e., return `Ordering::Less`).
996                        match are_in_order(y.clone(), x.clone()) {
997                            Ok(false) => Ordering::Less,
998                            Ok(true) => Ordering::Greater,
999                            Err(err) => {
1000                                if result.is_ok() {
1001                                    result = Err(err);
1002                                }
1003                                Ordering::Equal
1004                            }
1005                        }
1006                    }
1007                });
1008                result.map(|()| vec.into_iter().map(|(_, x)| x).collect())
1009            }
1010
1011            None => {
1012                let mut key_of = |x: Value| match &key {
1013                    // We rely on `comemo`'s memoization of function evaluation
1014                    // to not excessively reevaluate the key.
1015                    Some(f) => f.call(engine, context, [x]),
1016                    None => Ok(x),
1017                };
1018
1019                let mut result = Ok(());
1020                let mut vec = self.0;
1021                glidesort::sort_by(vec.make_mut(), |a, b| {
1022                    match (key_of(a.clone()), key_of(b.clone())) {
1023                        (Ok(a), Ok(b)) => ops::compare(&a, &b).unwrap_or_else(|err| {
1024                            if result.is_ok() {
1025                                result =
1026                                    Err(HintedString::from(err).with_hint(match key {
1027                                        None => {
1028                                            "consider choosing a `key` \
1029                                             or defining the comparison with `by`"
1030                                        }
1031                                        Some(_) => {
1032                                            "consider defining the comparison with `by` \
1033                                             or choosing a different `key`"
1034                                        }
1035                                    }))
1036                                    .at(span);
1037                            }
1038                            Ordering::Equal
1039                        }),
1040                        (Err(e), _) | (_, Err(e)) => {
1041                            if result.is_ok() {
1042                                result = Err(e);
1043                            }
1044                            Ordering::Equal
1045                        }
1046                    }
1047                });
1048                result.map(|()| vec.into())
1049            }
1050        }
1051    }
1052
1053    /// Deduplicates all items in the array.
1054    ///
1055    /// Returns a new array with all duplicate items removed. Only the first
1056    /// element of each duplicate is kept.
1057    ///
1058    /// ```example
1059    /// #(3, 3, 1, 2, 3).dedup()
1060    /// ```
1061    #[func(title = "Deduplicate")]
1062    pub fn dedup(
1063        self,
1064        engine: &mut Engine,
1065        context: Tracked<Context>,
1066        /// If given, applies this function to each element in the array to
1067        /// determine the keys to deduplicate by.
1068        ///
1069        /// ```example
1070        /// #("apple", "banana", " apple ").dedup(key: s => s.trim())
1071        /// ```
1072        #[named]
1073        key: Option<Func>,
1074    ) -> SourceResult<Array> {
1075        let mut out = EcoVec::with_capacity(self.0.len());
1076        let mut key_of = |x: Value| match &key {
1077            // NOTE: We are relying on `comemo`'s memoization of function
1078            // evaluation to not excessively reevaluate the `key`.
1079            Some(f) => f.call(engine, context, [x]),
1080            None => Ok(x),
1081        };
1082
1083        // This algorithm is O(N^2) because we cannot rely on `HashSet` since:
1084        // 1. We would like to preserve the order of the elements.
1085        // 2. We cannot hash arbitrary `Value`.
1086        'outer: for value in self {
1087            let key = key_of(value.clone())?;
1088            if out.is_empty() {
1089                out.push(value);
1090                continue;
1091            }
1092
1093            for second in out.iter() {
1094                if ops::equal(&key, &key_of(second.clone())?) {
1095                    continue 'outer;
1096                }
1097            }
1098
1099            out.push(value);
1100        }
1101
1102        Ok(Self(out))
1103    }
1104
1105    /// Converts an array of pairs into a dictionary. The first value of each
1106    /// pair is the key, the second the value.
1107    ///
1108    /// If the same key occurs multiple times, the last value is selected.
1109    ///
1110    /// ```example
1111    /// #(
1112    ///   ("apples", 2),
1113    ///   ("peaches", 3),
1114    ///   ("apples", 5),
1115    /// ).to-dict()
1116    /// ```
1117    #[func]
1118    pub fn to_dict(self) -> StrResult<Dict> {
1119        self.into_iter()
1120            .map(|value| {
1121                let value_ty = value.ty();
1122                let pair = value.cast::<Array>().map_err(|_| {
1123                    eco_format!("expected (str, any) pairs, found {value_ty}")
1124                })?;
1125                if let [key, value] = pair.as_slice() {
1126                    let key = key.clone().cast::<Str>().map_err(|_| {
1127                        eco_format!("expected key of type str, found {}", value.ty())
1128                    })?;
1129                    Ok((key, value.clone()))
1130                } else {
1131                    bail!("expected pairs of length 2, found length {}", pair.len());
1132                }
1133            })
1134            .collect()
1135    }
1136
1137    /// Reduces the elements to a single one, by repeatedly applying a reducing
1138    /// operation.
1139    ///
1140    /// If the array is empty, returns `{none}`, otherwise, returns the result
1141    /// of the reduction.
1142    ///
1143    /// The reducing function is a closure with two arguments: an "accumulator",
1144    /// and an element.
1145    ///
1146    /// For arrays with at least one element, this is the same as @array.fold
1147    /// with the first element of the array as the initial accumulator value,
1148    /// folding every subsequent element into it.
1149    ///
1150    /// ```example
1151    /// #let array = (2, 1, 4, 3)
1152    /// #array.reduce((acc, x) => calc.max(acc, x))
1153    /// ```
1154    #[func]
1155    pub fn reduce(
1156        self,
1157        engine: &mut Engine,
1158        context: Tracked<Context>,
1159        /// The reducing function. Must have two parameters: One for the
1160        /// accumulated value and one for an item.
1161        reducer: Func,
1162    ) -> SourceResult<Value> {
1163        let mut iter = self.into_iter();
1164        let mut acc = iter.next().unwrap_or_default();
1165        for item in iter {
1166            acc = reducer.call(engine, context, [acc, item])?;
1167        }
1168        Ok(acc)
1169    }
1170}
1171
1172/// A value that can be cast to bytes.
1173pub struct ToArray(Array);
1174
1175cast! {
1176    ToArray,
1177    v: Array => Self(v),
1178    v: Bytes => Self(v.iter().map(|&b| Value::Int(b.into())).collect()),
1179    v: Version => Self(v.values().iter().map(|&v| Value::Int(v as i64)).collect())
1180}
1181
1182impl Debug for Array {
1183    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
1184        f.debug_list().entries(&self.0).finish()
1185    }
1186}
1187
1188impl Repr for Array {
1189    fn repr(&self) -> EcoString {
1190        let max = 40;
1191        let mut pieces: Vec<_> = self
1192            .iter()
1193            .take(max)
1194            .map(|value| eco_format!("{}", value.repr()))
1195            .collect();
1196        if self.len() > max {
1197            pieces.push(eco_format!(".. ({} items omitted)", self.len() - max));
1198        }
1199        repr::pretty_array_like(&pieces, self.len() == 1).into()
1200    }
1201}
1202
1203impl Add for Array {
1204    type Output = Self;
1205
1206    fn add(mut self, rhs: Array) -> Self::Output {
1207        self += rhs;
1208        self
1209    }
1210}
1211
1212impl AddAssign for Array {
1213    fn add_assign(&mut self, rhs: Self) {
1214        self.0.extend(rhs.0);
1215    }
1216}
1217
1218impl Extend<Value> for Array {
1219    fn extend<T: IntoIterator<Item = Value>>(&mut self, iter: T) {
1220        self.0.extend(iter);
1221    }
1222}
1223
1224impl FromIterator<Value> for Array {
1225    fn from_iter<T: IntoIterator<Item = Value>>(iter: T) -> Self {
1226        Self(iter.into_iter().collect())
1227    }
1228}
1229
1230impl IntoIterator for Array {
1231    type Item = Value;
1232    type IntoIter = ecow::vec::IntoIter<Value>;
1233
1234    fn into_iter(self) -> Self::IntoIter {
1235        self.0.into_iter()
1236    }
1237}
1238
1239impl<'a> IntoIterator for &'a Array {
1240    type Item = &'a Value;
1241    type IntoIter = std::slice::Iter<'a, Value>;
1242
1243    fn into_iter(self) -> Self::IntoIter {
1244        self.iter()
1245    }
1246}
1247
1248impl From<EcoVec<Value>> for Array {
1249    fn from(v: EcoVec<Value>) -> Self {
1250        Array(v)
1251    }
1252}
1253
1254impl From<&[Value]> for Array {
1255    fn from(v: &[Value]) -> Self {
1256        Array(v.into())
1257    }
1258}
1259
1260impl<T> Reflect for Vec<T> {
1261    fn input() -> CastInfo {
1262        Array::input()
1263    }
1264
1265    fn output() -> CastInfo {
1266        Array::output()
1267    }
1268
1269    fn castable(value: &Value) -> bool {
1270        Array::castable(value)
1271    }
1272}
1273
1274impl<T: Reflect, const N: usize> Reflect for SmallVec<[T; N]> {
1275    fn input() -> CastInfo {
1276        Array::input()
1277    }
1278
1279    fn output() -> CastInfo {
1280        Array::output()
1281    }
1282
1283    fn castable(value: &Value) -> bool {
1284        Array::castable(value)
1285    }
1286}
1287
1288impl<T: IntoValue + Copy> IntoValue for &[T] {
1289    fn into_value(self) -> Value {
1290        Value::Array(self.iter().copied().map(IntoValue::into_value).collect())
1291    }
1292}
1293
1294impl<T: IntoValue> IntoValue for Vec<T> {
1295    fn into_value(self) -> Value {
1296        Value::Array(self.into_iter().map(IntoValue::into_value).collect())
1297    }
1298}
1299
1300impl<T: IntoValue, const N: usize> IntoValue for SmallVec<[T; N]> {
1301    fn into_value(self) -> Value {
1302        Value::Array(self.into_iter().map(IntoValue::into_value).collect())
1303    }
1304}
1305
1306impl<T: FromValue> FromValue for Vec<T> {
1307    fn from_value(value: Value) -> HintedStrResult<Self> {
1308        value.cast::<Array>()?.into_iter().map(Value::cast).collect()
1309    }
1310}
1311
1312impl<T: FromValue, const N: usize> FromValue for SmallVec<[T; N]> {
1313    fn from_value(value: Value) -> HintedStrResult<Self> {
1314        value.cast::<Array>()?.into_iter().map(Value::cast).collect()
1315    }
1316}
1317
1318/// One element, or multiple provided as an array.
1319#[derive(Debug, Clone, PartialEq, Hash)]
1320pub struct OneOrMultiple<T>(pub Vec<T>);
1321
1322impl<T: Reflect> Reflect for OneOrMultiple<T> {
1323    fn input() -> CastInfo {
1324        T::input() + Array::input()
1325    }
1326
1327    fn output() -> CastInfo {
1328        T::output() + Array::output()
1329    }
1330
1331    fn castable(value: &Value) -> bool {
1332        Array::castable(value) || T::castable(value)
1333    }
1334}
1335
1336impl<T: IntoValue + Clone> IntoValue for OneOrMultiple<T> {
1337    fn into_value(self) -> Value {
1338        self.0.into_value()
1339    }
1340}
1341
1342impl<T: FromValue> FromValue for OneOrMultiple<T> {
1343    fn from_value(value: Value) -> HintedStrResult<Self> {
1344        if T::castable(&value) {
1345            return Ok(Self(vec![T::from_value(value)?]));
1346        }
1347        if Array::castable(&value) {
1348            return Ok(Self(
1349                Array::from_value(value)?
1350                    .into_iter()
1351                    .map(|value| T::from_value(value))
1352                    .collect::<HintedStrResult<_>>()?,
1353            ));
1354        }
1355        Err(Self::error(&value))
1356    }
1357}
1358
1359impl<T> Default for OneOrMultiple<T> {
1360    fn default() -> Self {
1361        Self(vec![])
1362    }
1363}
1364
1365/// The error message when the array is empty.
1366#[cold]
1367fn array_is_empty() -> EcoString {
1368    "array is empty".into()
1369}
1370
1371/// The out of bounds access error message.
1372#[cold]
1373fn out_of_bounds(index: i64, len: usize) -> EcoString {
1374    eco_format!("array index out of bounds (index: {index}, len: {len})")
1375}
1376
1377/// The out of bounds access error message when no default value was given.
1378#[cold]
1379fn out_of_bounds_no_default(index: i64, len: usize) -> EcoString {
1380    eco_format!(
1381        "array index out of bounds (index: {index}, len: {len}) \
1382         and no default value was specified",
1383    )
1384}