Skip to main content

jsonld_syntax/
compare.rs

1use jstrict::Value;
2
3/// Comparison ignoring the order of array items and object entries.
4pub trait Compare {
5    /// Checks whether the two values are equal, up to the order of array
6    /// items and object entries.
7    ///
8    /// Two arrays are equal when they have the same length and each item of
9    /// one can be paired with a distinct, `compare`-equal item of the other.
10    /// An object containing a duplicate key never compares equal, since such
11    /// a document is not valid JSON-LD.
12    fn compare(&self, other: &Self) -> bool;
13}
14
15impl Compare for Value {
16    fn compare(&self, other: &Self) -> bool {
17        match (self, other) {
18            (Self::Null, Self::Null) => true,
19            (Self::Boolean(a), Self::Boolean(b)) => a == b,
20            (Self::Number(a), Self::Number(b)) => a == b,
21            (Self::String(a), Self::String(b)) => a == b,
22            (Self::Array(a), Self::Array(b)) if a.len() == b.len() => {
23                let mut selected = Vec::new();
24                selected.resize(b.len(), false);
25
26                'next_item: for item in a {
27                    for (other, selected) in b.iter().zip(selected.iter_mut()) {
28                        if !*selected && item.compare(other) {
29                            *selected = true;
30                            continue 'next_item;
31                        }
32                    }
33
34                    return false;
35                }
36
37                true
38            }
39            (Self::Object(a), Self::Object(b)) if a.len() == b.len() => {
40                for entry in a {
41                    // Duplicate keys mean the document isn't valid JSON-LD;
42                    // treat as "not equal".
43                    match b.get_unique(&*entry.key) {
44                        Ok(Some(value)) => {
45                            if !entry.value.compare(value) {
46                                return false;
47                            }
48                        }
49                        Ok(None) | Err(_) => return false,
50                    }
51                }
52
53                true
54            }
55            _ => false,
56        }
57    }
58}