From 64136e684eafff828f92f3785c1a895b61e9ec57 Mon Sep 17 00:00:00 2001 From: Bert Belder Date: Fri, 3 Jan 2020 14:41:17 +0100 Subject: [PATCH] Add safe downcasts for Local with TryFrom (#166) (#166) --- src/data.rs | 643 ++++++++++++++++++++++++++-------------------- tests/test_api.rs | 17 +- 2 files changed, 366 insertions(+), 294 deletions(-) diff --git a/src/data.rs b/src/data.rs index c2dc8e26..51bb98d3 100644 --- a/src/data.rs +++ b/src/data.rs @@ -1,14 +1,26 @@ // Copyright 2019-2020 the Deno authors. All rights reserved. MIT license. use std::convert::From; +use std::convert::TryFrom; use std::mem::transmute; use std::ops::Deref; use crate::support::Opaque; use crate::Local; +macro_rules! impl_deref { + { $a:ident for $b:ident } => { + impl Deref for $a { + type Target = $b; + fn deref(&self) -> &Self::Target { + unsafe { &*(self as *const _ as *const Self::Target) } + } + } + }; +} + macro_rules! impl_from { - ($a:ident, $b:ident) => { + { $a:ident for $b:ident } => { impl<'sc> From> for Local<'sc, $b> { fn from(l: Local<'sc, $a>) -> Self { unsafe { transmute(l) } @@ -17,12 +29,18 @@ macro_rules! impl_from { }; } -macro_rules! impl_deref { - ($a:ident, $b:ident) => { - impl Deref for $a { - type Target = $b; - fn deref(&self) -> &Self::Target { - unsafe { &*(self as *const _ as *const Self::Target) } +#[derive(Clone, Copy, Debug)] +pub struct TryFromTypeError; + +macro_rules! impl_try_from { + { $a:ident for $b:ident if $p:pat => $c:expr } => { + impl<'sc> TryFrom> for Local<'sc, $b> { + type Error = TryFromTypeError; + fn try_from(l: Local<'sc, $a>) -> Result { + match l { + $p if $c => Ok(unsafe { transmute(l) }), + _ => Err(TryFromTypeError) + } } } }; @@ -36,25 +54,22 @@ pub struct Data(Opaque); /// to an accessor callback. #[repr(C)] pub struct AccessorSignature(Opaque); - -impl_deref!(AccessorSignature, Data); -impl_from!(AccessorSignature, Data); +impl_deref! { AccessorSignature for Data } +impl_from! { AccessorSignature for Data } /// A compiled JavaScript module. #[repr(C)] pub struct Module(Opaque); - -impl_deref!(Module, Data); -impl_from!(Module, Data); +impl_deref! { Module for Data } +impl_from! { Module for Data } /// A private symbol /// /// This is an experimental feature. Use at your own risk. #[repr(C)] pub struct Private(Opaque); - -impl_deref!(Private, Data); -impl_from!(Private, Data); +impl_deref! { Private for Data } +impl_from! { Private for Data } /// A Signature specifies which receiver is valid for a function. /// @@ -64,16 +79,14 @@ impl_from!(Private, Data); /// signature's FunctionTemplate. #[repr(C)] pub struct Signature(Opaque); - -impl_deref!(Signature, Data); -impl_from!(Signature, Data); +impl_deref! { Signature for Data } +impl_from! { Signature for Data } /// The superclass of object and function templates. #[repr(C)] pub struct Template(Opaque); - -impl_deref!(Template, Data); -impl_from!(Template, Data); +impl_deref! { Template for Data } +impl_from! { Template for Data } /// A FunctionTemplate is used to create functions at runtime. There /// can only be one function created from a FunctionTemplate in a @@ -175,10 +188,9 @@ impl_from!(Template, Data); /// ``` #[repr(C)] pub struct FunctionTemplate(Opaque); - -impl_deref!(FunctionTemplate, Template); -impl_from!(FunctionTemplate, Data); -impl_from!(FunctionTemplate, Template); +impl_deref! { FunctionTemplate for Template } +impl_from! { FunctionTemplate for Data } +impl_from! { FunctionTemplate for Template } /// An ObjectTemplate is used to create objects at runtime. /// @@ -186,451 +198,514 @@ impl_from!(FunctionTemplate, Template); /// created from the ObjectTemplate. #[repr(C)] pub struct ObjectTemplate(Opaque); - -impl_deref!(ObjectTemplate, Template); -impl_from!(ObjectTemplate, Data); -impl_from!(ObjectTemplate, Template); +impl_deref! { ObjectTemplate for Template } +impl_from! { ObjectTemplate for Data } +impl_from! { ObjectTemplate for Template } /// A compiled JavaScript module, not yet tied to a Context. #[repr(C)] pub struct UnboundModuleScript(Opaque); - -impl_deref!(UnboundModuleScript, Data); -impl_from!(UnboundModuleScript, Data); +impl_deref! { UnboundModuleScript for Data } +impl_from! { UnboundModuleScript for Data } /// The superclass of all JavaScript values and objects. #[repr(C)] pub struct Value(Opaque); - -impl_deref!(Value, Data); -impl_from!(Value, Data); +impl_deref! { Value for Data } +impl_from! { Value for Data } /// A JavaScript value that wraps a C++ void*. This type of value is mainly used /// to associate C++ data structures with JavaScript objects. #[repr(C)] pub struct External(Opaque); - -impl_deref!(External, Value); -impl_from!(External, Data); -impl_from!(External, Value); +impl_deref! { External for Value } +impl_from! { External for Data } +impl_from! { External for Value } +impl_try_from! { Value for External if v => v.is_external() } /// A JavaScript object (ECMA-262, 4.3.3) #[repr(C)] pub struct Object(Opaque); - -impl_deref!(Object, Value); -impl_from!(Object, Data); -impl_from!(Object, Value); +impl_deref! { Object for Value } +impl_from! { Object for Data } +impl_from! { Object for Value } +impl_try_from! { Value for Object if v => v.is_object() } /// An instance of the built-in array constructor (ECMA-262, 15.4.2). #[repr(C)] pub struct Array(Opaque); - -impl_deref!(Array, Object); -impl_from!(Array, Data); -impl_from!(Array, Value); -impl_from!(Array, Object); +impl_deref! { Array for Object } +impl_from! { Array for Data } +impl_from! { Array for Value } +impl_from! { Array for Object } +impl_try_from! { Object for Array if v => v.is_array() } +impl_try_from! { Value for Array if v => v.is_array() } /// An instance of the built-in ArrayBuffer constructor (ES6 draft 15.13.5). #[repr(C)] pub struct ArrayBuffer(Opaque); - -impl_deref!(ArrayBuffer, Object); -impl_from!(ArrayBuffer, Data); -impl_from!(ArrayBuffer, Value); -impl_from!(ArrayBuffer, Object); +impl_deref! { ArrayBuffer for Object } +impl_from! { ArrayBuffer for Data } +impl_from! { ArrayBuffer for Value } +impl_from! { ArrayBuffer for Object } +impl_try_from! { Object for ArrayBuffer if v => v.is_array_buffer() } +impl_try_from! { Value for ArrayBuffer if v => v.is_array_buffer() } /// A base class for an instance of one of "views" over ArrayBuffer, /// including TypedArrays and DataView (ES6 draft 15.13). #[repr(C)] pub struct ArrayBufferView(Opaque); - -impl_deref!(ArrayBufferView, Object); -impl_from!(ArrayBufferView, Data); -impl_from!(ArrayBufferView, Value); -impl_from!(ArrayBufferView, Object); +impl_deref! { ArrayBufferView for Object } +impl_from! { ArrayBufferView for Data } +impl_from! { ArrayBufferView for Value } +impl_from! { ArrayBufferView for Object } +impl_try_from! { Object for ArrayBufferView if v => v.is_array_buffer_view() } +impl_try_from! { Value for ArrayBufferView if v => v.is_array_buffer_view() } /// An instance of DataView constructor (ES6 draft 15.13.7). #[repr(C)] pub struct DataView(Opaque); - -impl_deref!(DataView, ArrayBufferView); -impl_from!(DataView, Data); -impl_from!(DataView, Value); -impl_from!(DataView, Object); -impl_from!(DataView, ArrayBufferView); +impl_deref! { DataView for ArrayBufferView } +impl_from! { DataView for Data } +impl_from! { DataView for Value } +impl_from! { DataView for Object } +impl_from! { DataView for ArrayBufferView } +impl_try_from! { ArrayBufferView for DataView if v => v.is_data_view() } +impl_try_from! { Object for DataView if v => v.is_data_view() } +impl_try_from! { Value for DataView if v => v.is_data_view() } /// A base class for an instance of TypedArray series of constructors /// (ES6 draft 15.13.6). #[repr(C)] pub struct TypedArray(Opaque); - -impl_deref!(TypedArray, ArrayBufferView); -impl_from!(TypedArray, Data); -impl_from!(TypedArray, Value); -impl_from!(TypedArray, Object); -impl_from!(TypedArray, ArrayBufferView); +impl_deref! { TypedArray for ArrayBufferView } +impl_from! { TypedArray for Data } +impl_from! { TypedArray for Value } +impl_from! { TypedArray for Object } +impl_from! { TypedArray for ArrayBufferView } +impl_try_from! { ArrayBufferView for TypedArray if v => v.is_typed_array() } +impl_try_from! { Object for TypedArray if v => v.is_typed_array() } +impl_try_from! { Value for TypedArray if v => v.is_typed_array() } /// An instance of BigInt64Array constructor. #[repr(C)] pub struct BigInt64Array(Opaque); - -impl_deref!(BigInt64Array, TypedArray); -impl_from!(BigInt64Array, Data); -impl_from!(BigInt64Array, Value); -impl_from!(BigInt64Array, Object); -impl_from!(BigInt64Array, ArrayBufferView); -impl_from!(BigInt64Array, TypedArray); +impl_deref! { BigInt64Array for TypedArray } +impl_from! { BigInt64Array for Data } +impl_from! { BigInt64Array for Value } +impl_from! { BigInt64Array for Object } +impl_from! { BigInt64Array for ArrayBufferView } +impl_from! { BigInt64Array for TypedArray } +impl_try_from! { TypedArray for BigInt64Array if v => v.is_big_int64_array() } +impl_try_from! { ArrayBufferView for BigInt64Array if v => v.is_big_int64_array() } +impl_try_from! { Object for BigInt64Array if v => v.is_big_int64_array() } +impl_try_from! { Value for BigInt64Array if v => v.is_big_int64_array() } /// An instance of BigUint64Array constructor. #[repr(C)] pub struct BigUint64Array(Opaque); - -impl_deref!(BigUint64Array, TypedArray); -impl_from!(BigUint64Array, Data); -impl_from!(BigUint64Array, Value); -impl_from!(BigUint64Array, Object); -impl_from!(BigUint64Array, ArrayBufferView); -impl_from!(BigUint64Array, TypedArray); +impl_deref! { BigUint64Array for TypedArray } +impl_from! { BigUint64Array for Data } +impl_from! { BigUint64Array for Value } +impl_from! { BigUint64Array for Object } +impl_from! { BigUint64Array for ArrayBufferView } +impl_from! { BigUint64Array for TypedArray } +impl_try_from! { TypedArray for BigUint64Array if v => v.is_big_uint64_array() } +impl_try_from! { ArrayBufferView for BigUint64Array if v => v.is_big_uint64_array() } +impl_try_from! { Object for BigUint64Array if v => v.is_big_uint64_array() } +impl_try_from! { Value for BigUint64Array if v => v.is_big_uint64_array() } /// An instance of Float32Array constructor (ES6 draft 15.13.6). #[repr(C)] pub struct Float32Array(Opaque); - -impl_deref!(Float32Array, TypedArray); -impl_from!(Float32Array, Data); -impl_from!(Float32Array, Value); -impl_from!(Float32Array, Object); -impl_from!(Float32Array, ArrayBufferView); -impl_from!(Float32Array, TypedArray); +impl_deref! { Float32Array for TypedArray } +impl_from! { Float32Array for Data } +impl_from! { Float32Array for Value } +impl_from! { Float32Array for Object } +impl_from! { Float32Array for ArrayBufferView } +impl_from! { Float32Array for TypedArray } +impl_try_from! { TypedArray for Float32Array if v => v.is_float32_array() } +impl_try_from! { ArrayBufferView for Float32Array if v => v.is_float32_array() } +impl_try_from! { Object for Float32Array if v => v.is_float32_array() } +impl_try_from! { Value for Float32Array if v => v.is_float32_array() } /// An instance of Float64Array constructor (ES6 draft 15.13.6). #[repr(C)] pub struct Float64Array(Opaque); - -impl_deref!(Float64Array, TypedArray); -impl_from!(Float64Array, Data); -impl_from!(Float64Array, Value); -impl_from!(Float64Array, Object); -impl_from!(Float64Array, ArrayBufferView); -impl_from!(Float64Array, TypedArray); +impl_deref! { Float64Array for TypedArray } +impl_from! { Float64Array for Data } +impl_from! { Float64Array for Value } +impl_from! { Float64Array for Object } +impl_from! { Float64Array for ArrayBufferView } +impl_from! { Float64Array for TypedArray } +impl_try_from! { TypedArray for Float64Array if v => v.is_float64_array() } +impl_try_from! { ArrayBufferView for Float64Array if v => v.is_float64_array() } +impl_try_from! { Object for Float64Array if v => v.is_float64_array() } +impl_try_from! { Value for Float64Array if v => v.is_float64_array() } /// An instance of Int16Array constructor (ES6 draft 15.13.6). #[repr(C)] pub struct Int16Array(Opaque); - -impl_deref!(Int16Array, TypedArray); -impl_from!(Int16Array, Data); -impl_from!(Int16Array, Value); -impl_from!(Int16Array, Object); -impl_from!(Int16Array, ArrayBufferView); -impl_from!(Int16Array, TypedArray); +impl_deref! { Int16Array for TypedArray } +impl_from! { Int16Array for Data } +impl_from! { Int16Array for Value } +impl_from! { Int16Array for Object } +impl_from! { Int16Array for ArrayBufferView } +impl_from! { Int16Array for TypedArray } +impl_try_from! { TypedArray for Int16Array if v => v.is_int16_array() } +impl_try_from! { ArrayBufferView for Int16Array if v => v.is_int16_array() } +impl_try_from! { Object for Int16Array if v => v.is_int16_array() } +impl_try_from! { Value for Int16Array if v => v.is_int16_array() } /// An instance of Int32Array constructor (ES6 draft 15.13.6). #[repr(C)] pub struct Int32Array(Opaque); - -impl_deref!(Int32Array, TypedArray); -impl_from!(Int32Array, Data); -impl_from!(Int32Array, Value); -impl_from!(Int32Array, Object); -impl_from!(Int32Array, ArrayBufferView); -impl_from!(Int32Array, TypedArray); +impl_deref! { Int32Array for TypedArray } +impl_from! { Int32Array for Data } +impl_from! { Int32Array for Value } +impl_from! { Int32Array for Object } +impl_from! { Int32Array for ArrayBufferView } +impl_from! { Int32Array for TypedArray } +impl_try_from! { TypedArray for Int32Array if v => v.is_int32_array() } +impl_try_from! { ArrayBufferView for Int32Array if v => v.is_int32_array() } +impl_try_from! { Object for Int32Array if v => v.is_int32_array() } +impl_try_from! { Value for Int32Array if v => v.is_int32_array() } /// An instance of Int8Array constructor (ES6 draft 15.13.6). #[repr(C)] pub struct Int8Array(Opaque); - -impl_deref!(Int8Array, TypedArray); -impl_from!(Int8Array, Data); -impl_from!(Int8Array, Value); -impl_from!(Int8Array, Object); -impl_from!(Int8Array, ArrayBufferView); -impl_from!(Int8Array, TypedArray); +impl_deref! { Int8Array for TypedArray } +impl_from! { Int8Array for Data } +impl_from! { Int8Array for Value } +impl_from! { Int8Array for Object } +impl_from! { Int8Array for ArrayBufferView } +impl_from! { Int8Array for TypedArray } +impl_try_from! { TypedArray for Int8Array if v => v.is_int8_array() } +impl_try_from! { ArrayBufferView for Int8Array if v => v.is_int8_array() } +impl_try_from! { Object for Int8Array if v => v.is_int8_array() } +impl_try_from! { Value for Int8Array if v => v.is_int8_array() } /// An instance of Uint16Array constructor (ES6 draft 15.13.6). #[repr(C)] pub struct Uint16Array(Opaque); - -impl_deref!(Uint16Array, TypedArray); -impl_from!(Uint16Array, Data); -impl_from!(Uint16Array, Value); -impl_from!(Uint16Array, Object); -impl_from!(Uint16Array, ArrayBufferView); -impl_from!(Uint16Array, TypedArray); +impl_deref! { Uint16Array for TypedArray } +impl_from! { Uint16Array for Data } +impl_from! { Uint16Array for Value } +impl_from! { Uint16Array for Object } +impl_from! { Uint16Array for ArrayBufferView } +impl_from! { Uint16Array for TypedArray } +impl_try_from! { TypedArray for Uint16Array if v => v.is_uint16_array() } +impl_try_from! { ArrayBufferView for Uint16Array if v => v.is_uint16_array() } +impl_try_from! { Object for Uint16Array if v => v.is_uint16_array() } +impl_try_from! { Value for Uint16Array if v => v.is_uint16_array() } /// An instance of Uint32Array constructor (ES6 draft 15.13.6). #[repr(C)] pub struct Uint32Array(Opaque); - -impl_deref!(Uint32Array, TypedArray); -impl_from!(Uint32Array, Data); -impl_from!(Uint32Array, Value); -impl_from!(Uint32Array, Object); -impl_from!(Uint32Array, ArrayBufferView); -impl_from!(Uint32Array, TypedArray); +impl_deref! { Uint32Array for TypedArray } +impl_from! { Uint32Array for Data } +impl_from! { Uint32Array for Value } +impl_from! { Uint32Array for Object } +impl_from! { Uint32Array for ArrayBufferView } +impl_from! { Uint32Array for TypedArray } +impl_try_from! { TypedArray for Uint32Array if v => v.is_uint32_array() } +impl_try_from! { ArrayBufferView for Uint32Array if v => v.is_uint32_array() } +impl_try_from! { Object for Uint32Array if v => v.is_uint32_array() } +impl_try_from! { Value for Uint32Array if v => v.is_uint32_array() } /// An instance of Uint8Array constructor (ES6 draft 15.13.6). #[repr(C)] pub struct Uint8Array(Opaque); - -impl_deref!(Uint8Array, TypedArray); -impl_from!(Uint8Array, Data); -impl_from!(Uint8Array, Value); -impl_from!(Uint8Array, Object); -impl_from!(Uint8Array, ArrayBufferView); -impl_from!(Uint8Array, TypedArray); +impl_deref! { Uint8Array for TypedArray } +impl_from! { Uint8Array for Data } +impl_from! { Uint8Array for Value } +impl_from! { Uint8Array for Object } +impl_from! { Uint8Array for ArrayBufferView } +impl_from! { Uint8Array for TypedArray } +impl_try_from! { TypedArray for Uint8Array if v => v.is_uint8_array() } +impl_try_from! { ArrayBufferView for Uint8Array if v => v.is_uint8_array() } +impl_try_from! { Object for Uint8Array if v => v.is_uint8_array() } +impl_try_from! { Value for Uint8Array if v => v.is_uint8_array() } /// An instance of Uint8ClampedArray constructor (ES6 draft 15.13.6). #[repr(C)] pub struct Uint8ClampedArray(Opaque); - -impl_deref!(Uint8ClampedArray, TypedArray); -impl_from!(Uint8ClampedArray, Data); -impl_from!(Uint8ClampedArray, Value); -impl_from!(Uint8ClampedArray, Object); -impl_from!(Uint8ClampedArray, ArrayBufferView); -impl_from!(Uint8ClampedArray, TypedArray); +impl_deref! { Uint8ClampedArray for TypedArray } +impl_from! { Uint8ClampedArray for Data } +impl_from! { Uint8ClampedArray for Value } +impl_from! { Uint8ClampedArray for Object } +impl_from! { Uint8ClampedArray for ArrayBufferView } +impl_from! { Uint8ClampedArray for TypedArray } +impl_try_from! { TypedArray for Uint8ClampedArray if v => v.is_uint8_clamped_array() } +impl_try_from! { ArrayBufferView for Uint8ClampedArray if v => v.is_uint8_clamped_array() } +impl_try_from! { Object for Uint8ClampedArray if v => v.is_uint8_clamped_array() } +impl_try_from! { Value for Uint8ClampedArray if v => v.is_uint8_clamped_array() } /// A BigInt object (https://tc39.github.io/proposal-bigint) #[repr(C)] pub struct BigIntObject(Opaque); - -impl_deref!(BigIntObject, Object); -impl_from!(BigIntObject, Data); -impl_from!(BigIntObject, Value); -impl_from!(BigIntObject, Object); +impl_deref! { BigIntObject for Object } +impl_from! { BigIntObject for Data } +impl_from! { BigIntObject for Value } +impl_from! { BigIntObject for Object } +impl_try_from! { Object for BigIntObject if v => v.is_big_int_object() } +impl_try_from! { Value for BigIntObject if v => v.is_big_int_object() } /// A Boolean object (ECMA-262, 4.3.15). #[repr(C)] pub struct BooleanObject(Opaque); - -impl_deref!(BooleanObject, Object); -impl_from!(BooleanObject, Data); -impl_from!(BooleanObject, Value); -impl_from!(BooleanObject, Object); +impl_deref! { BooleanObject for Object } +impl_from! { BooleanObject for Data } +impl_from! { BooleanObject for Value } +impl_from! { BooleanObject for Object } +impl_try_from! { Object for BooleanObject if v => v.is_boolean_object() } +impl_try_from! { Value for BooleanObject if v => v.is_boolean_object() } /// An instance of the built-in Date constructor (ECMA-262, 15.9). #[repr(C)] pub struct Date(Opaque); - -impl_deref!(Date, Object); -impl_from!(Date, Data); -impl_from!(Date, Value); -impl_from!(Date, Object); +impl_deref! { Date for Object } +impl_from! { Date for Data } +impl_from! { Date for Value } +impl_from! { Date for Object } +impl_try_from! { Object for Date if v => v.is_date() } +impl_try_from! { Value for Date if v => v.is_date() } /// An instance of the built-in FinalizationGroup constructor. /// /// This API is experimental and may change significantly. #[repr(C)] pub struct FinalizationGroup(Opaque); - -impl_deref!(FinalizationGroup, Object); -impl_from!(FinalizationGroup, Data); -impl_from!(FinalizationGroup, Value); -impl_from!(FinalizationGroup, Object); +impl_deref! { FinalizationGroup for Object } +impl_from! { FinalizationGroup for Data } +impl_from! { FinalizationGroup for Value } +impl_from! { FinalizationGroup for Object } /// A JavaScript function object (ECMA-262, 15.3). #[repr(C)] pub struct Function(Opaque); - -impl_deref!(Function, Object); -impl_from!(Function, Data); -impl_from!(Function, Value); -impl_from!(Function, Object); +impl_deref! { Function for Object } +impl_from! { Function for Data } +impl_from! { Function for Value } +impl_from! { Function for Object } +impl_try_from! { Object for Function if v => v.is_function() } +impl_try_from! { Value for Function if v => v.is_function() } /// An instance of the built-in Map constructor (ECMA-262, 6th Edition, 23.1.1). #[repr(C)] pub struct Map(Opaque); - -impl_deref!(Map, Object); -impl_from!(Map, Data); -impl_from!(Map, Value); -impl_from!(Map, Object); +impl_deref! { Map for Object } +impl_from! { Map for Data } +impl_from! { Map for Value } +impl_from! { Map for Object } +impl_try_from! { Object for Map if v => v.is_map() } +impl_try_from! { Value for Map if v => v.is_map() } /// A Number object (ECMA-262, 4.3.21). #[repr(C)] pub struct NumberObject(Opaque); - -impl_deref!(NumberObject, Object); -impl_from!(NumberObject, Data); -impl_from!(NumberObject, Value); -impl_from!(NumberObject, Object); +impl_deref! { NumberObject for Object } +impl_from! { NumberObject for Data } +impl_from! { NumberObject for Value } +impl_from! { NumberObject for Object } +impl_try_from! { Object for NumberObject if v => v.is_number_object() } +impl_try_from! { Value for NumberObject if v => v.is_number_object() } /// An instance of the built-in Promise constructor (ES6 draft). #[repr(C)] pub struct Promise(Opaque); - -impl_deref!(Promise, Object); -impl_from!(Promise, Data); -impl_from!(Promise, Value); -impl_from!(Promise, Object); +impl_deref! { Promise for Object } +impl_from! { Promise for Data } +impl_from! { Promise for Value } +impl_from! { Promise for Object } +impl_try_from! { Object for Promise if v => v.is_promise() } +impl_try_from! { Value for Promise if v => v.is_promise() } #[repr(C)] pub struct PromiseResolver(Opaque); - -impl_deref!(PromiseResolver, Object); -impl_from!(PromiseResolver, Data); -impl_from!(PromiseResolver, Value); -impl_from!(PromiseResolver, Object); +impl_deref! { PromiseResolver for Object } +impl_from! { PromiseResolver for Data } +impl_from! { PromiseResolver for Value } +impl_from! { PromiseResolver for Object } /// An instance of the built-in Proxy constructor (ECMA-262, 6th Edition, /// 26.2.1). #[repr(C)] pub struct Proxy(Opaque); - -impl_deref!(Proxy, Object); -impl_from!(Proxy, Data); -impl_from!(Proxy, Value); -impl_from!(Proxy, Object); +impl_deref! { Proxy for Object } +impl_from! { Proxy for Data } +impl_from! { Proxy for Value } +impl_from! { Proxy for Object } +impl_try_from! { Object for Proxy if v => v.is_proxy() } +impl_try_from! { Value for Proxy if v => v.is_proxy() } /// An instance of the built-in RegExp constructor (ECMA-262, 15.10). #[repr(C)] pub struct RegExp(Opaque); - -impl_deref!(RegExp, Object); -impl_from!(RegExp, Data); -impl_from!(RegExp, Value); -impl_from!(RegExp, Object); +impl_deref! { RegExp for Object } +impl_from! { RegExp for Data } +impl_from! { RegExp for Value } +impl_from! { RegExp for Object } +impl_try_from! { Object for RegExp if v => v.is_reg_exp() } +impl_try_from! { Value for RegExp if v => v.is_reg_exp() } /// An instance of the built-in Set constructor (ECMA-262, 6th Edition, 23.2.1). #[repr(C)] pub struct Set(Opaque); - -impl_deref!(Set, Object); -impl_from!(Set, Data); -impl_from!(Set, Value); -impl_from!(Set, Object); +impl_deref! { Set for Object } +impl_from! { Set for Data } +impl_from! { Set for Value } +impl_from! { Set for Object } +impl_try_from! { Object for Set if v => v.is_set() } +impl_try_from! { Value for Set if v => v.is_set() } /// An instance of the built-in SharedArrayBuffer constructor. /// This API is experimental and may change significantly. #[repr(C)] pub struct SharedArrayBuffer(Opaque); - -impl_deref!(SharedArrayBuffer, Object); -impl_from!(SharedArrayBuffer, Data); -impl_from!(SharedArrayBuffer, Value); -impl_from!(SharedArrayBuffer, Object); +impl_deref! { SharedArrayBuffer for Object } +impl_from! { SharedArrayBuffer for Data } +impl_from! { SharedArrayBuffer for Value } +impl_from! { SharedArrayBuffer for Object } +impl_try_from! { Object for SharedArrayBuffer if v => v.is_shared_array_buffer() } +impl_try_from! { Value for SharedArrayBuffer if v => v.is_shared_array_buffer() } /// A String object (ECMA-262, 4.3.18). #[repr(C)] pub struct StringObject(Opaque); - -impl_deref!(StringObject, Object); -impl_from!(StringObject, Data); -impl_from!(StringObject, Value); -impl_from!(StringObject, Object); +impl_deref! { StringObject for Object } +impl_from! { StringObject for Data } +impl_from! { StringObject for Value } +impl_from! { StringObject for Object } +impl_try_from! { Object for StringObject if v => v.is_string_object() } +impl_try_from! { Value for StringObject if v => v.is_string_object() } /// A Symbol object (ECMA-262 edition 6). #[repr(C)] pub struct SymbolObject(Opaque); - -impl_deref!(SymbolObject, Object); -impl_from!(SymbolObject, Data); -impl_from!(SymbolObject, Value); -impl_from!(SymbolObject, Object); +impl_deref! { SymbolObject for Object } +impl_from! { SymbolObject for Data } +impl_from! { SymbolObject for Value } +impl_from! { SymbolObject for Object } +impl_try_from! { Object for SymbolObject if v => v.is_symbol_object() } +impl_try_from! { Value for SymbolObject if v => v.is_symbol_object() } #[repr(C)] pub struct WasmModuleObject(Opaque); - -impl_deref!(WasmModuleObject, Object); -impl_from!(WasmModuleObject, Data); -impl_from!(WasmModuleObject, Value); -impl_from!(WasmModuleObject, Object); +impl_deref! { WasmModuleObject for Object } +impl_from! { WasmModuleObject for Data } +impl_from! { WasmModuleObject for Value } +impl_from! { WasmModuleObject for Object } /// The superclass of primitive values. See ECMA-262 4.3.2. #[repr(C)] pub struct Primitive(Opaque); - -impl_deref!(Primitive, Value); -impl_from!(Primitive, Data); -impl_from!(Primitive, Value); +impl_deref! { Primitive for Value } +impl_from! { Primitive for Data } +impl_from! { Primitive for Value } +impl_try_from! { Value for Primitive if v => v.is_null_or_undefined() || v.is_boolean() || v.is_name() || v.is_number() || v.is_big_int() } /// A JavaScript BigInt value (https://tc39.github.io/proposal-bigint) #[repr(C)] pub struct BigInt(Opaque); - -impl_deref!(BigInt, Primitive); -impl_from!(BigInt, Data); -impl_from!(BigInt, Value); -impl_from!(BigInt, Primitive); +impl_deref! { BigInt for Primitive } +impl_from! { BigInt for Data } +impl_from! { BigInt for Value } +impl_from! { BigInt for Primitive } +impl_try_from! { Primitive for BigInt if v => v.is_big_int() } +impl_try_from! { Value for BigInt if v => v.is_big_int() } /// A primitive boolean value (ECMA-262, 4.3.14). Either the true /// or false value. #[repr(C)] pub struct Boolean(Opaque); - -impl_deref!(Boolean, Primitive); -impl_from!(Boolean, Data); -impl_from!(Boolean, Value); -impl_from!(Boolean, Primitive); +impl_deref! { Boolean for Primitive } +impl_from! { Boolean for Data } +impl_from! { Boolean for Value } +impl_from! { Boolean for Primitive } +impl_try_from! { Primitive for Boolean if v => v.is_boolean() } +impl_try_from! { Value for Boolean if v => v.is_boolean() } /// A superclass for symbols and strings. #[repr(C)] pub struct Name(Opaque); - -impl_deref!(Name, Primitive); -impl_from!(Name, Data); -impl_from!(Name, Value); -impl_from!(Name, Primitive); +impl_deref! { Name for Primitive } +impl_from! { Name for Data } +impl_from! { Name for Value } +impl_from! { Name for Primitive } +impl_try_from! { Primitive for Name if v => v.is_name() } +impl_try_from! { Value for Name if v => v.is_name() } /// A JavaScript string value (ECMA-262, 4.3.17). #[repr(C)] pub struct String(Opaque); - -impl_deref!(String, Name); -impl_from!(String, Data); -impl_from!(String, Value); -impl_from!(String, Primitive); -impl_from!(String, Name); +impl_deref! { String for Name } +impl_from! { String for Data } +impl_from! { String for Value } +impl_from! { String for Primitive } +impl_from! { String for Name } +impl_try_from! { Name for String if v => v.is_string() } +impl_try_from! { Primitive for String if v => v.is_string() } +impl_try_from! { Value for String if v => v.is_string() } /// A JavaScript symbol (ECMA-262 edition 6) #[repr(C)] pub struct Symbol(Opaque); - -impl_deref!(Symbol, Name); -impl_from!(Symbol, Data); -impl_from!(Symbol, Value); -impl_from!(Symbol, Primitive); -impl_from!(Symbol, Name); +impl_deref! { Symbol for Name } +impl_from! { Symbol for Data } +impl_from! { Symbol for Value } +impl_from! { Symbol for Primitive } +impl_from! { Symbol for Name } +impl_try_from! { Name for Symbol if v => v.is_symbol() } +impl_try_from! { Primitive for Symbol if v => v.is_symbol() } +impl_try_from! { Value for Symbol if v => v.is_symbol() } /// A JavaScript number value (ECMA-262, 4.3.20) #[repr(C)] pub struct Number(Opaque); - -impl_deref!(Number, Primitive); -impl_from!(Number, Data); -impl_from!(Number, Value); -impl_from!(Number, Primitive); +impl_deref! { Number for Primitive } +impl_from! { Number for Data } +impl_from! { Number for Value } +impl_from! { Number for Primitive } +impl_try_from! { Primitive for Number if v => v.is_number() } +impl_try_from! { Value for Number if v => v.is_number() } /// A JavaScript value representing a signed integer. #[repr(C)] pub struct Integer(Opaque); - -impl_deref!(Integer, Number); -impl_from!(Integer, Data); -impl_from!(Integer, Value); -impl_from!(Integer, Primitive); -impl_from!(Integer, Number); +impl_deref! { Integer for Number } +impl_from! { Integer for Data } +impl_from! { Integer for Value } +impl_from! { Integer for Primitive } +impl_from! { Integer for Number } +impl_try_from! { Number for Integer if v => v.is_int32() || v.is_uint32() } +impl_try_from! { Primitive for Integer if v => v.is_int32() || v.is_uint32() } +impl_try_from! { Value for Integer if v => v.is_int32() || v.is_uint32() } /// A JavaScript value representing a 32-bit signed integer. #[repr(C)] pub struct Int32(Opaque); - -impl_deref!(Int32, Integer); -impl_from!(Int32, Data); -impl_from!(Int32, Value); -impl_from!(Int32, Primitive); -impl_from!(Int32, Number); -impl_from!(Int32, Integer); +impl_deref! { Int32 for Integer } +impl_from! { Int32 for Data } +impl_from! { Int32 for Value } +impl_from! { Int32 for Primitive } +impl_from! { Int32 for Number } +impl_from! { Int32 for Integer } +impl_try_from! { Integer for Int32 if v => v.is_int32() } +impl_try_from! { Number for Int32 if v => v.is_int32() } +impl_try_from! { Primitive for Int32 if v => v.is_int32() } +impl_try_from! { Value for Int32 if v => v.is_int32() } /// A JavaScript value representing a 32-bit unsigned integer. #[repr(C)] pub struct Uint32(Opaque); - -impl_deref!(Uint32, Integer); -impl_from!(Uint32, Data); -impl_from!(Uint32, Value); -impl_from!(Uint32, Primitive); -impl_from!(Uint32, Number); -impl_from!(Uint32, Integer); +impl_deref! { Uint32 for Integer } +impl_from! { Uint32 for Data } +impl_from! { Uint32 for Value } +impl_from! { Uint32 for Primitive } +impl_from! { Uint32 for Number } +impl_from! { Uint32 for Integer } +impl_try_from! { Integer for Uint32 if v => v.is_uint32() } +impl_try_from! { Number for Uint32 if v => v.is_uint32() } +impl_try_from! { Primitive for Uint32 if v => v.is_uint32() } +impl_try_from! { Value for Uint32 if v => v.is_uint32() } diff --git a/tests/test_api.rs b/tests/test_api.rs index 7e40d798..b288acf4 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -5,7 +5,7 @@ extern crate lazy_static; use rusty_v8 as v8; use rusty_v8::{new_null, FunctionCallbackInfo, InIsolate, Local, ToLocal}; -use std::convert::Into; +use std::convert::{Into, TryInto}; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Mutex; @@ -1470,9 +1470,8 @@ fn array_buffer_view() { let source = v8::String::new(s, "new Uint8Array([23,23,23,23])").unwrap(); let mut script = v8::Script::compile(s, context, source, None).unwrap(); source.to_rust_string_lossy(s); - let result = script.run(s, context).unwrap(); - // TODO: safer casts. - let result = unsafe { Local::::cast(result) }; + let result: Local = + script.run(s, context).unwrap().try_into().unwrap(); assert_eq!(result.byte_length(), 4); assert_eq!(result.byte_offset(), 0); let mut dest = [0; 4]; @@ -1654,9 +1653,8 @@ fn uint8_array() { let source = v8::String::new(s, "new Uint8Array([23,23,23,23])").unwrap(); let mut script = v8::Script::compile(s, context, source, None).unwrap(); source.to_rust_string_lossy(s); - let result = script.run(s, context).unwrap(); - // TODO: safer casts. - let result = unsafe { Local::::cast(result) }; + let result: Local = + script.run(s, context).unwrap().try_into().unwrap(); assert_eq!(result.byte_length(), 4); assert_eq!(result.byte_offset(), 0); let mut dest = [0; 4]; @@ -1761,9 +1759,8 @@ fn shared_array_buffer() { .unwrap(); let mut script = v8::Script::compile(s, context, source, None).unwrap(); source.to_rust_string_lossy(s); - let result = script.run(s, context).unwrap(); - // TODO: safer casts. - let result = unsafe { Local::::cast(result) }; + let result: Local = + script.run(s, context).unwrap().try_into().unwrap(); assert_eq!(result.value(), 64); assert_eq!(shared_buf[2], 16); assert_eq!(shared_buf[14], 62);