diff --git a/crates/typst/src/foundations/array.rs b/crates/typst/src/foundations/array.rs index 1df24bd8f..a1e93d7b2 100644 --- a/crates/typst/src/foundations/array.rs +++ b/crates/typst/src/foundations/array.rs @@ -1,6 +1,6 @@ use std::cmp::Ordering; use std::fmt::{Debug, Formatter}; -use std::num::NonZeroI64; +use std::num::{NonZeroI64, NonZeroUsize}; use std::ops::{Add, AddAssign}; use ecow::{eco_format, EcoString, EcoVec}; @@ -724,6 +724,36 @@ impl Array { Array(vec) } + /// Splits an array into non-overlapping chunks, starting at the beginning, + /// ending with a single remainder chunk. + /// + /// All chunks but the last have `chunk-size` elements. + /// If `exact` is set to `{true}`, the remainder is dropped if it + /// contains less than `chunk-size` elements. + /// + /// ```example + /// #let array = (1, 2, 3, 4, 5, 6, 7, 8) + /// #array.chunks(3) + /// #array.chunks(3, exact: true) + /// ``` + #[func] + pub fn chunks( + self, + /// How many elements each chunk may at most contain. + chunk_size: NonZeroUsize, + /// Whether to keep the remainder if its size is less than `chunk-size`. + #[named] + #[default(false)] + exact: bool, + ) -> Array { + let to_array = |chunk| Array::from(chunk).into_value(); + if exact { + self.0.chunks_exact(chunk_size.get()).map(to_array).collect() + } else { + self.0.chunks(chunk_size.get()).map(to_array).collect() + } + } + /// Return a sorted version of this array, optionally by a given key /// function. The sorting algorithm used is stable. /// diff --git a/tests/typ/compiler/array.typ b/tests/typ/compiler/array.typ index 9ff294804..4a1948ff7 100644 --- a/tests/typ/compiler/array.typ +++ b/tests/typ/compiler/array.typ @@ -236,6 +236,26 @@ #test((1, 2).intersperse("a"), (1, "a", 2)) #test((1, 2, "b").intersperse("a"), (1, "a", 2, "a", "b")) +--- +// Test the `chunks` method. +#test(().chunks(10), ()) +#test((1, 2, 3).chunks(10), ((1, 2, 3),)) +#test((1, 2, 3, 4, 5, 6).chunks(3), ((1, 2, 3), (4, 5, 6))) +#test((1, 2, 3, 4, 5, 6, 7, 8).chunks(3), ((1, 2, 3), (4, 5, 6), (7, 8))) + +#test(().chunks(10, exact: true), ()) +#test((1, 2, 3).chunks(10, exact: true), ()) +#test((1, 2, 3, 4, 5, 6).chunks(3, exact: true), ((1, 2, 3), (4, 5, 6))) +#test((1, 2, 3, 4, 5, 6, 7, 8).chunks(3, exact: true), ((1, 2, 3), (4, 5, 6))) + +--- +// Error: 19-20 number must be positive +#(1, 2, 3).chunks(0) + +--- +// Error: 19-21 number must be positive +#(1, 2, 3).chunks(-5) + --- // Test the `sorted` method. #test(().sorted(), ())