js_test/
equal.rs

1use js_sys::Reflect;
2use wasm_bindgen::{JsCast, JsValue};
3
4/// Checks v1 deeply equals to v2.
5///
6/// Doesn't support circular structures.
7pub fn deep_equal(v1: &JsValue, v2: &JsValue) -> bool {
8    if v1 == v2 || js_sys::Object::is(v1, v2) {
9        return true;
10    }
11
12    let t1 = v1.js_typeof();
13    let t2 = v2.js_typeof();
14
15    if t1 != t2 {
16        return false;
17    };
18
19    if t1 == "object" && !v1.is_null() && !v2.is_null() {
20        let p1 = Reflect::get_prototype_of(v1).unwrap();
21        let p2 = Reflect::get_prototype_of(v1).unwrap();
22
23        p1 == p2 && {
24            let a1 = v1.dyn_ref::<js_sys::Array>();
25            let a2 = v2.dyn_ref::<js_sys::Array>();
26
27            match (a1, a2) {
28                (Some(a1), Some(a2)) => {
29                    a1.length() == a2.length()
30                        && a1.every(&mut |v, i, _| deep_equal(&v, &a2.get(i)))
31                }
32                (None, None) => {
33                    let o1 = v1.dyn_ref::<js_sys::Object>();
34                    let o2 = v2.dyn_ref::<js_sys::Object>();
35                    match (o1, o2) {
36                        (Some(o1), Some(o2)) => {
37                            let d1 = o1.dyn_ref::<js_sys::Date>();
38                            let d2 = o2.dyn_ref::<js_sys::Date>();
39
40                            match (d1, d2) {
41                                (Some(d1), Some(d2)) => return d1.get_time() == d2.get_time(),
42                                _ => {}
43                            }
44
45                            let keys1 = js_sys::Reflect::own_keys(&o1).unwrap();
46                            let keys2 =
47                                js_sys::Set::new(js_sys::Reflect::own_keys(&o2).unwrap().as_ref());
48
49                            keys1.for_each(&mut |v, _, _| {
50                                keys2.delete(&v);
51                            });
52
53                            keys2.size() == 0
54                                && keys1.every(&mut |k, _, _| {
55                                    let v1 = js_sys::Reflect::get(&o1, &k).unwrap();
56                                    let v2 = js_sys::Reflect::get(&o2, &k).unwrap();
57                                    deep_equal(&v1, &v2)
58                                })
59                        }
60                        _ => false,
61                    }
62                }
63                _ => false,
64            }
65        }
66    } else {
67        false
68    }
69}