Improved ObjectTemplate::set_*_handlers (#1237)

Prior to this commit, `v8::NamedPropertyHandlerConfiguration`
and `v8::IndexedPropertyHandlerConfiguration` did not expose the
`definer` hook, or `flags`.

This commit adds these options. In the process of doing this a couple of
other changes were made:

- Bitflag enum consts are now member consts of the related struct.
  This is done because PropertyHandlerFlags has conflicts with
  PropertyAttribute.
- PropertyDescriptor gets all C++ introspection methods exposed to Rust.
- NamedPropertyHandlerConfiguration callback types get rustdoc comments.
- IndexedPropertyHandlerConfiguration callback types get rustdoc
  comments.
- GenericNamedPropertySetterCallback gets a ReturnValue parameter, to
  signal trap passthrough.

Co-authored-by: Bartek Iwańczuk <biwanczuk@gmail.com>
This commit is contained in:
Luca Casonato 2023-05-26 13:14:18 +02:00 committed by GitHub
parent 43b798a39d
commit e7f96ac708
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 1141 additions and 244 deletions

View File

@ -1148,11 +1148,13 @@ void v8__ObjectTemplate__SetNamedPropertyHandler(
v8::GenericNamedPropertyQueryCallback query,
v8::GenericNamedPropertyDeleterCallback deleter,
v8::GenericNamedPropertyEnumeratorCallback enumerator,
v8::GenericNamedPropertyDefinerCallback definer,
v8::GenericNamedPropertyDescriptorCallback descriptor,
const v8::Value* data_or_null) {
const v8::Value* data_or_null,
v8::PropertyHandlerFlags flags) {
ptr_to_local(&self)->SetHandler(v8::NamedPropertyHandlerConfiguration(
getter, setter, query, deleter, enumerator, nullptr, descriptor,
ptr_to_local(data_or_null)));
getter, setter, query, deleter, enumerator, definer, descriptor,
ptr_to_local(data_or_null), flags));
}
void v8__ObjectTemplate__SetIndexedPropertyHandler(
@ -1161,11 +1163,13 @@ void v8__ObjectTemplate__SetIndexedPropertyHandler(
v8::IndexedPropertyQueryCallback query,
v8::IndexedPropertyDeleterCallback deleter,
v8::IndexedPropertyEnumeratorCallback enumerator,
v8::IndexedPropertyDefinerCallback definer,
v8::IndexedPropertyDescriptorCallback descriptor,
const v8::Value* data_or_null) {
const v8::Value* data_or_null,
v8::PropertyHandlerFlags flags) {
ptr_to_local(&self)->SetHandler(v8::IndexedPropertyHandlerConfiguration(
getter, setter, query, deleter, enumerator, nullptr, descriptor,
ptr_to_local(data_or_null)));
getter, setter, query, deleter, enumerator, definer, descriptor,
ptr_to_local(data_or_null), flags));
}
void v8__ObjectTemplate__SetAccessorProperty(const v8::ObjectTemplate& self,
@ -3357,6 +3361,60 @@ void v8__PropertyDescriptor__DESTRUCT(v8::PropertyDescriptor* self) {
self->~PropertyDescriptor();
}
bool v8__PropertyDescriptor__configurable(const v8::PropertyDescriptor* self) {
return self->configurable();
}
bool v8__PropertyDescriptor__enumerable(const v8::PropertyDescriptor* self) {
return self->enumerable();
}
bool v8__PropertyDescriptor__writable(const v8::PropertyDescriptor* self) {
return self->writable();
}
const v8::Value* v8__PropertyDescriptor__value(
const v8::PropertyDescriptor* self) {
return local_to_ptr(self->value());
}
const v8::Value* v8__PropertyDescriptor__get(
const v8::PropertyDescriptor* self) {
return local_to_ptr(self->get());
}
const v8::Value* v8__PropertyDescriptor__set(
const v8::PropertyDescriptor* self) {
return local_to_ptr(self->set());
}
bool v8__PropertyDescriptor__has_configurable(
const v8::PropertyDescriptor* self) {
return self->has_configurable();
}
bool v8__PropertyDescriptor__has_enumerable(
const v8::PropertyDescriptor* self) {
return self->has_enumerable();
}
bool v8__PropertyDescriptor__has_writable(
const v8::PropertyDescriptor* self) {
return self->has_writable();
}
bool v8__PropertyDescriptor__has_value(const v8::PropertyDescriptor* self) {
return self->has_value();
}
bool v8__PropertyDescriptor__has_get(const v8::PropertyDescriptor* self) {
return self->has_get();
}
bool v8__PropertyDescriptor__has_set(const v8::PropertyDescriptor* self) {
return self->has_set();
}
void v8__PropertyDescriptor__set_enumerable(v8::PropertyDescriptor* self,
bool enumurable) {
self->set_enumerable(enumurable);

View File

@ -1,14 +1,27 @@
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
use crate::support::intptr_t;
use crate::AccessorNameGetterCallback;
use crate::FunctionCallback;
use crate::IndexedDefinerCallback;
use crate::IndexedGetterCallback;
use crate::IndexedSetterCallback;
use crate::MessageCallback;
use crate::NamedDefinerCallback;
use crate::NamedGetterCallback;
use crate::NamedSetterCallback;
use crate::PropertyEnumeratorCallback;
use std::ffi::c_void;
#[derive(Clone, Copy)]
pub union ExternalReference<'s> {
pub function: FunctionCallback,
pub getter: AccessorNameGetterCallback<'s>,
pub named_getter: NamedGetterCallback<'s>,
pub named_setter: NamedSetterCallback<'s>,
pub named_definer: NamedDefinerCallback<'s>,
pub indexed_getter: IndexedGetterCallback<'s>,
pub indexed_setter: IndexedSetterCallback<'s>,
pub indexed_definer: IndexedDefinerCallback<'s>,
pub enumerator: PropertyEnumeratorCallback<'s>,
pub message: MessageCallback,
pub pointer: *mut c_void,
}

View File

@ -18,6 +18,7 @@ use crate::Isolate;
use crate::Local;
use crate::Name;
use crate::Object;
use crate::PropertyDescriptor;
use crate::Signature;
use crate::String;
use crate::UniqueRef;
@ -121,7 +122,7 @@ impl<'cb> ReturnValue<'cb> {
}
#[inline(always)]
fn from_property_callback_info(info: &'cb PropertyCallbackInfo) -> Self {
pub fn from_property_callback_info(info: &'cb PropertyCallbackInfo) -> Self {
let nn = info.get_return_value_non_null();
Self(nn, PhantomData)
}
@ -521,10 +522,10 @@ impl<'s> PropertyCallbackArguments<'s> {
pub type FunctionCallback = extern "C" fn(*const FunctionCallbackInfo);
impl<'a, F> MapFnFrom<F> for FunctionCallback
impl<F> MapFnFrom<F> for FunctionCallback
where
F: UnitType
+ Fn(&mut HandleScope<'a>, FunctionCallbackArguments<'a>, ReturnValue),
+ for<'s> Fn(&mut HandleScope<'s>, FunctionCallbackArguments<'s>, ReturnValue),
{
fn mapping() -> Self {
let f = |info: *const FunctionCallbackInfo| {
@ -538,15 +539,18 @@ where
}
}
/// AccessorNameGetterCallback is used as callback functions when getting a
/// particular property. See Object and ObjectTemplate's method SetAccessor.
pub type AccessorNameGetterCallback<'s> =
pub(crate) type NamedGetterCallback<'s> =
extern "C" fn(Local<'s, Name>, *const PropertyCallbackInfo);
impl<F> MapFnFrom<F> for AccessorNameGetterCallback<'_>
impl<F> MapFnFrom<F> for NamedGetterCallback<'_>
where
F: UnitType
+ Fn(&mut HandleScope, Local<Name>, PropertyCallbackArguments, ReturnValue),
+ for<'s> Fn(
&mut HandleScope<'s>,
Local<'s, Name>,
PropertyCallbackArguments<'s>,
ReturnValue,
),
{
fn mapping() -> Self {
let f = |key: Local<Name>, info: *const PropertyCallbackInfo| {
@ -560,13 +564,19 @@ where
}
}
pub type AccessorNameSetterCallback<'s> =
pub(crate) type NamedSetterCallback<'s> =
extern "C" fn(Local<'s, Name>, Local<'s, Value>, *const PropertyCallbackInfo);
impl<F> MapFnFrom<F> for AccessorNameSetterCallback<'_>
impl<F> MapFnFrom<F> for NamedSetterCallback<'_>
where
F: UnitType
+ Fn(&mut HandleScope, Local<Name>, Local<Value>, PropertyCallbackArguments),
+ for<'s> Fn(
&mut HandleScope<'s>,
Local<'s, Name>,
Local<'s, Value>,
PropertyCallbackArguments<'s>,
ReturnValue,
),
{
fn mapping() -> Self {
let f = |key: Local<Name>,
@ -575,19 +585,21 @@ where
let info = unsafe { &*info };
let scope = &mut unsafe { CallbackScope::new(info) };
let args = PropertyCallbackArguments::from_property_callback_info(info);
(F::get())(scope, key, value, args);
let rv = ReturnValue::from_property_callback_info(info);
(F::get())(scope, key, value, args, rv);
};
f.to_c_fn()
}
}
//Should return an Array in Return Value
pub type PropertyEnumeratorCallback<'s> =
// Should return an Array in Return Value
pub(crate) type PropertyEnumeratorCallback<'s> =
extern "C" fn(*const PropertyCallbackInfo);
impl<F> MapFnFrom<F> for PropertyEnumeratorCallback<'_>
where
F: UnitType + Fn(&mut HandleScope, PropertyCallbackArguments, ReturnValue),
F: UnitType
+ for<'s> Fn(&mut HandleScope<'s>, PropertyCallbackArguments<'s>, ReturnValue),
{
fn mapping() -> Self {
let f = |info: *const PropertyCallbackInfo| {
@ -601,15 +613,50 @@ where
}
}
/// IndexedPropertyGetterCallback is used as callback functions when registering a named handler
/// particular property. See Object and ObjectTemplate's method SetHandler.
pub type IndexedPropertyGetterCallback<'s> =
extern "C" fn(u32, *const PropertyCallbackInfo);
pub(crate) type NamedDefinerCallback<'s> = extern "C" fn(
Local<'s, Name>,
*const PropertyDescriptor,
*const PropertyCallbackInfo,
);
impl<F> MapFnFrom<F> for IndexedPropertyGetterCallback<'_>
impl<F> MapFnFrom<F> for NamedDefinerCallback<'_>
where
F: UnitType
+ Fn(&mut HandleScope, u32, PropertyCallbackArguments, ReturnValue),
+ for<'s> Fn(
&mut HandleScope<'s>,
Local<'s, Name>,
&PropertyDescriptor,
PropertyCallbackArguments<'s>,
ReturnValue,
),
{
fn mapping() -> Self {
let f = |key: Local<Name>,
desc: *const PropertyDescriptor,
info: *const PropertyCallbackInfo| {
let info = unsafe { &*info };
let scope = &mut unsafe { CallbackScope::new(info) };
let args = PropertyCallbackArguments::from_property_callback_info(info);
let desc = unsafe { &*desc };
let rv = ReturnValue::from_property_callback_info(info);
(F::get())(scope, key, desc, args, rv);
};
f.to_c_fn()
}
}
pub(crate) type IndexedGetterCallback<'s> =
extern "C" fn(u32, *const PropertyCallbackInfo);
impl<F> MapFnFrom<F> for IndexedGetterCallback<'_>
where
F: UnitType
+ for<'s> Fn(
&mut HandleScope<'s>,
u32,
PropertyCallbackArguments<'s>,
ReturnValue,
),
{
fn mapping() -> Self {
let f = |index: u32, info: *const PropertyCallbackInfo| {
@ -623,13 +670,19 @@ where
}
}
pub type IndexedPropertySetterCallback<'s> =
pub(crate) type IndexedSetterCallback<'s> =
extern "C" fn(u32, Local<'s, Value>, *const PropertyCallbackInfo);
impl<F> MapFnFrom<F> for IndexedPropertySetterCallback<'_>
impl<F> MapFnFrom<F> for IndexedSetterCallback<'_>
where
F: UnitType
+ Fn(&mut HandleScope, u32, Local<Value>, PropertyCallbackArguments),
+ for<'s> Fn(
&mut HandleScope<'s>,
u32,
Local<'s, Value>,
PropertyCallbackArguments<'s>,
ReturnValue,
),
{
fn mapping() -> Self {
let f =
@ -637,12 +690,42 @@ where
let info = unsafe { &*info };
let scope = &mut unsafe { CallbackScope::new(info) };
let args = PropertyCallbackArguments::from_property_callback_info(info);
(F::get())(scope, index, value, args);
let rv = ReturnValue::from_property_callback_info(info);
(F::get())(scope, index, value, args, rv);
};
f.to_c_fn()
}
}
pub(crate) type IndexedDefinerCallback<'s> =
extern "C" fn(u32, *const PropertyDescriptor, *const PropertyCallbackInfo);
impl<F> MapFnFrom<F> for IndexedDefinerCallback<'_>
where
F: UnitType
+ for<'s> Fn(
&mut HandleScope<'s>,
u32,
&PropertyDescriptor,
PropertyCallbackArguments<'s>,
ReturnValue,
),
{
fn mapping() -> Self {
let f = |index: u32,
desc: *const PropertyDescriptor,
info: *const PropertyCallbackInfo| {
let info = unsafe { &*info };
let scope = &mut unsafe { CallbackScope::new(info) };
let args = PropertyCallbackArguments::from_property_callback_info(info);
let rv = ReturnValue::from_property_callback_info(info);
let desc = unsafe { &*desc };
(F::get())(scope, index, desc, args, rv);
};
f.to_c_fn()
}
}
/// A builder to construct the properties of a Function or FunctionTemplate.
pub struct FunctionBuilder<'s, T> {
pub(crate) callback: FunctionCallback,

