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