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