View File

@ -7,17 +7,19 @@
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub struct GCType(u32);
pub const GC_TYPE_TYPE_SCAVENGE: GCType = GCType(1);
impl GCType {
pub const SCAVENGE: Self = Self(1 << 0);
pub const GC_TYPE_MINOR_MARK_COMPACT: GCType = GCType(2);
pub const MINOR_MARK_COMPACT: Self = Self(1 << 1);
pub const GC_TYPE_MARK_SWEEP_COMPACT: GCType = GCType(4);
pub const MARK_SWEEP_COMPACT: Self = Self(1 << 2);
pub const GC_TYPE_INCREMENTAL_MARKING: GCType = GCType(8);
pub const INCREMENTAL_MARKING: Self = Self(1 << 3);
pub const GC_TYPE_PROCESS_WEAK_CALLBACK: GCType = GCType(16);
pub const PROCESS_WEAK_CALLBACKS: Self = Self(1 << 4);
pub const GC_TYPE_ALL: GCType = GCType(31);
pub const ALL: Self = Self(31);
}
impl std::ops::BitOr for GCType {
type Output = Self;
@ -44,24 +46,21 @@ impl std::ops::BitOr for GCType {
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub struct GCCallbackFlags(u32);
pub const GC_CALLBACK_FLAGS_NO_FLAGS: GCCallbackFlags = GCCallbackFlags(0);
impl GCCallbackFlags {
pub const NONE: Self = Self(0);
pub const GC_CALLBACK_FLAGS_CONSTRUCT_RETAINED_OBJECT_INFOS: GCCallbackFlags =
GCCallbackFlags(2);
pub const CONSTRUCT_RETAINED_OBJECT_INFOS: Self = Self(1 << 1);
pub const GC_CALLBACK_FLAGS_FORCED: GCCallbackFlags = GCCallbackFlags(4);
pub const FORCED: Self = Self(1 << 2);
pub const GC_CALLBACK_FLAGS_SYNCHRONOUS_PHANTOM_CALLBACK_PROCESSING:
GCCallbackFlags = GCCallbackFlags(8);
pub const SYNCHRONOUS_PHANTOM_CALLBACK_PROCESSING: Self = Self(1 << 3);
pub const GC_CALLBACK_FLAGS_COLLECT_ALL_AVAILABLE_GARBAGE: GCCallbackFlags =
GCCallbackFlags(16);
pub const COLLECT_ALL_AVAILABLE_GARBAGE: Self = Self(1 << 4);
pub const GC_CALLBACK_FLAGS_COLLECT_ALL_EXTERNAL_MEMORY: GCCallbackFlags =
GCCallbackFlags(32);
pub const COLLECT_ALL_EXTERNAL_MEMORY: Self = Self(1 << 5);
pub const GC_CALLBACK_FLAGS_SCHEDULE_IDLE_GARBAGE_COLLECTION: GCCallbackFlags =
GCCallbackFlags(64);
pub const SCHEDULE_IDLE_GARBAGE_COLLECTION: Self = Self(1 << 6);
}
impl std::ops::BitOr for GCCallbackFlags {
type Output = Self;

View File

@ -1,6 +1,4 @@
use crate::PropertyFilter;
use crate::ONLY_ENUMERABLE;
use crate::SKIP_SYMBOLS;
#[derive(Debug, Clone, Copy)]
#[repr(C)]
@ -47,7 +45,8 @@ impl Default for GetPropertyNamesArgs {
fn default() -> Self {
GetPropertyNamesArgs {
mode: KeyCollectionMode::IncludePrototypes,
property_filter: ONLY_ENUMERABLE | SKIP_SYMBOLS,
property_filter: PropertyFilter::ONLY_ENUMERABLE
| PropertyFilter::SKIP_SYMBOLS,
index_filter: IndexFilter::IncludeIndices,
key_conversion: KeyConversionMode::KeepNumbers,
}
@ -72,7 +71,8 @@ impl GetPropertyNamesArgsBuilder {
pub fn new() -> Self {
Self {
mode: KeyCollectionMode::IncludePrototypes,
property_filter: ONLY_ENUMERABLE | SKIP_SYMBOLS,
property_filter: PropertyFilter::ONLY_ENUMERABLE
| PropertyFilter::SKIP_SYMBOLS,
index_filter: IndexFilter::IncludeIndices,
key_conversion: KeyConversionMode::KeepNumbers,
}

View File

@ -57,6 +57,7 @@ mod promise;
mod property_attribute;
mod property_descriptor;
mod property_filter;
mod property_handler_flags;
mod proxy;
mod scope;
mod script;
@ -126,6 +127,7 @@ pub use promise::{PromiseRejectEvent, PromiseRejectMessage, PromiseState};
pub use property_attribute::*;
pub use property_descriptor::*;
pub use property_filter::*;
pub use property_handler_flags::*;
pub use proxy::*;
pub use scope::CallbackScope;
pub use scope::ContextScope;

View File

@ -2,44 +2,44 @@
#[derive(Debug, Eq, PartialEq)]
pub struct PropertyAttribute(u32);
/// No property attributes.
pub const NONE: PropertyAttribute = PropertyAttribute(0);
/// Not writable. Corresponds to
/// `Object.defineProperty(o, "p", { writable: false })`.
pub const READ_ONLY: PropertyAttribute = PropertyAttribute(1);
/// Not enumerable. Corresponds to
/// `Object.defineProperty(o, "p", { enumerable: false })`.
pub const DONT_ENUM: PropertyAttribute = PropertyAttribute(2);
/// Not configurable. Corresponds to
/// `Object.defineProperty(o, "p", { configurable: false })`.
pub const DONT_DELETE: PropertyAttribute = PropertyAttribute(4);
impl PropertyAttribute {
/// No property attributes.
pub const NONE: Self = Self(0);
/// Not writable. Corresponds to
/// `Object.defineProperty(o, "p", { writable: false })`.
pub const READ_ONLY: Self = Self(1 << 0);
/// Not enumerable. Corresponds to
/// `Object.defineProperty(o, "p", { enumerable: false })`.
pub const DONT_ENUM: Self = Self(1 << 1);
/// Not configurable. Corresponds to
/// `Object.defineProperty(o, "p", { configurable: false })`.
pub const DONT_DELETE: Self = Self(1 << 2);
/// Test if no property attributes are set.
#[inline(always)]
pub fn is_none(&self) -> bool {
*self == NONE
*self == PropertyAttribute::NONE
}
/// Test if the read-only property attribute is set.
#[inline(always)]
pub fn is_read_only(&self) -> bool {
self.has(READ_ONLY)
self.has(Self::READ_ONLY)
}
/// Test if the non-enumerable property attribute is set.
#[inline(always)]
pub fn is_dont_enum(&self) -> bool {
self.has(DONT_ENUM)
self.has(Self::DONT_ENUM)
}
/// Test if the non-configurable property attribute is set.
#[inline(always)]
pub fn is_dont_delete(&self) -> bool {
self.has(DONT_DELETE)
self.has(Self::DONT_DELETE)
}
#[inline(always)]
@ -58,7 +58,7 @@ impl PropertyAttribute {
// Identical to #[derive(Default)] but arguably clearer when made explicit.
impl Default for PropertyAttribute {
fn default() -> Self {
NONE
Self::NONE
}
}
@ -73,36 +73,41 @@ impl std::ops::BitOr for PropertyAttribute {
#[test]
fn test_attr() {
assert!(NONE.is_none());
assert!(!NONE.is_read_only());
assert!(!NONE.is_dont_enum());
assert!(!NONE.is_dont_delete());
assert!(PropertyAttribute::NONE.is_none());
assert!(!PropertyAttribute::NONE.is_read_only());
assert!(!PropertyAttribute::NONE.is_dont_enum());
assert!(!PropertyAttribute::NONE.is_dont_delete());
assert!(!READ_ONLY.is_none());
assert!(READ_ONLY.is_read_only());
assert!(!READ_ONLY.is_dont_enum());
assert!(!READ_ONLY.is_dont_delete());
assert!(!PropertyAttribute::READ_ONLY.is_none());
assert!(PropertyAttribute::READ_ONLY.is_read_only());
assert!(!PropertyAttribute::READ_ONLY.is_dont_enum());
assert!(!PropertyAttribute::READ_ONLY.is_dont_delete());
assert!(!DONT_ENUM.is_none());
assert!(!DONT_ENUM.is_read_only());
assert!(DONT_ENUM.is_dont_enum());
assert!(!DONT_ENUM.is_dont_delete());
assert!(!PropertyAttribute::DONT_ENUM.is_none());
assert!(!PropertyAttribute::DONT_ENUM.is_read_only());
assert!(PropertyAttribute::DONT_ENUM.is_dont_enum());
assert!(!PropertyAttribute::DONT_ENUM.is_dont_delete());
assert!(!DONT_DELETE.is_none());
assert!(!DONT_DELETE.is_read_only());
assert!(!DONT_DELETE.is_dont_enum());
assert!(DONT_DELETE.is_dont_delete());
assert!(!PropertyAttribute::DONT_DELETE.is_none());
assert!(!PropertyAttribute::DONT_DELETE.is_read_only());
assert!(!PropertyAttribute::DONT_DELETE.is_dont_enum());
assert!(PropertyAttribute::DONT_DELETE.is_dont_delete());
assert_eq!(NONE, Default::default());
assert_eq!(READ_ONLY, NONE | READ_ONLY);
assert_eq!(PropertyAttribute::NONE, Default::default());
assert_eq!(
PropertyAttribute::READ_ONLY,
PropertyAttribute::NONE | PropertyAttribute::READ_ONLY
);
let attr = READ_ONLY | DONT_ENUM;
let attr = PropertyAttribute::READ_ONLY | PropertyAttribute::DONT_ENUM;
assert!(!attr.is_none());
assert!(attr.is_read_only());
assert!(attr.is_dont_enum());
assert!(!attr.is_dont_delete());
let attr = READ_ONLY | READ_ONLY | DONT_ENUM;
let attr = PropertyAttribute::READ_ONLY
| PropertyAttribute::READ_ONLY
| PropertyAttribute::DONT_ENUM;
assert!(!attr.is_none());
assert!(attr.is_read_only());
assert!(attr.is_dont_enum());

View File

@ -21,6 +21,35 @@ extern "C" {
set: *const Value,
);
fn v8__PropertyDescriptor__DESTRUCT(this: *mut PropertyDescriptor);
fn v8__PropertyDescriptor__configurable(
this: *const PropertyDescriptor,
) -> bool;
fn v8__PropertyDescriptor__enumerable(
this: *const PropertyDescriptor,
) -> bool;
fn v8__PropertyDescriptor__writable(this: *const PropertyDescriptor) -> bool;
fn v8__PropertyDescriptor__value(
this: *const PropertyDescriptor,
) -> *const Value;
fn v8__PropertyDescriptor__get(
this: *const PropertyDescriptor,
) -> *const Value;
fn v8__PropertyDescriptor__set(
this: *const PropertyDescriptor,
) -> *const Value;
fn v8__PropertyDescriptor__has_configurable(
this: *const PropertyDescriptor,
) -> bool;
fn v8__PropertyDescriptor__has_enumerable(
this: *const PropertyDescriptor,
) -> bool;
fn v8__PropertyDescriptor__has_writable(
this: *const PropertyDescriptor,
) -> bool;
fn v8__PropertyDescriptor__has_value(this: *const PropertyDescriptor)
-> bool;
fn v8__PropertyDescriptor__has_get(this: *const PropertyDescriptor) -> bool;
fn v8__PropertyDescriptor__has_set(this: *const PropertyDescriptor) -> bool;
fn v8__PropertyDescriptor__set_enumerable(
this: *mut PropertyDescriptor,
enumerable: bool,
@ -88,6 +117,54 @@ impl PropertyDescriptor {
}
}
pub fn configurable(&self) -> bool {
unsafe { v8__PropertyDescriptor__configurable(self) }
}
pub fn enumerable(&self) -> bool {
unsafe { v8__PropertyDescriptor__enumerable(self) }
}
pub fn writable(&self) -> bool {
unsafe { v8__PropertyDescriptor__writable(self) }
}
pub fn value(&self) -> Local<Value> {
unsafe { Local::from_raw(v8__PropertyDescriptor__value(self)) }.unwrap()
}
pub fn get(&self) -> Local<Value> {
unsafe { Local::from_raw(v8__PropertyDescriptor__get(self)) }.unwrap()
}
pub fn set(&self) -> Local<Value> {
unsafe { Local::from_raw(v8__PropertyDescriptor__set(self)) }.unwrap()
}
pub fn has_configurable(&self) -> bool {
unsafe { v8__PropertyDescriptor__has_configurable(self) }
}
pub fn has_enumerable(&self) -> bool {
unsafe { v8__PropertyDescriptor__has_enumerable(self) }
}
pub fn has_writable(&self) -> bool {
unsafe { v8__PropertyDescriptor__has_writable(self) }
}
pub fn has_value(&self) -> bool {
unsafe { v8__PropertyDescriptor__has_value(self) }
}
pub fn has_get(&self) -> bool {
unsafe { v8__PropertyDescriptor__has_get(self) }
}
pub fn has_set(&self) -> bool {
unsafe { v8__PropertyDescriptor__has_set(self) }
}
pub fn set_enumerable(&mut self, enumerable: bool) {
unsafe { v8__PropertyDescriptor__set_enumerable(self, enumerable) }
}

View File

@ -2,53 +2,53 @@
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
pub struct PropertyFilter(u32);
pub const ALL_PROPERTIES: PropertyFilter = PropertyFilter(0);
pub const ONLY_WRITABLE: PropertyFilter = PropertyFilter(1);
pub const ONLY_ENUMERABLE: PropertyFilter = PropertyFilter(2);
pub const ONLY_CONFIGURABLE: PropertyFilter = PropertyFilter(4);
pub const SKIP_STRINGS: PropertyFilter = PropertyFilter(8);
pub const SKIP_SYMBOLS: PropertyFilter = PropertyFilter(16);
impl PropertyFilter {
pub const ALL_PROPERTIES: PropertyFilter = PropertyFilter(0);
pub const ONLY_WRITABLE: PropertyFilter = PropertyFilter(1 << 0);
pub const ONLY_ENUMERABLE: PropertyFilter = PropertyFilter(1 << 1);
pub const ONLY_CONFIGURABLE: PropertyFilter = PropertyFilter(1 << 2);
pub const SKIP_STRINGS: PropertyFilter = PropertyFilter(1 << 3);
pub const SKIP_SYMBOLS: PropertyFilter = PropertyFilter(1 << 4);
/// Test if all property filters are set.
#[inline(always)]
pub fn is_all_properties(&self) -> bool {
*self == ALL_PROPERTIES
*self == Self::ALL_PROPERTIES
}
/// Test if the only-writable property filter is set.
#[inline(always)]
pub fn is_only_writable(&self) -> bool {
self.has(ONLY_WRITABLE)
self.has(Self::ONLY_WRITABLE)
}
/// Test if the only-enumerable property filter is set.
#[inline(always)]
pub fn is_only_enumerable(&self) -> bool {
self.has(ONLY_ENUMERABLE)
self.has(Self::ONLY_ENUMERABLE)
}
/// Test if the only-configurable property filter is set.
#[inline(always)]
pub fn is_only_configurable(&self) -> bool {
self.has(ONLY_CONFIGURABLE)
self.has(Self::ONLY_CONFIGURABLE)
}
/// Test if the skip-strings property filter is set.
#[inline(always)]
pub fn is_skip_strings(&self) -> bool {
self.has(SKIP_STRINGS)
self.has(Self::SKIP_STRINGS)
}
/// Test if the skip-symbols property filter is set.
#[inline(always)]
pub fn is_skip_symbols(&self) -> bool {
self.has(SKIP_SYMBOLS)
self.has(Self::SKIP_SYMBOLS)
}
#[inline(always)]
@ -62,7 +62,7 @@ impl PropertyFilter {
// Identical to #[derive(Default)] but arguably clearer when made explicit.
impl Default for PropertyFilter {
fn default() -> Self {
ALL_PROPERTIES
Self::ALL_PROPERTIES
}
}
@ -77,52 +77,57 @@ impl std::ops::BitOr for PropertyFilter {
#[test]
fn test_attr() {
assert!(ALL_PROPERTIES.is_all_properties());
assert!(!ALL_PROPERTIES.is_only_writable());
assert!(!ALL_PROPERTIES.is_only_enumerable());
assert!(!ALL_PROPERTIES.is_only_configurable());
assert!(!ALL_PROPERTIES.is_skip_strings());
assert!(!ALL_PROPERTIES.is_skip_symbols());
assert!(PropertyFilter::ALL_PROPERTIES.is_all_properties());
assert!(!PropertyFilter::ALL_PROPERTIES.is_only_writable());
assert!(!PropertyFilter::ALL_PROPERTIES.is_only_enumerable());
assert!(!PropertyFilter::ALL_PROPERTIES.is_only_configurable());
assert!(!PropertyFilter::ALL_PROPERTIES.is_skip_strings());
assert!(!PropertyFilter::ALL_PROPERTIES.is_skip_symbols());
assert!(!ONLY_WRITABLE.is_all_properties());
assert!(ONLY_WRITABLE.is_only_writable());
assert!(!ONLY_WRITABLE.is_only_enumerable());
assert!(!ONLY_WRITABLE.is_only_configurable());
assert!(!ONLY_WRITABLE.is_skip_strings());
assert!(!ONLY_WRITABLE.is_skip_symbols());
assert!(!PropertyFilter::ONLY_WRITABLE.is_all_properties());
assert!(PropertyFilter::ONLY_WRITABLE.is_only_writable());
assert!(!PropertyFilter::ONLY_WRITABLE.is_only_enumerable());
assert!(!PropertyFilter::ONLY_WRITABLE.is_only_configurable());
assert!(!PropertyFilter::ONLY_WRITABLE.is_skip_strings());
assert!(!PropertyFilter::ONLY_WRITABLE.is_skip_symbols());
assert!(!ONLY_ENUMERABLE.is_all_properties());
assert!(!ONLY_ENUMERABLE.is_only_writable());
assert!(ONLY_ENUMERABLE.is_only_enumerable());
assert!(!ONLY_ENUMERABLE.is_only_configurable());
assert!(!ONLY_ENUMERABLE.is_skip_strings());
assert!(!ONLY_ENUMERABLE.is_skip_symbols());
assert!(!PropertyFilter::ONLY_ENUMERABLE.is_all_properties());
assert!(!PropertyFilter::ONLY_ENUMERABLE.is_only_writable());
assert!(PropertyFilter::ONLY_ENUMERABLE.is_only_enumerable());
assert!(!PropertyFilter::ONLY_ENUMERABLE.is_only_configurable());
assert!(!PropertyFilter::ONLY_ENUMERABLE.is_skip_strings());
assert!(!PropertyFilter::ONLY_ENUMERABLE.is_skip_symbols());
assert!(!ONLY_CONFIGURABLE.is_all_properties());
assert!(!ONLY_CONFIGURABLE.is_only_writable());
assert!(!ONLY_CONFIGURABLE.is_only_enumerable());
assert!(ONLY_CONFIGURABLE.is_only_configurable());
assert!(!ONLY_CONFIGURABLE.is_skip_strings());
assert!(!ONLY_CONFIGURABLE.is_skip_symbols());
assert!(!PropertyFilter::ONLY_CONFIGURABLE.is_all_properties());
assert!(!PropertyFilter::ONLY_CONFIGURABLE.is_only_writable());
assert!(!PropertyFilter::ONLY_CONFIGURABLE.is_only_enumerable());
assert!(PropertyFilter::ONLY_CONFIGURABLE.is_only_configurable());
assert!(!PropertyFilter::ONLY_CONFIGURABLE.is_skip_strings());
assert!(!PropertyFilter::ONLY_CONFIGURABLE.is_skip_symbols());
assert!(!SKIP_STRINGS.is_all_properties());
assert!(!SKIP_STRINGS.is_only_writable());
assert!(!SKIP_STRINGS.is_only_enumerable());
assert!(!SKIP_STRINGS.is_only_configurable());
assert!(SKIP_STRINGS.is_skip_strings());
assert!(!SKIP_STRINGS.is_skip_symbols());
assert!(!PropertyFilter::SKIP_STRINGS.is_all_properties());
assert!(!PropertyFilter::SKIP_STRINGS.is_only_writable());
assert!(!PropertyFilter::SKIP_STRINGS.is_only_enumerable());
assert!(!PropertyFilter::SKIP_STRINGS.is_only_configurable());
assert!(PropertyFilter::SKIP_STRINGS.is_skip_strings());
assert!(!PropertyFilter::SKIP_STRINGS.is_skip_symbols());
assert!(!SKIP_SYMBOLS.is_all_properties());
assert!(!SKIP_SYMBOLS.is_only_writable());
assert!(!SKIP_SYMBOLS.is_only_enumerable());
assert!(!SKIP_SYMBOLS.is_only_configurable());
assert!(!SKIP_SYMBOLS.is_skip_strings());
assert!(SKIP_SYMBOLS.is_skip_symbols());
assert!(!PropertyFilter::SKIP_SYMBOLS.is_all_properties());
assert!(!PropertyFilter::SKIP_SYMBOLS.is_only_writable());
assert!(!PropertyFilter::SKIP_SYMBOLS.is_only_enumerable());
assert!(!PropertyFilter::SKIP_SYMBOLS.is_only_configurable());
assert!(!PropertyFilter::SKIP_SYMBOLS.is_skip_strings());
assert!(PropertyFilter::SKIP_SYMBOLS.is_skip_symbols());
assert_eq!(ALL_PROPERTIES, Default::default());
assert_eq!(ONLY_WRITABLE, ALL_PROPERTIES | ONLY_WRITABLE);
assert_eq!(PropertyFilter::ALL_PROPERTIES, Default::default());
assert_eq!(
PropertyFilter::ONLY_WRITABLE,
PropertyFilter::ALL_PROPERTIES | PropertyFilter::ONLY_WRITABLE
);
let attr = ONLY_WRITABLE | ONLY_WRITABLE | SKIP_STRINGS;
let attr = PropertyFilter::ONLY_WRITABLE
| PropertyFilter::ONLY_WRITABLE
| PropertyFilter::SKIP_STRINGS;
assert!(!attr.is_all_properties());
assert!(attr.is_only_writable());
assert!(!attr.is_only_enumerable());

View File

@ -0,0 +1,136 @@
// Copyright 2019-2021 the Deno authors. All rights reserved. MIT license.
#[repr(C)]
#[derive(Debug, Eq, PartialEq)]
pub struct PropertyHandlerFlags(u32);
impl PropertyHandlerFlags {
/// None.
pub const NONE: Self = Self(0);
/// See ALL_CAN_READ above.
pub const ALL_CAN_READ: Self = Self(1 << 0);
/// Will not call into interceptor for properties on the receiver or prototype
/// chain, i.e., only call into interceptor for properties that do not exist.
/// Currently only valid for named interceptors.
pub const NON_MASKING: Self = Self(1 << 1);
/// Will not call into interceptor for symbol lookup. Only meaningful for
/// named interceptors.
pub const ONLY_INTERCEPT_STRINGS: Self = Self(1 << 2);
/// The getter, query, enumerator callbacks do not produce side effects.
pub const HAS_NO_SIDE_EFFECT: Self = Self(1 << 3);
/// Test if no property handler flags are set.
#[inline(always)]
pub fn is_none(&self) -> bool {
*self == Self::NONE
}
/// Test if the all-can-read property handler flag is set.
#[inline(always)]
pub fn is_all_can_read(&self) -> bool {
self.has(Self::ALL_CAN_READ)
}
/// Test if the non-masking property handler flag is set.
#[inline(always)]
pub fn is_non_masking(&self) -> bool {
self.has(Self::NON_MASKING)
}
/// Test if the only-intercept-strings property handler flag is set.
#[inline(always)]
pub fn is_only_intercept_strings(&self) -> bool {
self.has(Self::ONLY_INTERCEPT_STRINGS)
}
/// Test if the has-no-side-effect property handler flag is set.
#[inline(always)]
pub fn is_has_no_side_effect(&self) -> bool {
self.has(Self::HAS_NO_SIDE_EFFECT)
}
#[inline(always)]
fn has(&self, that: Self) -> bool {
let Self(lhs) = self;
let Self(rhs) = that;
0 != lhs & rhs
}
}
// Identical to #[derive(Default)] but arguably clearer when made explicit.
impl Default for PropertyHandlerFlags {
fn default() -> Self {
Self::NONE
}
}
impl std::ops::BitOr for PropertyHandlerFlags {
type Output = Self;
fn bitor(self, Self(rhs): Self) -> Self {
let Self(lhs) = self;
Self(lhs | rhs)
}
}
#[test]
fn test_attr() {
assert!(PropertyHandlerFlags::NONE.is_none());
assert!(!PropertyHandlerFlags::NONE.is_all_can_read());
assert!(!PropertyHandlerFlags::NONE.is_non_masking());
assert!(!PropertyHandlerFlags::NONE.is_only_intercept_strings());
assert!(!PropertyHandlerFlags::NONE.is_has_no_side_effect());
assert!(!PropertyHandlerFlags::ALL_CAN_READ.is_none());
assert!(PropertyHandlerFlags::ALL_CAN_READ.is_all_can_read());
assert!(!PropertyHandlerFlags::ALL_CAN_READ.is_non_masking());
assert!(!PropertyHandlerFlags::ALL_CAN_READ.is_only_intercept_strings());
assert!(!PropertyHandlerFlags::ALL_CAN_READ.is_has_no_side_effect());
assert!(!PropertyHandlerFlags::NON_MASKING.is_none());
assert!(!PropertyHandlerFlags::NON_MASKING.is_all_can_read());
assert!(PropertyHandlerFlags::NON_MASKING.is_non_masking());
assert!(!PropertyHandlerFlags::NON_MASKING.is_only_intercept_strings());
assert!(!PropertyHandlerFlags::NON_MASKING.is_has_no_side_effect());
assert!(!PropertyHandlerFlags::ONLY_INTERCEPT_STRINGS.is_none());
assert!(!PropertyHandlerFlags::ONLY_INTERCEPT_STRINGS.is_all_can_read());
assert!(!PropertyHandlerFlags::ONLY_INTERCEPT_STRINGS.is_non_masking());
assert!(
PropertyHandlerFlags::ONLY_INTERCEPT_STRINGS.is_only_intercept_strings()
);
assert!(!PropertyHandlerFlags::ONLY_INTERCEPT_STRINGS.is_has_no_side_effect());
assert!(!PropertyHandlerFlags::HAS_NO_SIDE_EFFECT.is_none());
assert!(!PropertyHandlerFlags::HAS_NO_SIDE_EFFECT.is_all_can_read());
assert!(!PropertyHandlerFlags::HAS_NO_SIDE_EFFECT.is_non_masking());
assert!(!PropertyHandlerFlags::HAS_NO_SIDE_EFFECT.is_only_intercept_strings());
assert!(PropertyHandlerFlags::HAS_NO_SIDE_EFFECT.is_has_no_side_effect());
assert_eq!(PropertyHandlerFlags::NONE, Default::default());
assert_eq!(
PropertyHandlerFlags::ALL_CAN_READ,
PropertyHandlerFlags::NONE | PropertyHandlerFlags::ALL_CAN_READ
);
let attr =
PropertyHandlerFlags::ALL_CAN_READ | PropertyHandlerFlags::NON_MASKING;
assert!(!attr.is_none());
assert!(attr.is_all_can_read());
assert!(attr.is_non_masking());
assert!(!attr.is_only_intercept_strings());
assert!(!attr.is_has_no_side_effect());
let attr = PropertyHandlerFlags::ONLY_INTERCEPT_STRINGS
| PropertyHandlerFlags::HAS_NO_SIDE_EFFECT
| PropertyHandlerFlags::NON_MASKING;
assert!(!attr.is_none());
assert!(!attr.is_all_can_read());
assert!(attr.is_non_masking());
assert!(attr.is_only_intercept_strings());
assert!(attr.is_has_no_side_effect());
}

View File

@ -9,25 +9,27 @@ use crate::fast_api::FastFunction;
use crate::isolate::Isolate;
use crate::support::int;
use crate::support::MapFnTo;
use crate::AccessorNameGetterCallback;
use crate::AccessorNameSetterCallback;
use crate::ConstructorBehavior;
use crate::Context;
use crate::Function;
use crate::FunctionBuilder;
use crate::FunctionCallback;
use crate::HandleScope;
use crate::IndexedPropertyGetterCallback;
use crate::IndexedPropertySetterCallback;
use crate::IndexedDefinerCallback;
use crate::IndexedGetterCallback;
use crate::IndexedSetterCallback;
use crate::Local;
use crate::NamedDefinerCallback;
use crate::NamedGetterCallback;
use crate::NamedSetterCallback;
use crate::Object;
use crate::PropertyAttribute;
use crate::PropertyEnumeratorCallback;
use crate::PropertyHandlerFlags;
use crate::SideEffectType;
use crate::Signature;
use crate::String;
use crate::Value;
use crate::NONE;
use std::convert::TryFrom;
use std::ffi::c_void;
use std::ptr::null;
@ -110,29 +112,143 @@ extern "C" {
fn v8__ObjectTemplate__SetNamedPropertyHandler(
this: *const ObjectTemplate,
getter: Option<AccessorNameGetterCallback>,
setter: Option<AccessorNameSetterCallback>,
query: Option<AccessorNameGetterCallback>,
deleter: Option<AccessorNameGetterCallback>,
enumerator: Option<PropertyEnumeratorCallback>,
descriptor: Option<AccessorNameGetterCallback>,
getter: Option<GenericNamedPropertyGetterCallback>,
setter: Option<GenericNamedPropertySetterCallback>,
query: Option<GenericNamedPropertyQueryCallback>,
deleter: Option<GenericNamedPropertyDeleterCallback>,
enumerator: Option<GenericNamedPropertyEnumeratorCallback>,
definer: Option<GenericNamedPropertyDefinerCallback>,
descriptor: Option<GenericNamedPropertyDescriptorCallback>,
data_or_null: *const Value,
flags: PropertyHandlerFlags,
);
fn v8__ObjectTemplate__SetIndexedPropertyHandler(
this: *const ObjectTemplate,
getter: Option<IndexedPropertyGetterCallback>,
setter: Option<IndexedPropertySetterCallback>,
query: Option<IndexedPropertyGetterCallback>,
deleter: Option<IndexedPropertyGetterCallback>,
enumerator: Option<PropertyEnumeratorCallback>,
descriptor: Option<IndexedPropertyGetterCallback>,
query: Option<IndexedPropertyQueryCallback>,
deleter: Option<IndexedPropertyDeleterCallback>,
enumerator: Option<IndexedPropertyEnumeratorCallback>,
definer: Option<IndexedPropertyDefinerCallback>,
descriptor: Option<IndexedPropertyDescriptorCallback>,
data_or_null: *const Value,
);
fn v8__ObjectTemplate__SetImmutableProto(this: *const ObjectTemplate);
}
pub type AccessorNameGetterCallback<'s> = NamedGetterCallback<'s>;
/// Note: [ReturnValue] is ignored for accessors.
pub type AccessorNameSetterCallback<'s> = NamedSetterCallback<'s>;
/// Interceptor for get requests on an object.
///
/// Use [ReturnValue] to set the return value of the intercepted get request. If
/// the property does not exist the callback should not set the result and must
/// not produce side effects.
///
/// See also [ObjectTemplate::set_handler].
pub type GenericNamedPropertyGetterCallback<'s> = NamedGetterCallback<'s>;
/// Interceptor for set requests on an object.
///
/// Use [ReturnValue] to indicate whether the request was intercepted or not. If
/// the setter successfully intercepts the request, i.e., if the request should
/// not be further executed, call [ReturnValue::set]. If the setter did not
/// intercept the request, i.e., if the request should be handled as if no
/// interceptor is present, do not not call set() and do not produce side
/// effects.
///
/// See also [ObjectTemplate::set_named_property_handler].
pub type GenericNamedPropertySetterCallback<'s> = NamedSetterCallback<'s>;
/// Intercepts all requests that query the attributes of the property, e.g.,
/// getOwnPropertyDescriptor(), propertyIsEnumerable(), and defineProperty().
///
/// Use [ReturnValue::set] to set the property attributes. The value is an
/// integer encoding a [PropertyAttribute]. If the property does not exist the
/// callback should not set the result and must not produce side effects.
///
/// Note: Some functions query the property attributes internally, even though
/// they do not return the attributes. For example, hasOwnProperty() can trigger
/// this interceptor depending on the state of the object.
///
/// See also [ObjectTemplate::set_named_property_handler].
pub type GenericNamedPropertyQueryCallback<'s> = NamedGetterCallback<'s>;
/// Interceptor for delete requests on an object.
///
/// Use [ReturnValue] to indicate whether the request was intercepted or not. If
/// the deleter successfully intercepts the request, i.e., if the request should
/// not be further executed, call [ReturnValue::set] with a boolean value. The
/// value is used as the return value of delete. If the deleter does not
/// intercept the request then it should not set the result and must not produce
/// side effects.
///
/// Note: If you need to mimic the behavior of delete, i.e., throw in strict
/// mode instead of returning false, use
/// [PropertyCallbackArguments::should_throw_on_error] to determine if you are
/// in strict mode.
///
/// See also [ObjectTemplate::set_named_property_handler].
pub type GenericNamedPropertyDeleterCallback<'s> = NamedGetterCallback<'s>;
/// Returns an array containing the names of the properties the named property getter intercepts.
///
/// Note: The values in the array must be of type v8::Name.
///
/// See also [ObjectTemplate::set_named_property_handler].
pub type GenericNamedPropertyEnumeratorCallback<'s> =
PropertyEnumeratorCallback<'s>;
/// Interceptor for defineProperty requests on an object.
///
/// Use [ReturnValue] to indicate whether the request was intercepted or not. If
/// the definer successfully intercepts the request, i.e., if the request should
/// not be further executed, call [ReturnValue::set]. If the definer did not
/// intercept the request, i.e., if the request should be handled as if no
/// interceptor is present, do not not call set() and do not produce side
/// effects.
///
/// See also [ObjectTemplate::set_named_property_handler].
pub type GenericNamedPropertyDefinerCallback<'s> = NamedDefinerCallback<'s>;
/// Interceptor for getOwnPropertyDescriptor requests on an object.
///
/// Use [ReturnValue::set] to set the return value of the intercepted request.
/// The return value must be an object that can be converted to a
/// [PropertyDescriptor], e.g., a [Value] returned from
/// `Object.getOwnPropertyDescriptor()`.
///
/// Note: If GetOwnPropertyDescriptor is intercepted, it will always return
/// true, i.e., indicate that the property was found.
///
/// See also [ObjectTemplate::set_named_property_handler].
pub type GenericNamedPropertyDescriptorCallback<'s> = NamedGetterCallback<'s>;
/// See [GenericNamedPropertyGetterCallback].
pub type IndexedPropertyGetterCallback<'s> = IndexedGetterCallback<'s>;
/// See [GenericNamedPropertySetterCallback].
pub type IndexedPropertySetterCallback<'s> = IndexedSetterCallback<'s>;
/// See [GenericNamedPropertyQueryCallback].
pub type IndexedPropertyQueryCallback<'s> = IndexedGetterCallback<'s>;
/// See [GenericNamedPropertyDeleterCallback].
pub type IndexedPropertyDeleterCallback<'s> = IndexedGetterCallback<'s>;
/// See [GenericNamedPropertyEnumeratorCallback].
pub type IndexedPropertyEnumeratorCallback<'s> = PropertyEnumeratorCallback<'s>;
/// See [GenericNamedPropertyDefinerCallback].
pub type IndexedPropertyDefinerCallback<'s> = IndexedDefinerCallback<'s>;
/// See [GenericNamedPropertyDescriptorCallback].
pub type IndexedPropertyDescriptorCallback<'s> = IndexedGetterCallback<'s>;
pub struct AccessorConfiguration<'s> {
pub(crate) getter: AccessorNameGetterCallback<'s>,
pub(crate) setter: Option<AccessorNameSetterCallback<'s>>,
@ -146,7 +262,7 @@ impl<'s> AccessorConfiguration<'s> {
getter: getter.map_fn_to(),
setter: None,
data: None,
property_attribute: NONE,
property_attribute: PropertyAttribute::NONE,
}
}
@ -175,13 +291,15 @@ impl<'s> AccessorConfiguration<'s> {
#[derive(Default)]
pub struct NamedPropertyHandlerConfiguration<'s> {
pub(crate) getter: Option<AccessorNameGetterCallback<'s>>,
pub(crate) setter: Option<AccessorNameSetterCallback<'s>>,
pub(crate) query: Option<AccessorNameGetterCallback<'s>>,
pub(crate) deleter: Option<AccessorNameGetterCallback<'s>>,
pub(crate) enumerator: Option<PropertyEnumeratorCallback<'s>>,
pub(crate) descriptor: Option<AccessorNameGetterCallback<'s>>,
pub(crate) getter: Option<GenericNamedPropertyGetterCallback<'s>>,
pub(crate) setter: Option<GenericNamedPropertySetterCallback<'s>>,
pub(crate) query: Option<GenericNamedPropertyQueryCallback<'s>>,
pub(crate) deleter: Option<GenericNamedPropertyDeleterCallback<'s>>,
pub(crate) enumerator: Option<GenericNamedPropertyEnumeratorCallback<'s>>,
pub(crate) definer: Option<GenericNamedPropertyDefinerCallback<'s>>,
pub(crate) descriptor: Option<GenericNamedPropertyDescriptorCallback<'s>>,
pub(crate) data: Option<Local<'s, Value>>,
pub(crate) flags: PropertyHandlerFlags,
}
impl<'s> NamedPropertyHandlerConfiguration<'s> {
@ -192,8 +310,10 @@ impl<'s> NamedPropertyHandlerConfiguration<'s> {
query: None,
deleter: None,
enumerator: None,
definer: None,
descriptor: None,
data: None,
flags: PropertyHandlerFlags::NONE,
}
}
@ -203,12 +323,14 @@ impl<'s> NamedPropertyHandlerConfiguration<'s> {
|| self.query.is_some()
|| self.deleter.is_some()
|| self.enumerator.is_some()
|| self.definer.is_some()
|| self.descriptor.is_some()
|| !self.flags.is_none()
}
pub fn getter(
mut self,
getter: impl MapFnTo<AccessorNameGetterCallback<'s>>,
getter: impl MapFnTo<GenericNamedPropertyGetterCallback<'s>>,
) -> Self {
self.getter = Some(getter.map_fn_to());
self
@ -216,46 +338,47 @@ impl<'s> NamedPropertyHandlerConfiguration<'s> {
pub fn setter(
mut self,
setter: impl MapFnTo<AccessorNameSetterCallback<'s>>,
setter: impl MapFnTo<GenericNamedPropertySetterCallback<'s>>,
) -> Self {
self.setter = Some(setter.map_fn_to());
self
}
// Intercepts all requests that query the attributes of the property,
// e.g., getOwnPropertyDescriptor(), propertyIsEnumerable(), and defineProperty()
// Use ReturnValue.set_int32(value) to set the property attributes. The value is an interger encoding a v8::PropertyAttribute.
pub fn query(
mut self,
query: impl MapFnTo<AccessorNameGetterCallback<'s>>,
query: impl MapFnTo<GenericNamedPropertyQueryCallback<'s>>,
) -> Self {
self.query = Some(query.map_fn_to());
self
}
// Interceptor for delete requests on an object.
// Use ReturnValue.set_bool to indicate whether the request was intercepted or not. If the deleter successfully intercepts the request,
// i.e., if the request should not be further executed, call info.GetReturnValue().Set(value) with a boolean value.
// The value is used as the return value of delete.
pub fn deleter(
mut self,
deleter: impl MapFnTo<AccessorNameGetterCallback<'s>>,
deleter: impl MapFnTo<GenericNamedPropertyDeleterCallback<'s>>,
) -> Self {
self.deleter = Some(deleter.map_fn_to());
self
}
// Returns an array containing the names of the properties the named property getter intercepts.
// use ReturnValue.set with a v8::Array
pub fn enumerator(
mut self,
enumerator: impl MapFnTo<PropertyEnumeratorCallback<'s>>,
enumerator: impl MapFnTo<GenericNamedPropertyEnumeratorCallback<'s>>,
) -> Self {
self.enumerator = Some(enumerator.map_fn_to());
self
}
pub fn definer(
mut self,
definer: impl MapFnTo<GenericNamedPropertyDefinerCallback<'s>>,
) -> Self {
self.definer = Some(definer.map_fn_to());
self
}
pub fn descriptor(
mut self,
descriptor: impl MapFnTo<AccessorNameGetterCallback<'s>>,
descriptor: impl MapFnTo<GenericNamedPropertyDescriptorCallback<'s>>,
) -> Self {
self.descriptor = Some(descriptor.map_fn_to());
self
@ -266,17 +389,25 @@ impl<'s> NamedPropertyHandlerConfiguration<'s> {
self.data = Some(data);
self
}
/// Set the property handler flags. The default is PropertyHandlerFlags::NONE.
pub fn flags(mut self, flags: PropertyHandlerFlags) -> Self {
self.flags = flags;
self
}
}
#[derive(Default)]
pub struct IndexedPropertyHandlerConfiguration<'s> {
pub(crate) getter: Option<IndexedPropertyGetterCallback<'s>>,
pub(crate) setter: Option<IndexedPropertySetterCallback<'s>>,
pub(crate) query: Option<IndexedPropertyGetterCallback<'s>>,
pub(crate) deleter: Option<IndexedPropertyGetterCallback<'s>>,
pub(crate) enumerator: Option<PropertyEnumeratorCallback<'s>>,
pub(crate) descriptor: Option<IndexedPropertyGetterCallback<'s>>,
pub(crate) query: Option<IndexedPropertyQueryCallback<'s>>,
pub(crate) deleter: Option<IndexedPropertyDeleterCallback<'s>>,
pub(crate) enumerator: Option<IndexedPropertyEnumeratorCallback<'s>>,
pub(crate) definer: Option<IndexedPropertyDefinerCallback<'s>>,
pub(crate) descriptor: Option<IndexedPropertyDescriptorCallback<'s>>,
pub(crate) data: Option<Local<'s, Value>>,
pub(crate) flags: PropertyHandlerFlags,
}
impl<'s> IndexedPropertyHandlerConfiguration<'s> {
@ -287,8 +418,10 @@ impl<'s> IndexedPropertyHandlerConfiguration<'s> {
query: None,
deleter: None,
enumerator: None,
definer: None,
descriptor: None,
data: None,
flags: PropertyHandlerFlags::NONE,
}
}
@ -298,7 +431,9 @@ impl<'s> IndexedPropertyHandlerConfiguration<'s> {
|| self.query.is_some()
|| self.deleter.is_some()
|| self.enumerator.is_some()
|| self.definer.is_some()
|| self.descriptor.is_some()
|| !self.flags.is_none()
}
pub fn getter(
@ -319,7 +454,7 @@ impl<'s> IndexedPropertyHandlerConfiguration<'s> {
pub fn query(
mut self,
query: impl MapFnTo<IndexedPropertyGetterCallback<'s>>,
query: impl MapFnTo<IndexedPropertyQueryCallback<'s>>,
) -> Self {
self.query = Some(query.map_fn_to());
self
@ -327,7 +462,7 @@ impl<'s> IndexedPropertyHandlerConfiguration<'s> {
pub fn deleter(
mut self,
deleter: impl MapFnTo<IndexedPropertyGetterCallback<'s>>,
deleter: impl MapFnTo<IndexedPropertyDeleterCallback<'s>>,
) -> Self {
self.deleter = Some(deleter.map_fn_to());
self
@ -335,15 +470,23 @@ impl<'s> IndexedPropertyHandlerConfiguration<'s> {
pub fn enumerator(
mut self,
enumerator: impl MapFnTo<PropertyEnumeratorCallback<'s>>,
enumerator: impl MapFnTo<IndexedPropertyEnumeratorCallback<'s>>,
) -> Self {
self.enumerator = Some(enumerator.map_fn_to());
self
}
pub fn definer(
mut self,
definer: impl MapFnTo<IndexedPropertyDefinerCallback<'s>>,
) -> Self {
self.definer = Some(definer.map_fn_to());
self
}
pub fn descriptor(
mut self,
descriptor: impl MapFnTo<IndexedPropertyGetterCallback<'s>>,
descriptor: impl MapFnTo<IndexedPropertyDescriptorCallback<'s>>,
) -> Self {
self.descriptor = Some(descriptor.map_fn_to());
self
@ -354,13 +497,19 @@ impl<'s> IndexedPropertyHandlerConfiguration<'s> {
self.data = Some(data);
self
}
/// Set the property handler flags. The default is PropertyHandlerFlags::NONE.
pub fn flags(mut self, flags: PropertyHandlerFlags) -> Self {
self.flags = flags;
self
}
}
impl Template {
/// Adds a property to each instance created by this template.
#[inline(always)]
pub fn set(&self, key: Local<Name>, value: Local<Data>) {
self.set_with_attr(key, value, NONE)
self.set_with_attr(key, value, PropertyAttribute::NONE)
}
/// Adds a property to each instance created by this template with
@ -708,8 +857,10 @@ impl ObjectTemplate {
configuration.query,
configuration.deleter,
configuration.enumerator,
configuration.definer,
configuration.descriptor,
configuration.data.map_or_else(null, |p| &*p),
configuration.flags,
)
}
}
@ -727,6 +878,7 @@ impl ObjectTemplate {
configuration.query,
configuration.deleter,
configuration.enumerator,
configuration.definer,
configuration.descriptor,
configuration.data.map_or_else(null, |p| &*p),
)

View File

@ -1507,7 +1507,9 @@ fn object_template() {
let object_templ = v8::ObjectTemplate::new(scope);
let function_templ = v8::FunctionTemplate::new(scope, fortytwo_callback);
let name = v8::String::new(scope, "f").unwrap();
let attr = v8::READ_ONLY | v8::DONT_ENUM | v8::DONT_DELETE;
let attr = v8::PropertyAttribute::READ_ONLY
| v8::PropertyAttribute::DONT_ENUM
| v8::PropertyAttribute::DONT_DELETE;
object_templ.set_internal_field_count(1);
object_templ.set_with_attr(name.into(), function_templ.into(), attr);
let context = v8::Context::new(scope);
@ -1530,7 +1532,7 @@ fn object_template() {
scope,
name.into(),
object.into(),
v8::DONT_ENUM,
v8::PropertyAttribute::DONT_ENUM,
);
let source = r#"
{
@ -1787,7 +1789,8 @@ fn object_template_set_accessor() {
let setter = |scope: &mut v8::HandleScope,
key: v8::Local<v8::Name>,
value: v8::Local<v8::Value>,
args: v8::PropertyCallbackArguments| {
args: v8::PropertyCallbackArguments,
_rv: v8::ReturnValue| {
let this = args.this();
assert_eq!(args.holder(), this);
@ -1819,24 +1822,24 @@ fn object_template_set_accessor() {
rv.set(this.get_internal_field(scope, 0).unwrap());
};
let setter_with_data =
|scope: &mut v8::HandleScope,
key: v8::Local<v8::Name>,
value: v8::Local<v8::Value>,
args: v8::PropertyCallbackArguments| {
let this = args.this();
let setter_with_data = |scope: &mut v8::HandleScope,
key: v8::Local<v8::Name>,
value: v8::Local<v8::Value>,
args: v8::PropertyCallbackArguments,
_rv: v8::ReturnValue| {
let this = args.this();
assert_eq!(args.holder(), this);
assert!(args.data().is_string());
assert!(!args.should_throw_on_error());
assert_eq!(args.data().to_rust_string_lossy(scope), "data");
assert_eq!(args.holder(), this);
assert!(args.data().is_string());
assert!(!args.should_throw_on_error());
assert_eq!(args.data().to_rust_string_lossy(scope), "data");
let expected_key = v8::String::new(scope, "key").unwrap();
assert!(key.strict_equals(expected_key.into()));
let expected_key = v8::String::new(scope, "key").unwrap();
assert!(key.strict_equals(expected_key.into()));
assert!(value.is_int32());
assert!(this.set_internal_field(0, value));
};
assert!(value.is_int32());
assert!(this.set_internal_field(0, value));
};
let key = v8::String::new(scope, "key").unwrap();
let name = v8::String::new(scope, "obj").unwrap();
@ -1972,6 +1975,11 @@ fn object_template_set_named_property_handler() {
key: v8::Local<v8::Name>,
args: v8::PropertyCallbackArguments,
mut rv: v8::ReturnValue| {
let fallthrough_key = v8::String::new(scope, "fallthrough").unwrap();
if key.strict_equals(fallthrough_key.into()) {
return;
}
let this = args.this();
assert_eq!(args.holder(), this);
@ -1987,7 +1995,18 @@ fn object_template_set_named_property_handler() {
let setter = |scope: &mut v8::HandleScope,
key: v8::Local<v8::Name>,
value: v8::Local<v8::Value>,
args: v8::PropertyCallbackArguments| {
args: v8::PropertyCallbackArguments,
mut rv: v8::ReturnValue| {
let fallthrough_key = v8::String::new(scope, "fallthrough").unwrap();
if key.strict_equals(fallthrough_key.into()) {
return;
}
let panic_on_get = v8::String::new(scope, "panicOnGet").unwrap();
if key.strict_equals(panic_on_get.into()) {
return;
}
let this = args.this();
assert_eq!(args.holder(), this);
@ -1999,12 +2018,24 @@ fn object_template_set_named_property_handler() {
assert!(value.is_int32());
assert!(this.set_internal_field(0, value));
rv.set_undefined();
};
let query = |scope: &mut v8::HandleScope,
key: v8::Local<v8::Name>,
args: v8::PropertyCallbackArguments,
mut rv: v8::ReturnValue| {
let fallthrough_key = v8::String::new(scope, "fallthrough").unwrap();
if key.strict_equals(fallthrough_key.into()) {
return;
}
let panic_on_get = v8::String::new(scope, "panicOnGet").unwrap();
if key.strict_equals(panic_on_get.into()) {
return;
}
let this = args.this();
assert_eq!(args.holder(), this);
@ -2013,7 +2044,7 @@ fn object_template_set_named_property_handler() {
let expected_key = v8::String::new(scope, "key").unwrap();
assert!(key.strict_equals(expected_key.into()));
//PropertyAttribute::READ_ONLY
// PropertyAttribute::READ_ONLY
rv.set_int32(1);
let expected_value = v8::Integer::new(scope, 42);
assert!(this
@ -2021,13 +2052,23 @@ fn object_template_set_named_property_handler() {
.unwrap()
.strict_equals(expected_value.into()));
};
let deleter = |scope: &mut v8::HandleScope,
key: v8::Local<v8::Name>,
_args: v8::PropertyCallbackArguments,
args: v8::PropertyCallbackArguments,
mut rv: v8::ReturnValue| {
let fallthrough_key = v8::String::new(scope, "fallthrough").unwrap();
if key.strict_equals(fallthrough_key.into()) {
return;
}
let this = args.this();
let expected_key = v8::String::new(scope, "key").unwrap();
assert!(key.strict_equals(expected_key.into()));
assert!(this.set_internal_field(0, v8::undefined(scope).into()));
rv.set_bool(true);
};
@ -2047,11 +2088,77 @@ fn object_template_set_named_property_handler() {
.unwrap()
.strict_equals(expected_value.into()));
let key = v8::String::new(scope, "key").unwrap();
let key: v8::Local<v8::Name> =
v8::String::new(scope, "key").unwrap().into();
let result = v8::Array::new_with_elements(scope, &[key.into()]);
rv.set(result.into());
};
let definer = |scope: &mut v8::HandleScope,
key: v8::Local<v8::Name>,
desc: &v8::PropertyDescriptor,
args: v8::PropertyCallbackArguments,
mut rv: v8::ReturnValue| {
let fallthrough_key = v8::String::new(scope, "fallthrough").unwrap();
if key.strict_equals(fallthrough_key.into()) {
return;
}
let this = args.this();
let expected_key = v8::String::new(scope, "key").unwrap();
assert!(key.strict_equals(expected_key.into()));
assert!(desc.has_enumerable());
assert!(desc.has_configurable());
assert!(desc.has_writable());
assert!(desc.has_value());
assert!(!desc.has_get());
assert!(!desc.has_set());
assert!(desc.enumerable());
assert!(desc.configurable());
assert!(desc.writable());
let value = desc.value();
assert!(value.is_int32());
assert!(this.set_internal_field(0, value));
rv.set_undefined();
};
let descriptor = |scope: &mut v8::HandleScope,
key: v8::Local<v8::Name>,
args: v8::PropertyCallbackArguments,
mut rv: v8::ReturnValue| {
let fallthrough_key = v8::String::new(scope, "fallthrough").unwrap();
if key.strict_equals(fallthrough_key.into()) {
return;
}
let this = args.this();
let expected_key = v8::String::new(scope, "key").unwrap();
assert!(key.strict_equals(expected_key.into()));
let descriptor = v8::Object::new(scope);
let value_key = v8::String::new(scope, "value").unwrap();
let value = this.get_internal_field(scope, 0).unwrap();
descriptor.set(scope, value_key.into(), value);
let enumerable_key = v8::String::new(scope, "enumerable").unwrap();
let enumerable = v8::Boolean::new(scope, true);
descriptor.set(scope, enumerable_key.into(), enumerable.into());
let configurable_key = v8::String::new(scope, "configurable").unwrap();
let configurable = v8::Boolean::new(scope, true);
descriptor.set(scope, configurable_key.into(), configurable.into());
let writable_key = v8::String::new(scope, "writable").unwrap();
let writable = v8::Boolean::new(scope, true);
descriptor.set(scope, writable_key.into(), writable.into());
rv.set(descriptor.into());
};
let name = v8::String::new(scope, "obj").unwrap();
// Lone getter
@ -2070,6 +2177,14 @@ fn object_template_set_named_property_handler() {
obj.into(),
);
assert!(eval(scope, "obj.key").unwrap().strict_equals(int.into()));
assert!(eval(scope, "obj.fallthrough").unwrap().is_undefined());
assert!(eval(scope, "obj.fallthrough = 'a'; obj.fallthrough")
.unwrap()
.is_string());
assert!(obj
.get_internal_field(scope, 0)
.unwrap()
.strict_equals(int.into()));
// Getter + setter + deleter
let templ = v8::ObjectTemplate::new(scope);
@ -2094,8 +2209,18 @@ fn object_template_set_named_property_handler() {
.get_internal_field(scope, 0)
.unwrap()
.strict_equals(new_int.into()));
assert!(eval(scope, "delete obj.key").unwrap().boolean_value(scope));
assert!(obj.get_internal_field(scope, 0).unwrap().is_undefined());
assert!(eval(scope, "delete obj.key").unwrap().boolean_value(scope));
assert!(eval(scope, "obj.fallthrough = 'a'; obj.fallthrough")
.unwrap()
.is_string());
assert!(obj.get_internal_field(scope, 0).unwrap().is_undefined());
assert!(eval(scope, "delete obj.fallthrough")
.unwrap()
.boolean_value(scope));
assert!(eval(scope, "obj.fallthrough").unwrap().is_undefined());
// query descriptor
let templ = v8::ObjectTemplate::new(scope);
@ -2111,16 +2236,16 @@ fn object_template_set_named_property_handler() {
name.into(),
obj.into(),
);
let result =
eval(scope, "Object.getOwnPropertyDescriptor(obj, 'key')").unwrap();
let object = result.to_object(scope).unwrap();
let key = v8::String::new(scope, "writable").unwrap();
let value = object.get(scope, key.into()).unwrap();
assert!(eval(scope, "'key' in obj").unwrap().boolean_value(scope));
assert!(!eval(scope, "'fallthrough' in obj")
.unwrap()
.boolean_value(scope));
eval(scope, "obj.fallthrough = 'a'").unwrap();
assert!(eval(scope, "'fallthrough' in obj")
.unwrap()
.boolean_value(scope));
let non_writable = v8::Boolean::new(scope, false);
assert!(value.strict_equals(non_writable.into()));
//enumerator
// enumerator
let templ = v8::ObjectTemplate::new(scope);
templ.set_internal_field_count(1);
templ.set_named_property_handler(
@ -2142,7 +2267,113 @@ fn object_template_set_named_property_handler() {
let index = v8::Integer::new(scope, 0);
let result = arr.get(scope, index.into()).unwrap();
let expected = v8::String::new(scope, "key").unwrap();
assert!(expected.strict_equals(result))
assert!(expected.strict_equals(result));
eval(scope, "obj.fallthrough = 'a'").unwrap();
let arr = v8::Local::<v8::Array>::try_from(
eval(scope, "Object.keys(obj)").unwrap(),
)
.unwrap();
assert_eq!(arr.length(), 2);
// definer
let templ = v8::ObjectTemplate::new(scope);
templ.set_internal_field_count(1);
templ.set_named_property_handler(
v8::NamedPropertyHandlerConfiguration::new().definer(definer),
);
let obj = templ.new_instance(scope).unwrap();
obj.set_internal_field(0, int.into());
scope.get_current_context().global(scope).set(
scope,
name.into(),
obj.into(),
);
eval(
scope,
"Object.defineProperty(obj, 'key', { value: 9, enumerable: true, configurable: true, writable: true })",
)
.unwrap();
assert!(obj
.get_internal_field(scope, 0)
.unwrap()
.strict_equals(new_int.into()));
assert!(eval(
scope,
"Object.defineProperty(obj, 'fallthrough', { value: 'a' }); obj.fallthrough"
)
.unwrap()
.is_string());
// descriptor
let templ = v8::ObjectTemplate::new(scope);
templ.set_internal_field_count(1);
templ.set_named_property_handler(
v8::NamedPropertyHandlerConfiguration::new().descriptor(descriptor),
);
let obj = templ.new_instance(scope).unwrap();
obj.set_internal_field(0, int.into());
scope.get_current_context().global(scope).set(
scope,
name.into(),
obj.into(),
);
let desc = eval(scope, "Object.getOwnPropertyDescriptor(obj, 'key')")
.unwrap()
.to_object(scope)
.unwrap();
let expected_value = v8::Integer::new(scope, 42);
let value_key = v8::String::new(scope, "value").unwrap().into();
assert!(desc
.get(scope, value_key)
.unwrap()
.strict_equals(expected_value.into()));
let enumerable_key = v8::String::new(scope, "enumerable").unwrap().into();
assert!(desc
.get(scope, enumerable_key)
.unwrap()
.boolean_value(scope));
let configurable_key =
v8::String::new(scope, "configurable").unwrap().into();
assert!(desc
.get(scope, configurable_key)
.unwrap()
.boolean_value(scope));
let writable_key = v8::String::new(scope, "writable").unwrap().into();
assert!(desc.get(scope, writable_key).unwrap().boolean_value(scope));
assert!(
eval(scope, "Object.getOwnPropertyDescriptor(obj, 'fallthrough')")
.unwrap()
.is_undefined()
);
// Getter + Setter + Query + NON_MASKING
let templ = v8::ObjectTemplate::new(scope);
templ.set_internal_field_count(1);
templ.set_named_property_handler(
v8::NamedPropertyHandlerConfiguration::new()
.getter(getter)
.setter(setter)
.query(query)
.flags(v8::PropertyHandlerFlags::NON_MASKING),
);
let obj = templ.new_instance(scope).unwrap();
obj.set_internal_field(0, int.into());
scope.get_current_context().global(scope).set(
scope,
name.into(),
obj.into(),
);
assert!(!eval(scope, "'panicOnGet' in obj")
.unwrap()
.boolean_value(scope));
eval(scope, "obj.panicOnGet = 'x'").unwrap();
assert!(eval(scope, "'panicOnGet' in obj")
.unwrap()
.boolean_value(scope));
assert!(eval(scope, "obj.panicOnGet").unwrap().is_string());
}
}
@ -2172,7 +2403,8 @@ fn object_template_set_indexed_property_handler() {
let setter = |_scope: &mut v8::HandleScope,
index: u32,
value: v8::Local<v8::Value>,
args: v8::PropertyCallbackArguments| {
args: v8::PropertyCallbackArguments,
mut rv: v8::ReturnValue| {
let this = args.this();
assert_eq!(args.holder(), this);
@ -2183,6 +2415,22 @@ fn object_template_set_indexed_property_handler() {
assert!(value.is_int32());
assert!(this.set_internal_field(0, value));
rv.set_undefined();
};
let query = |_scope: &mut v8::HandleScope,
index: u32,
_args: v8::PropertyCallbackArguments,
mut rv: v8::ReturnValue| {
if index == 12 {
return;
}
assert_eq!(index, 37);
// PropertyAttribute::READ_ONLY
rv.set_int32(1);
};
let deleter = |_scope: &mut v8::HandleScope,
@ -2215,6 +2463,53 @@ fn object_template_set_indexed_property_handler() {
rv.set(result.into());
};
let definer = |_scope: &mut v8::HandleScope,
index: u32,
desc: &v8::PropertyDescriptor,
args: v8::PropertyCallbackArguments,
mut rv: v8::ReturnValue| {
let this = args.this();
assert_eq!(index, 37);
assert!(!desc.has_enumerable());
assert!(!desc.has_configurable());
assert!(!desc.has_writable());
assert!(desc.has_value());
assert!(!desc.has_get());
assert!(!desc.has_set());
let value = desc.value();
this.set_internal_field(0, value);
rv.set_undefined();
};
let descriptor = |scope: &mut v8::HandleScope,
index: u32,
args: v8::PropertyCallbackArguments,
mut rv: v8::ReturnValue| {
let this = args.this();
assert_eq!(index, 37);
let descriptor = v8::Object::new(scope);
let value_key = v8::String::new(scope, "value").unwrap();
let value = this.get_internal_field(scope, 0).unwrap();
descriptor.set(scope, value_key.into(), value);
let enumerable_key = v8::String::new(scope, "enumerable").unwrap();
let enumerable = v8::Boolean::new(scope, true);
descriptor.set(scope, enumerable_key.into(), enumerable.into());
let configurable_key = v8::String::new(scope, "configurable").unwrap();
let configurable = v8::Boolean::new(scope, true);
descriptor.set(scope, configurable_key.into(), configurable.into());
let writable_key = v8::String::new(scope, "writable").unwrap();
let writable = v8::Boolean::new(scope, true);
descriptor.set(scope, writable_key.into(), writable.into());
rv.set(descriptor.into());
};
let name = v8::String::new(scope, "obj").unwrap();
// Lone getter
@ -2258,7 +2553,22 @@ fn object_template_set_indexed_property_handler() {
assert!(!eval(scope, "delete obj[37]").unwrap().boolean_value(scope));
//Enumerator
// Query
let templ = v8::ObjectTemplate::new(scope);
templ.set_internal_field_count(1);
templ.set_indexed_property_handler(
v8::IndexedPropertyHandlerConfiguration::new().query(query),
);
let obj = templ.new_instance(scope).unwrap();
obj.set_internal_field(0, int.into());
scope
.get_current_context()
.global(scope)
.set(scope, name.into(), obj.into());
assert!(eval(scope, "'37' in obj").unwrap().boolean_value(scope));
// Enumerator
let templ = v8::ObjectTemplate::new(scope);
templ.set_internal_field_count(1);
templ.set_indexed_property_handler(
@ -2285,8 +2595,61 @@ fn object_template_set_indexed_property_handler() {
",
)
.unwrap();
assert!(value.strict_equals(int.into()));
// Definer
let templ = v8::ObjectTemplate::new(scope);
templ.set_internal_field_count(1);
templ.set_indexed_property_handler(
v8::IndexedPropertyHandlerConfiguration::new().definer(definer),
);
let obj = templ.new_instance(scope).unwrap();
obj.set_internal_field(0, int.into());
scope
.get_current_context()
.global(scope)
.set(scope, name.into(), obj.into());
eval(scope, "Object.defineProperty(obj, 37, { value: 9 })").unwrap();
assert!(obj
.get_internal_field(scope, 0)
.unwrap()
.strict_equals(new_int.into()));
// Descriptor
let templ = v8::ObjectTemplate::new(scope);
templ.set_internal_field_count(1);
templ.set_indexed_property_handler(
v8::IndexedPropertyHandlerConfiguration::new().descriptor(descriptor),
);
let obj = templ.new_instance(scope).unwrap();
obj.set_internal_field(0, int.into());
scope
.get_current_context()
.global(scope)
.set(scope, name.into(), obj.into());
let desc = eval(scope, "Object.getOwnPropertyDescriptor(obj, 37)")
.unwrap()
.to_object(scope)
.unwrap();
let value_key = v8::String::new(scope, "value").unwrap().into();
assert!(desc
.get(scope, value_key)
.unwrap()
.strict_equals(int.into()));
let enumerable_key = v8::String::new(scope, "enumerable").unwrap().into();
assert!(desc
.get(scope, enumerable_key)
.unwrap()
.boolean_value(scope));
let configurable_key = v8::String::new(scope, "configurable").unwrap().into();
assert!(desc
.get(scope, configurable_key)
.unwrap()
.boolean_value(scope));
let writable_key = v8::String::new(scope, "writable").unwrap().into();
assert!(desc.get(scope, writable_key).unwrap().boolean_value(scope));
}
#[test]
@ -2624,7 +2987,8 @@ fn object_set_accessor_with_setter() {
let setter = |scope: &mut v8::HandleScope,
key: v8::Local<v8::Name>,
value: v8::Local<v8::Value>,
args: v8::PropertyCallbackArguments| {
args: v8::PropertyCallbackArguments,
_rv: v8::ReturnValue| {
println!("setter called");
let this = args.this();
@ -2725,7 +3089,8 @@ fn object_set_accessor_with_setter_with_property() {
let setter = |scope: &mut v8::HandleScope,
key: v8::Local<v8::Name>,
value: v8::Local<v8::Value>,
args: v8::PropertyCallbackArguments| {
args: v8::PropertyCallbackArguments,
_rv: v8::ReturnValue| {
println!("setter called");
let this = args.this();
@ -2757,7 +3122,7 @@ fn object_set_accessor_with_setter_with_property() {
getter_setter_key.into(),
AccessorConfiguration::new(getter)
.setter(setter)
.property_attribute(v8::READ_ONLY),
.property_attribute(v8::PropertyAttribute::READ_ONLY),
);
let int_key = v8::String::new(scope, "int_key").unwrap();
@ -2830,7 +3195,8 @@ fn object_set_accessor_with_data() {
let setter = |scope: &mut v8::HandleScope,
key: v8::Local<v8::Name>,
value: v8::Local<v8::Value>,
args: v8::PropertyCallbackArguments| {
args: v8::PropertyCallbackArguments,
_rv: v8::ReturnValue| {
println!("setter called");
let this = args.this();
@ -6363,7 +6729,8 @@ fn test_object_get_property_names() {
scope,
v8::GetPropertyNamesArgs {
mode: v8::KeyCollectionMode::IncludePrototypes,
property_filter: v8::ONLY_ENUMERABLE | v8::SKIP_SYMBOLS,
property_filter: v8::PropertyFilter::ONLY_ENUMERABLE
| v8::PropertyFilter::SKIP_SYMBOLS,
index_filter: v8::IndexFilter::IncludeIndices,
key_conversion: v8::KeyConversionMode::KeepNumbers,
},
@ -9523,7 +9890,7 @@ fn gc_callbacks() {
data: *mut c_void,
) {
// We should get a mark-sweep GC here.
assert_eq!(r#type, v8::GC_TYPE_MARK_SWEEP_COMPACT);
assert_eq!(r#type, v8::GCType::MARK_SWEEP_COMPACT);
let state = unsafe { &mut *(data as *mut GCCallbackState) };
state.mark_sweep_calls += 1;
}
@ -9535,7 +9902,7 @@ fn gc_callbacks() {
data: *mut c_void,
) {
// We should get a mark-sweep GC here.
assert_eq!(r#type, v8::GC_TYPE_INCREMENTAL_MARKING);
assert_eq!(r#type, v8::GCType::INCREMENTAL_MARKING);
let state = unsafe { &mut *(data as *mut GCCallbackState) };
state.incremental_marking_calls += 1;
}
@ -9543,11 +9910,11 @@ fn gc_callbacks() {
let mut state = GCCallbackState::default();
let state_ptr = &mut state as *mut _ as *mut c_void;
let isolate = &mut v8::Isolate::new(Default::default());
isolate.add_gc_prologue_callback(callback, state_ptr, v8::GC_TYPE_ALL);
isolate.add_gc_prologue_callback(callback, state_ptr, v8::GCType::ALL);
isolate.add_gc_prologue_callback(
callback2,
state_ptr,
v8::GC_TYPE_INCREMENTAL_MARKING | v8::GC_TYPE_PROCESS_WEAK_CALLBACK,
v8::GCType::INCREMENTAL_MARKING | v8::GCType::PROCESS_WEAK_CALLBACKS,
);
{