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.0.clone().to_unpacked() == other.0.clone().to_unpacked()
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.clone().is_nan() && other.clone().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        match (Unpacked::from(self.clone()), Unpacked::from(other.clone())) {
24            (Unpacked::Number(a), Unpacked::Number(b)) => {
25                f64::from(a).to_bits() == f64::from(b).to_bits()
26            }
27            _ => self == other,
28        }
29    }
30
31    /// Whether `self` is the string `s`, compared without building a VM
32    /// string from `s` — a key against a built-in name.
33    pub(crate) fn is_str(&self, s: &str) -> bool {
34        matches!(Unpacked::from(self.clone()), Unpacked::String(k) if k.is_str(s))
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use crate::{
41        naive::Naive,
42        vm::{Any, BigInt, ToAny, ToObject},
43    };
44
45    type A = Naive;
46
47    #[test]
48    fn same_value_zero() {
49        let n = |v: f64| -> Any<A> { v.to_any() };
50        assert!(n(f64::NAN).same_value_zero(&n(f64::NAN)));
51        assert!(n(0.0).same_value_zero(&n(-0.0)));
52        assert!(n(1.0).same_value_zero(&n(1.0)));
53        assert!(!n(1.0).same_value_zero(&n(2.0)));
54        assert!(!n(f64::NAN).same_value_zero(&n(0.0)));
55        assert!(!n(f64::NAN).same_value_zero(&"NaN".into()));
56    }
57
58    #[test]
59    fn same_value() {
60        let n = |v: f64| -> Any<A> { v.to_any() };
61        assert!(n(f64::NAN).same_value(&n(f64::NAN)));
62        assert!(!n(0.0).same_value(&n(-0.0)));
63        assert!(!n(-0.0).same_value(&n(0.0)));
64        assert!(n(-0.0).same_value(&n(-0.0)));
65        assert!(n(1.0).same_value(&n(1.0)));
66        assert!(!n(1.0).same_value(&n(2.0)));
67        assert!(!n(f64::NAN).same_value(&n(0.0)));
68        assert!(!n(f64::NAN).same_value(&"NaN".into()));
69        // Everything else is `===`: a string by value, an object by identity.
70        let s: Any<A> = "a".into();
71        assert!(s.same_value(&"a".into()));
72        assert!(!s.same_value(&"b".into()));
73        let o: Any<A> = [].to_object().to_any();
74        assert!(o.same_value(&o.clone()));
75        assert!(!o.same_value(&[].to_object().to_any()));
76        assert!(!n(1.0).same_value(&BigInt::<A>::from(1u64).to_any()));
77    }
78
79    #[test]
80    fn is_str() {
81        let s: Any<A> = "at".into();
82        assert!(s.is_str("at"));
83        assert!(!s.is_str("a"));
84        assert!(!s.is_str("ats"));
85        let n: Any<A> = 0.0.to_any();
86        assert!(!n.is_str("0"));
87    }
88}