From 55e8a2d60db09b9a411d8277f8e79700cb77a7fb Mon Sep 17 00:00:00 2001 From: Divy Srivastava Date: Tue, 24 Jan 2023 07:33:00 -0800 Subject: [PATCH] feat: Add v8::Object::DefineProperty (#1172) --- src/binding.cc | 41 +++++++++++++++++++++ src/lib.rs | 2 + src/object.rs | 25 +++++++++++++ src/property_descriptor.rs | 75 ++++++++++++++++++++++++++++++++++++++ tests/test_api.rs | 29 +++++++++++++++ 5 files changed, 172 insertions(+) create mode 100644 src/property_descriptor.rs diff --git a/src/binding.cc b/src/binding.cc index 8a6ee379..f39f30ee 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -1254,6 +1254,14 @@ MaybeBool v8__Object__DefineOwnProperty(const v8::Object& self, ptr_to_local(&context), ptr_to_local(&key), ptr_to_local(&value), attr)); } +MaybeBool v8__Object__DefineProperty(const v8::Object& self, + const v8::Context& context, + const v8::Name& key, + v8::PropertyDescriptor& desc) { + return maybe_to_maybe_bool(ptr_to_local(&self)->DefineProperty( + ptr_to_local(&context), ptr_to_local(&key), desc)); +} + MaybeBool v8__Object__SetAccessor(const v8::Object& self, const v8::Context& context, const v8::Name& key, @@ -3228,3 +3236,36 @@ void icu_set_default_locale(const char* locale) { } } // extern "C" + +// v8::PropertyDescriptor + +extern "C" { + +static_assert(sizeof(v8::PropertyDescriptor) == sizeof(size_t), + "v8::PropertyDescriptor size mismatch"); + +void v8__PropertyDescriptor__CONSTRUCT(uninit_t* buf) { + construct_in_place(buf); +} + +void v8__PropertyDescriptor__CONSTRUCT__Get_Set( + uninit_t* buf, v8::Local get, + v8::Local set) { + construct_in_place(buf, get, set); +} + +void v8__PropertyDescriptor__DESTRUCT(v8::PropertyDescriptor* self) { + self->~PropertyDescriptor(); +} + +void v8__PropertyDescriptor__set_enumerable(v8::PropertyDescriptor* self, + bool enumurable) { + self->set_enumerable(enumurable); +} + +void v8__PropertyDescriptor__set_configurable(v8::PropertyDescriptor* self, + bool configurable) { + self->set_configurable(configurable); +} + +} // extern "C" diff --git a/src/lib.rs b/src/lib.rs index c6ced253..c10ba73b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,6 +57,7 @@ mod primitives; mod private; mod promise; mod property_attribute; +mod property_descriptor; mod property_filter; mod proxy; mod scope; @@ -125,6 +126,7 @@ pub use primitives::*; pub use private::*; pub use promise::{PromiseRejectEvent, PromiseRejectMessage, PromiseState}; pub use property_attribute::*; +pub use property_descriptor::*; pub use property_filter::*; pub use proxy::*; pub use scope::CallbackScope; diff --git a/src/object.rs b/src/object.rs index ddc00d2e..05fc6295 100644 --- a/src/object.rs +++ b/src/object.rs @@ -17,6 +17,7 @@ use crate::Name; use crate::Object; use crate::Private; use crate::PropertyAttribute; +use crate::PropertyDescriptor; use crate::PropertyFilter; use crate::Value; use std::convert::TryFrom; @@ -86,6 +87,12 @@ extern "C" { value: *const Value, attr: PropertyAttribute, ) -> MaybeBool; + fn v8__Object__DefineProperty( + this: *const Object, + context: *const Context, + key: *const Name, + desc: *const PropertyDescriptor, + ) -> MaybeBool; fn v8__Object__GetIdentityHash(this: *const Object) -> int; fn v8__Object__GetCreationContext(this: *const Object) -> *const Context; fn v8__Object__GetOwnPropertyNames( @@ -339,6 +346,24 @@ impl Object { .into() } + #[inline(always)] + pub fn define_property( + &self, + scope: &mut HandleScope, + key: Local, + descriptor: &PropertyDescriptor, + ) -> Option { + unsafe { + v8__Object__DefineProperty( + self, + &*scope.get_current_context(), + &*key, + descriptor, + ) + .into() + } + } + #[inline(always)] pub fn get<'s>( &self, diff --git a/src/property_descriptor.rs b/src/property_descriptor.rs new file mode 100644 index 00000000..1e9cd5b8 --- /dev/null +++ b/src/property_descriptor.rs @@ -0,0 +1,75 @@ +use std::mem::size_of; +use std::mem::MaybeUninit; + +use crate::Local; +use crate::Value; + +extern "C" { + fn v8__PropertyDescriptor__CONSTRUCT(out: *mut PropertyDescriptor); + fn v8__PropertyDescriptor__CONSTRUCT__Get_Set( + this: *const PropertyDescriptor, + get: *const Value, + set: *const Value, + ); + fn v8__PropertyDescriptor__DESTRUCT(this: *mut PropertyDescriptor); + fn v8__PropertyDescriptor__set_enumerable( + this: *mut PropertyDescriptor, + enumerable: bool, + ); + fn v8__PropertyDescriptor__set_configurable( + this: *mut PropertyDescriptor, + configurable: bool, + ); +} + +#[repr(transparent)] +pub struct PropertyDescriptor([usize; 1]); + +const _: () = { + assert!( + size_of::() == size_of::(), + "PropertyDescriptor size is not 1 usize" + ); +}; + +impl Default for PropertyDescriptor { + fn default() -> Self { + Self::new() + } +} + +impl PropertyDescriptor { + pub fn new() -> Self { + let mut this = MaybeUninit::::uninit(); + unsafe { + v8__PropertyDescriptor__CONSTRUCT(this.as_mut_ptr()); + this.assume_init() + } + } + + pub fn new_from_get_set(get: Local, set: Local) -> Self { + let mut this = MaybeUninit::::uninit(); + unsafe { + v8__PropertyDescriptor__CONSTRUCT__Get_Set( + this.as_mut_ptr(), + &*get, + &*set, + ); + this.assume_init() + } + } + + pub fn set_enumerable(&mut self, enumerable: bool) { + unsafe { v8__PropertyDescriptor__set_enumerable(self, enumerable) } + } + + pub fn set_configurable(&mut self, configurable: bool) { + unsafe { v8__PropertyDescriptor__set_configurable(self, configurable) } + } +} + +impl Drop for PropertyDescriptor { + fn drop(&mut self) { + unsafe { v8__PropertyDescriptor__DESTRUCT(self) } + } +} diff --git a/tests/test_api.rs b/tests/test_api.rs index 41aef83e..bf727f3a 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -8966,3 +8966,32 @@ fn test_fast_calls_pointer() { eval(scope, source).unwrap(); assert_eq!("fast", unsafe { WHO }); } + +#[test] +fn object_define_property() { + let _setup_guard = setup::parallel_test(); + let isolate = &mut v8::Isolate::new(Default::default()); + { + let scope = &mut v8::HandleScope::new(isolate); + let context = v8::Context::new(scope); + let scope = &mut v8::ContextScope::new(scope, context); + + let mut desc = v8::PropertyDescriptor::new(); + desc.set_configurable(true); + desc.set_enumerable(false); + + let name = v8::String::new(scope, "g").unwrap(); + context + .global(scope) + .define_property(scope, name.into(), &desc); + let source = r#" + { + const d = Object.getOwnPropertyDescriptor(globalThis, "g"); + [d.configurable, d.enumerable, d.writable].toString() + } + "#; + let actual = eval(scope, source).unwrap(); + let expected = v8::String::new(scope, "true,false,false").unwrap(); + assert!(expected.strict_equals(actual)); + } +}