Repository: typst/typst
File: crates/typst/src/foundations/array.rs (Rust)

Code before:
        #[external]
        #[named]
        #[default(false)]
        exact: bool,
        /// The arrays to zip with.
        #[external]
        #[variadic]
        others: Vec<Array>,
    ) -> SourceResult<Array> {
        let exact: bool = args.named("exact")?.unwrap_or_default();

        let remaining = args.remaining();

        // Fast path for one array.
        if remaining == 0 {
            return Ok(self.into_iter().map(|item| array![item].into_value()).collect());
        }

        // Fast path for just two arrays.
        if remaining == 1 {
            let Spanned { v: other, span: other_span } =
                args.expect::<Spanned<Array>>("others")?;
            if exact && self.len() != other.len() {
                bail!(
                    other_span,
                    "Second argument has different length ({}) from first argument ({})",
                    other.len(),
                    self.len()
                );
            }
            return Ok(self
                .into_iter()
                .zip(other)
                .map(|(first, second)| array![first, second].into_value())
                .collect());
        }

        // If there is more than one array, we use the manual method.
        let mut out = Self::with_capacity(self.len());
        let arrays = args.all::<Spanned<Array>>()?;
        if let Some(Spanned { v, span }) =
            arrays.iter().find(|sp| sp.v.len() != self.len())
        {
            bail!(
                *span,
                "Argument has different length ({}) from first argument ({})",
                v.len(),
                self.len()
            );
        }


Review comment (suggestion):
The error message should be all lowercase. I also think "array" would be clearer than "argument".

Code after:
        /// For example, `(1, 2).zip((1, 2, 3), exact: true)` produces an error.
        #[named]
        #[default(false)]
        exact: bool,
        /// The arrays to zip with.
        #[external]
        #[variadic]
        others: Vec<Array>,
    ) -> SourceResult<Array> {
        let remaining = args.remaining();

        // Fast path for one array.
        if remaining == 0 {
            return Ok(self.into_iter().map(|item| array![item].into_value()).collect());
        }

        // Fast path for just two arrays.
        if remaining == 1 {
            let Spanned { v: other, span: other_span } =
                args.expect::<Spanned<Array>>("others")?;
            if exact && self.len() != other.len() {
                bail!(
                    other_span,
                    "second array has different length ({}) from first array ({})",
                    other.len(),
                    self.len()
                );
            }
            return Ok(self
                .into_iter()
                .zip(other)
                .map(|(first, second)| array![first, second].into_value())
                .collect());
        }

        // If there is more than one array, we use the manual method.
        let mut out = Self::with_capacity(self.len());
        let arrays = args.all::<Spanned<Array>>()?;
        if exact {
            let errs = arrays
                .iter()
                .filter(|sp| sp.v.len() != self.len())
                .map(|Spanned { v, span }| {
                    SourceDiagnostic::error(
                        *span,
                        eco_format!(
                            "array has different length ({}) from first array ({})",
                            v.len(),
                            self.len()
                        ),
                    )