Skip to main content

nanvm_lib/vm/any/
partial_eq.rs

1use crate::vm::{Any, IVm, Unpacked};
2
3/// Same as `===` in ECMAScript.
4impl<A: IVm> PartialEq for Any<A> {
5    fn eq(&self, other: &Self) -> bool {
6        self.with_unpacked(|a| other.with_unpacked(|b| a == b))
7    }
8}
9
10impl<A: IVm> Any<A> {
11    /// `SameValueZero` (<https://tc39.es/ecma262/#sec-samevaluezero>), the
12    /// equality `includes` searches with: `===`, except that `NaN` equals
13    /// `NaN`. `0` and `-0` stay equal, as under `===`.
14    pub(crate) fn same_value_zero(&self, other: &Self) -> bool {
15        self == other || (self.is_nan() && other.is_nan())
16    }
17
18    /// `SameValue` (<https://tc39.es/ecma262/#sec-samevalue>), the equality
19    /// of `Object.is`: `===`, except that `NaN` equals `NaN` and `0` does
20    /// not equal `-0`. Every `NaN` is the one quiet `NaN`
21    /// ([`Number::NAN`](crate::vm::Number)), so equal bits are equal values.
22    pub fn same_value(&self, other: &Self) -> bool {
23        self.with_unpacked(|a| {
24            other.with_unpacked(|b| match (a, b) {
25                (Unpacked::Number(a), Unpacked::Number(b)) => {
26                    f64::from(*a).to_bits() == f64::from(*b).to_bits()
27                }
28                _ => a == b,
29            })
30        })
31    }
32
33    /// Whether `self` is the string `s`, compared without building a VM
34    /// string from `s` — a key against a built-in name.
35    pub(crate) fn is_str(&self, s: &str) -> bool {
36        self.with_unpacked(|v| matches!(v, Unpacked::String(k) if k.is_str(s)))
37    }
38}
39
40#[cfg(test)]
41mod tests {
42    use crate::{
43        naive::Naive,
44        vm::{Any, BigInt, ToAny, ToObject},
45    };
46
47    type A = Naive;
48
49    #[test]
50    fn same_value_zero() {
51        let n = |v: f64| -> Any<A> { v.to_any() };
52        assert!(n(f64::NAN).same_value_zero(&n(f64::NAN)));
53        assert!(n(0.0).same_value_zero(&n(-0.0)));
54        assert!(n(1.0).same_value_zero(&n(1.0)));
55        assert!(!n(1.0).same_value_zero(&n(2.0)));
56        assert!(!n(f64::NAN).same_value_zero(&n(0.0)));
57        assert!(!n(f64::NAN).same_value_zero(&"NaN".into()));
58    }
59
60    #[test]
61    fn same_value() {
62        let n = |v: f64| -> Any<A> { v.to_any() };
63        assert!(n(f64::NAN).same_value(&n(f64::NAN)));
64        assert!(!n(0.0).same_value(&n(-0.0)));
65        assert!(!n(-0.0).same_value(&n(0.0)));
66        assert!(n(-0.0).same_value(&n(-0.0)));
67        assert!(n(1.0).same_value(&n(1.0)));
68        assert!(!n(1.0).same_value(&n(2.0)));
69        assert!(!n(f64::NAN).same_value(&n(0.0)));
70        assert!(!n(f64::NAN).same_value(&"NaN".into()));
71        // Everything else is `===`: a string by value, an object by identity.
72        let s: Any<A> = "a".into();
73        assert!(s.same_value(&"a".into()));
74        assert!(!s.same_value(&"b".into()));
75        let o: Any<A> = [].to_object().to_any();
76        assert!(o.same_value(&o.clone()));
77        assert!(!o.same_value(&[].to_object().to_any()));
78        assert!(!n(1.0).same_value(&BigInt::<A>::from(1u64).to_any()));
79    }
80
81    #[test]
82    fn is_str() {
83        let s: Any<A> = "at".into();
84        assert!(s.is_str("at"));
85        assert!(!s.is_str("a"));
86        assert!(!s.is_str("ats"));
87        let n: Any<A> = 0.0.to_any();
88        assert!(!n.is_str("0"));
89    }
90}