use super::*;
use crate::{builtins::Number, Context};
impl Value {
pub fn strict_equals(&self, other: &Self) -> bool {
if self.get_type() != other.get_type() {
return false;
}
match (self, other) {
(Self::BigInt(x), Self::BigInt(y)) => BigInt::equal(x, y),
(Self::Rational(x), Self::Rational(y)) => Number::equal(*x, *y),
(Self::Rational(x), Self::Integer(y)) => Number::equal(*x, f64::from(*y)),
(Self::Integer(x), Self::Rational(y)) => Number::equal(f64::from(*x), *y),
(Self::Integer(x), Self::Integer(y)) => x == y,
(Self::Null, Self::Null) => true,
(_, _) => same_value_non_numeric(self, other),
}
}
#[allow(clippy::float_cmp)]
pub fn equals(&self, other: &Self, interpreter: &mut Context) -> Result<bool> {
if self.get_type() == other.get_type() {
return Ok(self.strict_equals(other));
}
Ok(match (self, other) {
(Self::Null, Self::Undefined) | (Self::Undefined, Self::Null) => true,
(Self::Integer(_), Self::String(_))
| (Self::Rational(_), Self::String(_))
| (Self::String(_), Self::Integer(_))
| (Self::String(_), Self::Rational(_))
| (Self::Rational(_), Self::Boolean(_))
| (Self::Integer(_), Self::Boolean(_)) => {
let x = self.to_number(interpreter)?;
let y = other.to_number(interpreter)?;
Number::equal(x, y)
}
(Self::BigInt(ref a), Self::String(ref b)) => match string_to_bigint(b) {
Some(ref b) => a.as_inner() == b,
None => false,
},
(Self::String(ref a), Self::BigInt(ref b)) => match string_to_bigint(a) {
Some(ref a) => a == b.as_inner(),
None => false,
},
(Self::Boolean(x), _) => return other.equals(&Value::from(*x as i32), interpreter),
(_, Self::Boolean(y)) => return self.equals(&Value::from(*y as i32), interpreter),
(Self::Object(_), _) => {
let primitive = self.to_primitive(interpreter, PreferredType::Default)?;
return primitive.equals(other, interpreter);
}
(_, Self::Object(_)) => {
let primitive = other.to_primitive(interpreter, PreferredType::Default)?;
return primitive.equals(self, interpreter);
}
(Self::BigInt(ref a), Self::Rational(ref b)) => a.as_inner() == b,
(Self::Rational(ref a), Self::BigInt(ref b)) => a == b.as_inner(),
(Self::BigInt(ref a), Self::Integer(ref b)) => a.as_inner() == b,
(Self::Integer(ref a), Self::BigInt(ref b)) => a == b.as_inner(),
_ => false,
})
}
}
pub fn string_to_bigint(string: &str) -> Option<BigInt> {
if string.is_empty() {
return Some(BigInt::from(0));
}
BigInt::from_str(string)
}
pub fn same_value(x: &Value, y: &Value) -> bool {
if x.get_type() != y.get_type() {
return false;
}
match (x, y) {
(Value::BigInt(x), Value::BigInt(y)) => BigInt::same_value(x, y),
(Value::Rational(x), Value::Rational(y)) => Number::same_value(*x, *y),
(Value::Rational(x), Value::Integer(y)) => Number::same_value(*x, f64::from(*y)),
(Value::Integer(x), Value::Rational(y)) => Number::same_value(f64::from(*x), *y),
(Value::Integer(x), Value::Integer(y)) => x == y,
(_, _) => same_value_non_numeric(x, y),
}
}
pub fn same_value_zero(x: &Value, y: &Value) -> bool {
if x.get_type() != y.get_type() {
return false;
}
match (x, y) {
(Value::BigInt(x), Value::BigInt(y)) => BigInt::same_value_zero(x, y),
(Value::Rational(x), Value::Rational(y)) => Number::same_value_zero(*x, *y),
(Value::Rational(x), Value::Integer(y)) => Number::same_value_zero(*x, f64::from(*y)),
(Value::Integer(x), Value::Rational(y)) => Number::same_value_zero(f64::from(*x), *y),
(Value::Integer(x), Value::Integer(y)) => x == y,
(_, _) => same_value_non_numeric(x, y),
}
}
fn same_value_non_numeric(x: &Value, y: &Value) -> bool {
debug_assert!(x.get_type() == y.get_type());
match (x, y) {
(Value::Null, Value::Null) | (Value::Undefined, Value::Undefined) => true,
(Value::String(ref x), Value::String(ref y)) => x == y,
(Value::Boolean(x), Value::Boolean(y)) => x == y,
(Value::Object(ref x), Value::Object(ref y)) => GcObject::equals(x, y),
_ => false,
}
}