diff --git a/boa_engine/src/object/builtins/jsarray.rs b/boa_engine/src/object/builtins/jsarray.rs index 972d361d0c..9433b88167 100644 --- a/boa_engine/src/object/builtins/jsarray.rs +++ b/boa_engine/src/object/builtins/jsarray.rs @@ -3,7 +3,7 @@ use crate::{ builtins::Array, error::JsNativeError, object::{JsFunction, JsObject, JsObjectType}, - value::IntoOrUndefined, + value::{IntoOrUndefined, TryFromJs}, Context, JsResult, JsString, JsValue, }; use boa_gc::{Finalize, Trace}; @@ -40,7 +40,7 @@ impl JsArray { /// This does not clone the fields of the array, it only does a shallow clone of the object. #[inline] pub fn from_object(object: JsObject) -> JsResult { - if object.borrow().is_array() { + if object.is_array() { Ok(Self { inner: object }) } else { Err(JsNativeError::typ() @@ -399,3 +399,14 @@ impl Deref for JsArray { } impl JsObjectType for JsArray {} + +impl TryFromJs for JsArray { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message("value is not an Array object") + .into()), + } + } +} diff --git a/boa_engine/src/object/builtins/jsarraybuffer.rs b/boa_engine/src/object/builtins/jsarraybuffer.rs index 2c0d7f913b..9a94dcca74 100644 --- a/boa_engine/src/object/builtins/jsarraybuffer.rs +++ b/boa_engine/src/object/builtins/jsarraybuffer.rs @@ -6,6 +6,7 @@ use crate::{ object::{ internal_methods::get_prototype_from_constructor, JsObject, JsObjectType, ObjectData, }, + value::TryFromJs, Context, JsResult, JsValue, }; use boa_gc::{Finalize, Trace}; @@ -117,7 +118,7 @@ impl JsArrayBuffer { /// This does not clone the fields of the array buffer, it only does a shallow clone of the object. #[inline] pub fn from_object(object: JsObject) -> JsResult { - if object.borrow().is_array_buffer() { + if object.is_array_buffer() { Ok(Self { inner: object }) } else { Err(JsNativeError::typ() @@ -222,3 +223,14 @@ impl Deref for JsArrayBuffer { } impl JsObjectType for JsArrayBuffer {} + +impl TryFromJs for JsArrayBuffer { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message("value is not an ArrayBuffer object") + .into()), + } + } +} diff --git a/boa_engine/src/object/builtins/jsdataview.rs b/boa_engine/src/object/builtins/jsdataview.rs index 444103a7d0..5284db3d1d 100644 --- a/boa_engine/src/object/builtins/jsdataview.rs +++ b/boa_engine/src/object/builtins/jsdataview.rs @@ -6,6 +6,7 @@ use crate::{ internal_methods::get_prototype_from_constructor, JsArrayBuffer, JsObject, JsObjectType, ObjectData, }, + value::TryFromJs, Context, JsNativeError, JsResult, JsValue, }; @@ -111,7 +112,7 @@ impl JsDataView { /// Create a new `JsDataView` object from an existing object. #[inline] pub fn from_object(object: JsObject) -> JsResult { - if object.borrow().is_data_view() { + if object.is_data_view() { Ok(Self { inner: object }) } else { Err(JsNativeError::typ() @@ -485,3 +486,14 @@ impl Deref for JsDataView { } impl JsObjectType for JsDataView {} + +impl TryFromJs for JsDataView { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message("value is not an DataView object") + .into()), + } + } +} diff --git a/boa_engine/src/object/builtins/jsdate.rs b/boa_engine/src/object/builtins/jsdate.rs index 544a47ff14..14a40f4cd8 100644 --- a/boa_engine/src/object/builtins/jsdate.rs +++ b/boa_engine/src/object/builtins/jsdate.rs @@ -7,6 +7,7 @@ use chrono::DateTime; use crate::{ builtins::Date, object::{JsObject, JsObjectType, ObjectData}, + value::TryFromJs, Context, JsNativeError, JsResult, JsValue, }; @@ -47,6 +48,18 @@ impl JsDate { Self { inner } } + /// Create a new `JsDate` object from an existing object. + #[inline] + pub fn from_object(object: JsObject) -> JsResult { + if object.is_date() { + Ok(Self { inner: object }) + } else { + Err(JsNativeError::typ() + .with_message("object is not a Date") + .into()) + } + } + /// Return a `Number` representing the milliseconds elapsed since the UNIX epoch. /// /// Same as JavaScript's `Date.now()` @@ -587,3 +600,14 @@ impl Deref for JsDate { } impl JsObjectType for JsDate {} + +impl TryFromJs for JsDate { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message("value is not a Date object") + .into()), + } + } +} diff --git a/boa_engine/src/object/builtins/jsfunction.rs b/boa_engine/src/object/builtins/jsfunction.rs index db7effee07..0bd9574a05 100644 --- a/boa_engine/src/object/builtins/jsfunction.rs +++ b/boa_engine/src/object/builtins/jsfunction.rs @@ -1,7 +1,8 @@ //! A Rust API wrapper for Boa's `Function` Builtin ECMAScript Object use crate::{ object::{JsObject, JsObjectType}, - JsValue, + value::TryFromJs, + Context, JsNativeError, JsResult, JsValue, }; use boa_gc::{Finalize, Trace}; use std::ops::Deref; @@ -52,3 +53,18 @@ impl Deref for JsFunction { } impl JsObjectType for JsFunction {} + +impl TryFromJs for JsFunction { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()).ok_or_else(|| { + JsNativeError::typ() + .with_message("object is not a function") + .into() + }), + _ => Err(JsNativeError::typ() + .with_message("value is not a Function object") + .into()), + } + } +} diff --git a/boa_engine/src/object/builtins/jsgenerator.rs b/boa_engine/src/object/builtins/jsgenerator.rs index 0fccc5d9a4..cbb13c6d3a 100644 --- a/boa_engine/src/object/builtins/jsgenerator.rs +++ b/boa_engine/src/object/builtins/jsgenerator.rs @@ -2,6 +2,7 @@ use crate::{ builtins::generator::{Generator, GeneratorState}, object::{JsObject, JsObjectType, ObjectData}, + value::TryFromJs, Context, JsNativeError, JsResult, JsValue, }; @@ -34,7 +35,7 @@ impl JsGenerator { /// Create a `JsGenerator` from a regular expression `JsObject` #[inline] pub fn from_object(object: JsObject) -> JsResult { - if object.borrow().is_generator() { + if object.is_generator() { Ok(Self { inner: object }) } else { Err(JsNativeError::typ() @@ -99,3 +100,14 @@ impl Deref for JsGenerator { } impl JsObjectType for JsGenerator {} + +impl TryFromJs for JsGenerator { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message("value is not a Generator object") + .into()), + } + } +} diff --git a/boa_engine/src/object/builtins/jsmap.rs b/boa_engine/src/object/builtins/jsmap.rs index 5eb184ab97..34f213a0f5 100644 --- a/boa_engine/src/object/builtins/jsmap.rs +++ b/boa_engine/src/object/builtins/jsmap.rs @@ -5,6 +5,7 @@ use crate::{ error::JsNativeError, object::{JsFunction, JsMapIterator, JsObject, JsObjectType, ObjectData}, string::utf16, + value::TryFromJs, Context, JsResult, JsValue, }; @@ -169,7 +170,7 @@ impl JsMap { /// ``` #[inline] pub fn from_object(object: JsObject) -> JsResult { - if object.borrow().is_map() { + if object.is_map() { Ok(Self { inner: object }) } else { Err(JsNativeError::typ() @@ -422,3 +423,14 @@ impl Deref for JsMap { } impl JsObjectType for JsMap {} + +impl TryFromJs for JsMap { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message("value is not a Map object") + .into()), + } + } +} diff --git a/boa_engine/src/object/builtins/jsmap_iterator.rs b/boa_engine/src/object/builtins/jsmap_iterator.rs index 8bea527ad1..cc1a72a06c 100644 --- a/boa_engine/src/object/builtins/jsmap_iterator.rs +++ b/boa_engine/src/object/builtins/jsmap_iterator.rs @@ -3,6 +3,7 @@ use crate::{ builtins::map::MapIterator, error::JsNativeError, object::{JsObject, JsObjectType}, + value::TryFromJs, Context, JsResult, JsValue, }; @@ -19,7 +20,7 @@ impl JsMapIterator { /// Create a [`JsMapIterator`] from a [`JsObject`]. If object is not a `MapIterator`, throw `TypeError` #[inline] pub fn from_object(object: JsObject) -> JsResult { - if object.borrow().is_map_iterator() { + if object.is_map_iterator() { Ok(Self { inner: object }) } else { Err(JsNativeError::typ() @@ -58,3 +59,14 @@ impl Deref for JsMapIterator { } impl JsObjectType for JsMapIterator {} + +impl TryFromJs for JsMapIterator { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message("value is not a MapIterator object") + .into()), + } + } +} diff --git a/boa_engine/src/object/builtins/jspromise.rs b/boa_engine/src/object/builtins/jspromise.rs index 8618e5dea6..402ddc0132 100644 --- a/boa_engine/src/object/builtins/jspromise.rs +++ b/boa_engine/src/object/builtins/jspromise.rs @@ -11,6 +11,7 @@ use crate::{ }, context::intrinsics::StandardConstructors, object::{JsObject, JsObjectType, ObjectData}, + value::TryFromJs, Context, JsError, JsNativeError, JsResult, JsValue, }; @@ -243,13 +244,13 @@ impl JsPromise { /// # } /// ``` #[inline] - pub fn from_object(object: JsObject) -> JsResult { + pub fn from_object(object: JsObject) -> JsResult { if !object.is_promise() { return Err(JsNativeError::typ() .with_message("`object` is not a Promise") .into()); } - Ok(JsPromise { inner: object }) + Ok(Self { inner: object }) } /// Resolves a `JsValue` into a `JsPromise`. @@ -883,3 +884,14 @@ impl std::ops::Deref for JsPromise { } impl JsObjectType for JsPromise {} + +impl TryFromJs for JsPromise { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message("value is not a Promise object") + .into()), + } + } +} diff --git a/boa_engine/src/object/builtins/jsproxy.rs b/boa_engine/src/object/builtins/jsproxy.rs index 266c3485da..3e9491e346 100644 --- a/boa_engine/src/object/builtins/jsproxy.rs +++ b/boa_engine/src/object/builtins/jsproxy.rs @@ -6,7 +6,8 @@ use crate::{ native_function::{NativeFunction, NativeFunctionPointer}, object::{FunctionObjectBuilder, JsObject, JsObjectType, ObjectData}, string::utf16, - Context, JsResult, JsValue, + value::TryFromJs, + Context, JsNativeError, JsResult, JsValue, }; use super::JsFunction; @@ -33,6 +34,19 @@ impl JsProxy { pub fn builder(target: JsObject) -> JsProxyBuilder { JsProxyBuilder::new(target) } + + /// Create a [`JsProxy`] from a [`JsObject`], if the object is not a `Proxy` throw a + /// `TypeError`. + #[inline] + pub fn from_object(object: JsObject) -> JsResult { + if object.borrow().is_proxy() { + Ok(Self { inner: object }) + } else { + Err(JsNativeError::typ() + .with_message("object is not a Proxy") + .into()) + } + } } impl From for JsObject { @@ -60,6 +74,17 @@ impl std::ops::Deref for JsProxy { impl JsObjectType for JsProxy {} +impl TryFromJs for JsProxy { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message("value is not a Proxy object") + .into()), + } + } +} + /// `JsRevocableProxy` provides a wrapper for `JsProxy` that can be disabled. /// /// Safe interface for the [`Proxy.revocable`][revocable] method that creates a diff --git a/boa_engine/src/object/builtins/jsregexp.rs b/boa_engine/src/object/builtins/jsregexp.rs index 638e3e3d1d..73b808e26e 100644 --- a/boa_engine/src/object/builtins/jsregexp.rs +++ b/boa_engine/src/object/builtins/jsregexp.rs @@ -2,6 +2,7 @@ use crate::{ builtins::RegExp, object::{JsArray, JsObject, JsObjectType}, + value::TryFromJs, Context, JsNativeError, JsResult, JsValue, }; @@ -79,7 +80,7 @@ impl JsRegExp { /// Create a `JsRegExp` from a regular expression `JsObject` #[inline] pub fn from_object(object: JsObject) -> JsResult { - if object.borrow().is_regexp() { + if object.is_regexp() { Ok(Self { inner: object }) } else { Err(JsNativeError::typ() @@ -279,3 +280,14 @@ impl Deref for JsRegExp { } impl JsObjectType for JsRegExp {} + +impl TryFromJs for JsRegExp { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message("value is not a RegExp object") + .into()), + } + } +} diff --git a/boa_engine/src/object/builtins/jsset.rs b/boa_engine/src/object/builtins/jsset.rs index 21b835f70b..8197c13439 100644 --- a/boa_engine/src/object/builtins/jsset.rs +++ b/boa_engine/src/object/builtins/jsset.rs @@ -7,6 +7,7 @@ use crate::{ builtins::Set, error::JsNativeError, object::{JsFunction, JsObject, JsObjectType, JsSetIterator}, + value::TryFromJs, Context, JsResult, JsValue, }; @@ -143,7 +144,7 @@ impl JsSet { /// Utility: Creates `JsSet` from `JsObject`, if not a Set throw `TypeError`. #[inline] pub fn from_object(object: JsObject) -> JsResult { - if object.borrow().is_set() { + if object.is_set() { Ok(Self { inner: object }) } else { Err(JsNativeError::typ() @@ -185,3 +186,14 @@ impl Deref for JsSet { } impl JsObjectType for JsSet {} + +impl TryFromJs for JsSet { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message("value is not a Set object") + .into()), + } + } +} diff --git a/boa_engine/src/object/builtins/jsset_iterator.rs b/boa_engine/src/object/builtins/jsset_iterator.rs index 39489cbe8b..b0b764eee8 100644 --- a/boa_engine/src/object/builtins/jsset_iterator.rs +++ b/boa_engine/src/object/builtins/jsset_iterator.rs @@ -7,6 +7,7 @@ use crate::{ builtins::set::SetIterator, error::JsNativeError, object::{JsObject, JsObjectType}, + value::TryFromJs, Context, JsResult, JsValue, }; @@ -20,7 +21,7 @@ impl JsSetIterator { /// Create a `JsSetIterator` from a `JsObject`. /// If object is not a `SetIterator`, throw `TypeError`. pub fn from_object(object: JsObject) -> JsResult { - if object.borrow().is_set_iterator() { + if object.is_set_iterator() { Ok(Self { inner: object }) } else { Err(JsNativeError::typ() @@ -58,3 +59,14 @@ impl Deref for JsSetIterator { } impl JsObjectType for JsSetIterator {} + +impl TryFromJs for JsSetIterator { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message("value is not a SetIterator object") + .into()), + } + } +} diff --git a/boa_engine/src/object/builtins/jstypedarray.rs b/boa_engine/src/object/builtins/jstypedarray.rs index 0506de5abf..3777b0d08e 100644 --- a/boa_engine/src/object/builtins/jstypedarray.rs +++ b/boa_engine/src/object/builtins/jstypedarray.rs @@ -4,25 +4,28 @@ use crate::{ builtins::BuiltInConstructor, error::JsNativeError, object::{JsArrayBuffer, JsFunction, JsObject, JsObjectType}, - value::IntoOrUndefined, + value::{IntoOrUndefined, TryFromJs}, Context, JsResult, JsString, JsValue, }; use boa_gc::{Finalize, Trace}; use std::ops::Deref; -/// `JsTypedArray` provides a wrapper for Boa's implementation of the ECMAScript `TypedArray` builtin object. +/// `JsTypedArray` provides a wrapper for Boa's implementation of the ECMAScript `TypedArray` +/// builtin object. #[derive(Debug, Clone, Trace, Finalize)] pub struct JsTypedArray { inner: JsValue, } impl JsTypedArray { - /// Create a [`JsTypedArray`] from a [`JsObject`], if the object is not a typed array throw a `TypeError`. + /// Create a [`JsTypedArray`] from a [`JsObject`], if the object is not a typed array throw a + /// `TypeError`. /// - /// This does not clone the fields of the typed array, it only does a shallow clone of the object. + /// This does not clone the fields of the typed array, it only does a shallow clone of the + /// object. #[inline] pub fn from_object(object: JsObject) -> JsResult { - if object.borrow().is_typed_array() { + if object.is_typed_array() { Ok(Self { inner: object.into(), }) @@ -346,15 +349,55 @@ impl Deref for JsTypedArray { impl JsObjectType for JsTypedArray {} +impl TryFromJs for JsTypedArray { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message("value is not a TypedArray object") + .into()), + } + } +} + macro_rules! JsTypedArrayType { - ($name:ident, $constructor_function:ident, $constructor_object:ident, $element:ty) => { - #[doc = concat!("`", stringify!($name), "` provides a wrapper for Boa's implementation of the ECMAScript `", stringify!($constructor_function) ,"` builtin object.")] + ( + $name:ident, + $constructor_function:ident, + $checker_function:ident, + $constructor_object:ident, + $element:ty + ) => { + + #[doc = concat!( + "`", stringify!($name), + "` provides a wrapper for Boa's implementation of the ECMAScript `", + stringify!($constructor_function) ,"` builtin object." + )] #[derive(Debug, Clone, Trace, Finalize)] pub struct $name { inner: JsTypedArray, } impl $name { + #[doc = concat!("Creates a `", stringify!($name), + "` using a [`JsObject`]. It will make sure that the object is of the correct kind." + )] + #[inline] + pub fn from_object(object: JsObject) -> JsResult { + if object.$checker_function() { + Ok(Self { + inner: JsTypedArray { + inner: object.into(), + }, + }) + } else { + Err(JsNativeError::typ() + .with_message("object is not a TypedArray") + .into()) + } + } + /// Create the typed array from a [`JsArrayBuffer`]. pub fn from_array_buffer( array_buffer: JsArrayBuffer, @@ -441,14 +484,77 @@ macro_rules! JsTypedArrayType { &self.inner } } + + impl TryFromJs for $name { + fn try_from_js(value: &JsValue, _context: &mut Context<'_>) -> JsResult { + match value { + JsValue::Object(o) => Self::from_object(o.clone()), + _ => Err(JsNativeError::typ() + .with_message(concat!( + "value is not a ", + stringify!($constructor_function), + " object" + )) + .into()), + } + } + } }; } -JsTypedArrayType!(JsUint8Array, Uint8Array, typed_uint8_array, u8); -JsTypedArrayType!(JsInt8Array, Int8Array, typed_int8_array, i8); -JsTypedArrayType!(JsUint16Array, Uint16Array, typed_uint16_array, u16); -JsTypedArrayType!(JsInt16Array, Int16Array, typed_int16_array, i16); -JsTypedArrayType!(JsUint32Array, Uint32Array, typed_uint32_array, u32); -JsTypedArrayType!(JsInt32Array, Int32Array, typed_int32_array, i32); -JsTypedArrayType!(JsFloat32Array, Float32Array, typed_float32_array, f32); -JsTypedArrayType!(JsFloat64Array, Float64Array, typed_float64_array, f64); +JsTypedArrayType!( + JsUint8Array, + Uint8Array, + is_typed_uint8_array, + typed_uint8_array, + u8 +); +JsTypedArrayType!( + JsInt8Array, + Int8Array, + is_typed_int8_array, + typed_int8_array, + i8 +); +JsTypedArrayType!( + JsUint16Array, + Uint16Array, + is_typed_uint16_array, + typed_uint16_array, + u16 +); +JsTypedArrayType!( + JsInt16Array, + Int16Array, + is_typed_int16_array, + typed_int16_array, + i16 +); +JsTypedArrayType!( + JsUint32Array, + Uint32Array, + is_typed_uint32_array, + typed_uint32_array, + u32 +); +JsTypedArrayType!( + JsInt32Array, + Int32Array, + is_typed_int32_array, + typed_int32_array, + i32 +); +JsTypedArrayType!( + JsFloat32Array, + Float32Array, + is_typed_float32_array, + typed_float32_array, + f32 +); +JsTypedArrayType!( + JsFloat64Array, + Float64Array, + is_typed_float64_array, + typed_float64_array, + f64 +); diff --git a/boa_engine/src/object/jsobject.rs b/boa_engine/src/object/jsobject.rs index ddc67a370c..f81676ae55 100644 --- a/boa_engine/src/object/jsobject.rs +++ b/boa_engine/src/object/jsobject.rs @@ -309,6 +309,17 @@ impl JsObject { self.borrow().is_array() } + /// Checks if it's a `DataView` object. + /// + /// # Panics + /// + /// Panics if the object is currently mutably borrowed. + #[inline] + #[track_caller] + pub fn is_data_view(&self) -> bool { + self.borrow().is_data_view() + } + /// Checks if it is an `ArrayIterator` object. /// /// # Panics @@ -463,6 +474,17 @@ impl JsObject { self.borrow().is_bigint() } + /// Checks if it's a `Date` object. + /// + /// # Panics + /// + /// Panics if the object is currently mutably borrowed. + #[inline] + #[track_caller] + pub fn is_date(&self) -> bool { + self.borrow().is_date() + } + /// Checks if it's a `RegExp` object. /// /// # Panics @@ -485,6 +507,94 @@ impl JsObject { self.borrow().is_typed_array() } + /// Checks if it's a `Uint8Array` object. + /// + /// # Panics + /// + /// Panics if the object is currently mutably borrowed. + #[inline] + #[track_caller] + pub fn is_typed_uint8_array(&self) -> bool { + self.borrow().is_typed_uint8_array() + } + + /// Checks if it's a `Int8Array` object. + /// + /// # Panics + /// + /// Panics if the object is currently mutably borrowed. + #[inline] + #[track_caller] + pub fn is_typed_int8_array(&self) -> bool { + self.borrow().is_typed_int8_array() + } + + /// Checks if it's a `Uint16Array` object. + /// + /// # Panics + /// + /// Panics if the object is currently mutably borrowed. + #[inline] + #[track_caller] + pub fn is_typed_uint16_array(&self) -> bool { + self.borrow().is_typed_uint16_array() + } + + /// Checks if it's a `Int16Array` object. + /// + /// # Panics + /// + /// Panics if the object is currently mutably borrowed. + #[inline] + #[track_caller] + pub fn is_typed_int16_array(&self) -> bool { + self.borrow().is_typed_int16_array() + } + + /// Checks if it's a `Uint32Array` object. + /// + /// # Panics + /// + /// Panics if the object is currently mutably borrowed. + #[inline] + #[track_caller] + pub fn is_typed_uint32_array(&self) -> bool { + self.borrow().is_typed_uint32_array() + } + + /// Checks if it's a `Int32Array` object. + /// + /// # Panics + /// + /// Panics if the object is currently mutably borrowed. + #[inline] + #[track_caller] + pub fn is_typed_int32_array(&self) -> bool { + self.borrow().is_typed_int32_array() + } + + /// Checks if it's a `Float32Array` object. + /// + /// # Panics + /// + /// Panics if the object is currently mutably borrowed. + #[inline] + #[track_caller] + pub fn is_typed_float32_array(&self) -> bool { + self.borrow().is_typed_float32_array() + } + + /// Checks if it's a `Float64Array` object. + /// + /// # Panics + /// + /// Panics if the object is currently mutably borrowed. + #[inline] + #[track_caller] + pub fn is_typed_float64_array(&self) -> bool { + self.borrow().is_typed_float64_array() + } + /// Checks if it's a `Promise` object. /// /// # Panics @@ -507,6 +617,17 @@ impl JsObject { self.borrow().is_ordinary() } + /// Checks if it's a proxy object. + /// + /// # Panics + /// + /// Panics if the object is currently mutably borrowed. + #[inline] + #[track_caller] + pub fn is_proxy(&self) -> bool { + self.borrow().is_proxy() + } + /// Returns `true` if it holds an Rust type that implements `NativeObject`. /// /// # Panics diff --git a/boa_engine/src/object/mod.rs b/boa_engine/src/object/mod.rs index 7f38e20fa6..a850e36d95 100644 --- a/boa_engine/src/object/mod.rs +++ b/boa_engine/src/object/mod.rs @@ -45,7 +45,7 @@ use crate::{ set::ordered_set::OrderedSet, set::SetIterator, string::StringIterator, - typed_array::integer_indexed_object::IntegerIndexed, + typed_array::{integer_indexed_object::IntegerIndexed, TypedArrayKind}, DataView, Date, Promise, RegExp, }, js_string, @@ -1429,6 +1429,118 @@ impl Object { ) } + /// Checks if it a `Uint8Array` object. + #[inline] + pub const fn is_typed_uint8_array(&self) -> bool { + if let ObjectData { + kind: ObjectKind::IntegerIndexed(ref int), + .. + } = self.data + { + matches!(int.typed_array_name(), TypedArrayKind::Uint8) + } else { + false + } + } + + /// Checks if it a `Int8Array` object. + #[inline] + pub const fn is_typed_int8_array(&self) -> bool { + if let ObjectData { + kind: ObjectKind::IntegerIndexed(ref int), + .. + } = self.data + { + matches!(int.typed_array_name(), TypedArrayKind::Int8) + } else { + false + } + } + + /// Checks if it a `Uint16Array` object. + #[inline] + pub const fn is_typed_uint16_array(&self) -> bool { + if let ObjectData { + kind: ObjectKind::IntegerIndexed(ref int), + .. + } = self.data + { + matches!(int.typed_array_name(), TypedArrayKind::Uint16) + } else { + false + } + } + + /// Checks if it a `Int16Array` object. + #[inline] + pub const fn is_typed_int16_array(&self) -> bool { + if let ObjectData { + kind: ObjectKind::IntegerIndexed(ref int), + .. + } = self.data + { + matches!(int.typed_array_name(), TypedArrayKind::Int16) + } else { + false + } + } + + /// Checks if it a `Uint32Array` object. + #[inline] + pub const fn is_typed_uint32_array(&self) -> bool { + if let ObjectData { + kind: ObjectKind::IntegerIndexed(ref int), + .. + } = self.data + { + matches!(int.typed_array_name(), TypedArrayKind::Uint32) + } else { + false + } + } + + /// Checks if it a `Int32Array` object. + #[inline] + pub const fn is_typed_int32_array(&self) -> bool { + if let ObjectData { + kind: ObjectKind::IntegerIndexed(ref int), + .. + } = self.data + { + matches!(int.typed_array_name(), TypedArrayKind::Int32) + } else { + false + } + } + + /// Checks if it a `Float32Array` object. + #[inline] + pub const fn is_typed_float32_array(&self) -> bool { + if let ObjectData { + kind: ObjectKind::IntegerIndexed(ref int), + .. + } = self.data + { + matches!(int.typed_array_name(), TypedArrayKind::Float32) + } else { + false + } + } + + /// Checks if it a `Float64Array` object. + #[inline] + pub const fn is_typed_float64_array(&self) -> bool { + if let ObjectData { + kind: ObjectKind::IntegerIndexed(ref int), + .. + } = self.data + { + matches!(int.typed_array_name(), TypedArrayKind::Float64) + } else { + false + } + } + /// Gets the data view data if the object is a `DataView`. #[inline] pub const fn as_data_view(&self) -> Option<&DataView> { diff --git a/boa_engine/src/object/operations.rs b/boa_engine/src/object/operations.rs index 5dfc97a236..5a74b4cb5c 100644 --- a/boa_engine/src/object/operations.rs +++ b/boa_engine/src/object/operations.rs @@ -300,13 +300,16 @@ impl JsObject { Ok(desc.is_some()) } - /// Call this object. + /// `Call ( F, V [ , argumentsList ] )` /// /// # Panics /// /// Panics if the object is currently mutably borrowed. - // - // + /// + /// More information: + /// - [ECMAScript reference][spec] + /// + /// [spec]: https://tc39.es/ecma262/#sec-call #[track_caller] #[inline] pub fn call( @@ -317,8 +320,9 @@ impl JsObject { ) -> JsResult { // 1. If argumentsList is not present, set argumentsList to a new empty List. // 2. If IsCallable(F) is false, throw a TypeError exception. - let function = JsFunction::from_object(self.clone()) - .ok_or_else(|| JsNativeError::typ().with_message("not a function"))?; + let function = JsFunction::from_object(self.clone()).ok_or_else(|| { + JsNativeError::typ().with_message("only callable objects / functions can be called") + })?; // 3. Return ? F.[[Call]](V, argumentsList). function.__call__(this, args, context)