summaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
authorPgBiel <9021226+PgBiel@users.noreply.github.com>2023-12-05 15:15:03 -0300
committerGitHub <noreply@github.com>2023-12-05 19:15:03 +0100
commit0ebce56b36ea2a875609949f4da81c9ca6a4a081 (patch)
tree98fb0485843c2a34e22a3994b985add38fd1fdec /crates
parent3960f8f7d935fc5b47404abeb5a64f458d0616c2 (diff)
Implement lexicographic array comparison (#2827)
Diffstat (limited to 'crates')
-rw-r--r--crates/typst/src/eval/ops.rs21
1 files changed, 21 insertions, 0 deletions
diff --git a/crates/typst/src/eval/ops.rs b/crates/typst/src/eval/ops.rs
index cb830614..8e8b6d29 100644
--- a/crates/typst/src/eval/ops.rs
+++ b/crates/typst/src/eval/ops.rs
@@ -551,6 +551,7 @@ pub fn compare(lhs: &Value, rhs: &Value) -> StrResult<Ordering> {
(Duration(a), Duration(b)) => a.cmp(b),
(Datetime(a), Datetime(b)) => try_cmp_datetimes(a, b)?,
+ (Array(a), Array(b)) => try_cmp_arrays(a.as_slice(), b.as_slice())?,
_ => mismatch!("cannot compare {} and {}", lhs, rhs),
})
@@ -568,6 +569,26 @@ fn try_cmp_datetimes(a: &Datetime, b: &Datetime) -> StrResult<Ordering> {
.ok_or_else(|| eco_format!("cannot compare {} and {}", a.kind(), b.kind()))
}
+/// Try to compare arrays of values lexicographically.
+fn try_cmp_arrays(a: &[Value], b: &[Value]) -> StrResult<Ordering> {
+ a.iter()
+ .zip(b.iter())
+ .find_map(|(first, second)| {
+ match compare(first, second) {
+ // Keep searching for a pair of elements that isn't equal.
+ Ok(Ordering::Equal) => None,
+ // Found a pair which either is not equal or not comparable, so
+ // we stop searching.
+ result => Some(result),
+ }
+ })
+ .unwrap_or_else(|| {
+ // The two arrays are equal up to the shortest array's extent,
+ // so compare their lengths instead.
+ Ok(a.len().cmp(&b.len()))
+ })
+}
+
/// Test whether one value is "in" another one.
pub fn in_(lhs: Value, rhs: Value) -> StrResult<Value> {
if let Some(b) = contains(&lhs, &rhs) {