Skip to main content

jsonld_core/utils/
comparison.rs

1use jstrict::Value;
2
3/// Compares two JSON values for JSON-LD equivalence: arrays are compared as
4/// multisets (any order, duplicates counted), except the value of an `@list`
5/// entry whose order is significant; objects must bind the same keys to
6/// equivalent values; everything else must be strictly equal.
7#[must_use]
8pub fn simple_json_ld_eq(a: &Value, b: &Value) -> bool {
9    match (a, b) {
10        (Value::Array(a), Value::Array(b)) if a.len() == b.len() => {
11            let mut selected = Vec::with_capacity(a.len());
12            selected.resize(a.len(), false);
13
14            'a_items: for item in a {
15                for (i, sel) in selected.iter_mut().enumerate() {
16                    // SAFETY: `i < selected.len() == a.len() == b.len()`.
17                    let other = unsafe { b.get(i).unwrap_unchecked() };
18                    if !*sel && simple_json_ld_eq(item, other) {
19                        *sel = true;
20                        continue 'a_items;
21                    }
22                }
23
24                return false;
25            }
26
27            true
28        }
29        (Value::Object(a), Value::Object(b)) if a.len() == b.len() => {
30            for entry in a {
31                let key = &entry.key;
32                let value_a = &entry.value;
33                if let Some(value_b) = b.get(key).next() {
34                    if key == "@list" {
35                        match (value_a, value_b) {
36                            (Value::Array(item_a), Value::Array(item_b)) if item_a.len() == item_b.len() => {
37                                if !item_a.iter().zip(item_b).all(|(a, b)| simple_json_ld_eq(a, b)) {
38                                    return false;
39                                }
40                            }
41                            _ => {
42                                if !simple_json_ld_eq(value_a, value_b) {
43                                    return false;
44                                }
45                            }
46                        }
47                    } else if !simple_json_ld_eq(value_a, value_b) {
48                        return false;
49                    }
50                } else {
51                    return false;
52                }
53            }
54
55            true
56        }
57        (Value::Null, Value::Null) => true,
58        (Value::Boolean(a), Value::Boolean(b)) => a == b,
59        (Value::Number(a), Value::Number(b)) => a == b,
60        (Value::String(a), Value::String(b)) => (**a) == (**b),
61        _ => false,
62    }
63}