From 1f41a9f2a1d1ad4e88459645f6a3a997db3d6cc0 Mon Sep 17 00:00:00 2001 From: Philipp Niedermayer Date: Mon, 1 Sep 2025 11:16:19 +0200 Subject: [PATCH] Fix slicing last n elements using count (#6838) --- crates/typst-library/src/foundations/array.rs | 5 +---- crates/typst-library/src/foundations/bytes.rs | 6 +----- crates/typst-library/src/foundations/str.rs | 4 ++-- tests/suite/foundations/array.typ | 6 ++++++ tests/suite/foundations/bytes.typ | 15 +++++++++++++++ tests/suite/foundations/str.typ | 2 ++ 6 files changed, 27 insertions(+), 11 deletions(-) diff --git a/crates/typst-library/src/foundations/array.rs b/crates/typst-library/src/foundations/array.rs index 5e72ce88..256eb93f 100644 --- a/crates/typst-library/src/foundations/array.rs +++ b/crates/typst-library/src/foundations/array.rs @@ -286,11 +286,8 @@ impl Array { #[named] count: Option, ) -> StrResult { - let mut end = end; - if end.is_none() { - end = count.map(|c: i64| start + c); - } let start = self.locate(start, true)?; + let end = end.or(count.map(|c| start as i64 + c)); let end = self.locate(end.unwrap_or(self.len() as i64), true)?.max(start); Ok(self.0[start..end].into()) } diff --git a/crates/typst-library/src/foundations/bytes.rs b/crates/typst-library/src/foundations/bytes.rs index f4547439..fb11aed8 100644 --- a/crates/typst-library/src/foundations/bytes.rs +++ b/crates/typst-library/src/foundations/bytes.rs @@ -197,12 +197,8 @@ impl Bytes { #[named] count: Option, ) -> StrResult { - let mut end = end; - if end.is_none() { - end = count.map(|c: i64| start + c); - } - let start = self.locate(start)?; + let end = end.or(count.map(|c| start as i64 + c)); let end = self.locate(end.unwrap_or(self.len() as i64))?.max(start); let slice = &self.as_slice()[start..end]; diff --git a/crates/typst-library/src/foundations/str.rs b/crates/typst-library/src/foundations/str.rs index 2999c1e3..c37d801e 100644 --- a/crates/typst-library/src/foundations/str.rs +++ b/crates/typst-library/src/foundations/str.rs @@ -254,9 +254,9 @@ impl Str { #[named] count: Option, ) -> StrResult { - let end = end.or(count.map(|c| start + c)).unwrap_or(self.len() as i64); let start = self.locate(start)?; - let end = self.locate(end)?.max(start); + let end = end.or(count.map(|c| start as i64 + c)); + let end = self.locate(end.unwrap_or(self.len() as i64))?.max(start); Ok(self.0[start..end].into()) } diff --git a/tests/suite/foundations/array.typ b/tests/suite/foundations/array.typ index 0c820d7f..92d52724 100644 --- a/tests/suite/foundations/array.typ +++ b/tests/suite/foundations/array.typ @@ -223,6 +223,8 @@ #test(range(10).slice(2, 6), (2, 3, 4, 5)) #test(range(10).slice(4, count: 3), (4, 5, 6)) #test(range(10).slice(-5, count: 2), (5, 6)) +#test((1, 2, 3).slice(-3, count: 3), (1, 2, 3)) +#test((1, 2, 3).slice(-1, count: 1), (3,)) #test((1, 2, 3).slice(2, -2), ()) #test((1, 2, 3).slice(-2, 2), (2,)) #test((1, 2, 3).slice(-3, 2), (1, 2)) @@ -232,6 +234,10 @@ // Error: 2-30 array index out of bounds (index: 12, len: 10) #range(10).slice(9, count: 3) +--- array-slice-out-of-bounds-from-back --- +// Error: 2-31 array index out of bounds (index: 12, len: 10) +#range(10).slice(-2, count: 4) + --- array-slice-out-of-bounds-negative --- // Error: 2-24 array index out of bounds (index: -4, len: 3) #(1, 2, 3).slice(0, -4) diff --git a/tests/suite/foundations/bytes.typ b/tests/suite/foundations/bytes.typ index c7089278..8f2c4bc2 100644 --- a/tests/suite/foundations/bytes.typ +++ b/tests/suite/foundations/bytes.typ @@ -29,3 +29,18 @@ --- bytes-bad-conversion-from-dict --- // Error: 8-14 expected string, array, or bytes, found dictionary #bytes((a: 1)) + +--- bytes-slice --- +// Test the `slice` method. +#test(bytes("abcd").slice(2), bytes("cd")) +#test(bytes("abcd").slice(0, 3), bytes("abc")) +#test(bytes("abcd").slice(1, -1), bytes("bc")) +#test(bytes("abcd").slice(3, 3), bytes("")) +#test(bytes("abcd").slice(3, 0), bytes("")) +#test(bytes("abcd").slice(-2), bytes("cd")) +#test(bytes("abcd").slice(-3, 2), bytes("b")) +#test(bytes("abcd").slice(-3, -1), bytes("bc")) +#test(bytes("abcd").slice(-2, -2), bytes("")) +#test(bytes("abcd").slice(1, count: 3), bytes("bcd")) +#test(bytes("abcd").slice(-3, count: 3), bytes("bcd")) +#test(bytes("abcd").slice(2, count: 0), bytes("")) diff --git a/tests/suite/foundations/str.typ b/tests/suite/foundations/str.typ index aeaa0a0a..c4fc6736 100644 --- a/tests/suite/foundations/str.typ +++ b/tests/suite/foundations/str.typ @@ -145,6 +145,8 @@ #test("abc🏡def".slice(2, 7), "c🏡") #test("abc🏡def".slice(2, -2), "c🏡d") #test("abc🏡def".slice(-3, -1), "de") +#test("x🏡yz".slice(-2, count: 2), "yz") +#test("x🏡yz".slice(-7, count: 7), "x🏡yz") --- string-slice-not-a-char-boundary --- // Error: 2-21 string index -1 is not a character boundary