#[cfg(feature = "annex-b")]
use crate::builtins::is_html_dda::IsHTMLDDA;
use crate::{JsBigInt, JsObject, JsSymbol, value::Type};
use boa_engine::JsVariant;
use boa_gc::{Finalize, Trace, custom_trace};
use boa_string::JsString;
#[derive(Clone, Debug)]
pub(crate) enum EnumBasedValue {
Undefined,
Null,
Boolean(bool),
Integer32(i32),
Float64(f64),
BigInt(JsBigInt),
Object(JsObject),
Symbol(JsSymbol),
String(JsString),
}
impl Finalize for EnumBasedValue {
fn finalize(&self) {
if let Some(o) = self.as_object() {
o.finalize();
}
}
}
#[allow(unsafe_op_in_unsafe_fn)]
unsafe impl Trace for EnumBasedValue {
custom_trace! {this, mark, {
if let Some(o) = this.as_object() {
mark(&o);
}
}}
}
impl EnumBasedValue {
#[must_use]
#[inline]
pub(crate) const fn null() -> Self {
Self::Null
}
#[must_use]
#[inline]
pub(crate) const fn undefined() -> Self {
Self::Undefined
}
#[must_use]
#[inline]
pub(crate) const fn float64(value: f64) -> Self {
Self::Float64(value)
}
#[must_use]
#[inline]
pub(crate) const fn integer32(value: i32) -> Self {
Self::Integer32(value)
}
#[must_use]
#[inline]
pub(crate) const fn boolean(value: bool) -> Self {
Self::Boolean(value)
}
#[must_use]
#[inline]
pub(crate) fn bigint(value: JsBigInt) -> Self {
Self::BigInt(value)
}
#[must_use]
#[inline]
pub(crate) fn object(value: JsObject) -> Self {
Self::Object(value)
}
#[must_use]
#[inline]
pub(crate) fn symbol(value: JsSymbol) -> Self {
Self::Symbol(value)
}
#[must_use]
#[inline]
pub(crate) fn string(value: JsString) -> Self {
Self::String(value)
}
#[must_use]
#[inline]
pub(crate) const fn is_undefined(&self) -> bool {
matches!(self, Self::Undefined)
}
#[must_use]
#[inline]
pub(crate) const fn is_null(&self) -> bool {
matches!(self, Self::Null)
}
#[must_use]
#[inline]
pub(crate) const fn is_null_or_undefined(&self) -> bool {
matches!(self, Self::Null | Self::Undefined)
}
#[must_use]
#[inline]
pub(crate) const fn is_bool(&self) -> bool {
matches!(self, Self::Boolean(_))
}
#[must_use]
#[inline]
pub(crate) const fn is_float64(&self) -> bool {
matches!(self, Self::Float64(_))
}
#[must_use]
#[inline]
pub(crate) const fn is_negative_zero(&self) -> bool {
matches!(self, Self::Float64(value) if value.to_bits() == (-0f64).to_bits())
}
#[must_use]
#[inline]
pub(crate) const fn is_integer32(&self) -> bool {
matches!(self, Self::Integer32(_))
}
#[must_use]
#[inline]
pub(crate) const fn is_bigint(&self) -> bool {
matches!(self, Self::BigInt(_))
}
#[must_use]
#[inline]
pub(crate) const fn is_object(&self) -> bool {
matches!(self, Self::Object(_))
}
#[must_use]
#[inline]
pub(crate) const fn is_symbol(&self) -> bool {
matches!(self, Self::Symbol(_))
}
#[must_use]
#[inline]
pub(crate) const fn is_string(&self) -> bool {
matches!(self, Self::String(_))
}
#[must_use]
#[inline]
pub(crate) const fn get_type(&self) -> Type {
match self {
Self::Float64(_) | Self::Integer32(_) => Type::Number,
Self::String(_) => Type::String,
Self::Boolean(_) => Type::Boolean,
Self::Symbol(_) => Type::Symbol,
Self::Null => Type::Null,
Self::Undefined => Type::Undefined,
Self::BigInt(_) => Type::BigInt,
Self::Object(_) => Type::Object,
}
}
#[must_use]
#[inline]
pub(crate) const fn as_float64(&self) -> Option<f64> {
match self {
Self::Float64(value) => Some(*value),
_ => None,
}
}
#[must_use]
#[inline]
pub(crate) const fn as_integer32(&self) -> Option<i32> {
match self {
Self::Integer32(value) => Some(*value),
_ => None,
}
}
#[must_use]
#[inline]
pub(crate) const fn as_bool(&self) -> Option<bool> {
match self {
Self::Boolean(value) => Some(*value),
_ => None,
}
}
#[must_use]
#[inline]
pub(crate) fn as_bigint(&self) -> Option<JsBigInt> {
match self {
Self::BigInt(value) => Some(value.clone()),
_ => None,
}
}
#[must_use]
#[inline]
pub(crate) fn as_object(&self) -> Option<JsObject> {
match self {
Self::Object(value) => Some(value.clone()),
_ => None,
}
}
#[must_use]
#[inline]
pub(crate) fn as_symbol(&self) -> Option<JsSymbol> {
match self {
Self::Symbol(value) => Some(value.clone()),
_ => None,
}
}
#[must_use]
#[inline]
pub(crate) fn as_string(&self) -> Option<JsString> {
match self {
Self::String(value) => Some(value.clone()),
_ => None,
}
}
#[must_use]
#[inline]
pub(crate) fn to_boolean(&self) -> bool {
match self {
Self::Symbol(_) => true,
#[cfg(feature = "annex-b")]
Self::Object(obj) if obj.is::<IsHTMLDDA>() => false,
Self::Object(_) => true,
Self::Null | Self::Undefined => false,
Self::Integer32(n) => *n != 0,
Self::Boolean(v) => *v,
Self::String(s) => !s.is_empty(),
Self::BigInt(n) => !n.is_zero(),
Self::Float64(n) => *n != 0.0 && !n.is_nan(),
}
}
#[must_use]
#[inline]
pub(crate) fn as_variant(&self) -> JsVariant {
match self {
Self::Undefined => JsVariant::Undefined,
Self::Null => JsVariant::Null,
Self::Boolean(v) => JsVariant::Boolean(*v),
Self::Integer32(v) => JsVariant::Integer32(*v),
Self::Float64(v) => JsVariant::Float64(*v),
Self::BigInt(v) => JsVariant::BigInt(v.clone()),
Self::Object(v) => JsVariant::Object(v.clone()),
Self::Symbol(v) => JsVariant::Symbol(v.clone()),
Self::String(v) => JsVariant::String(v.clone()),
}
}
}