mirror of
https://github.com/denoland/rusty_v8.git
synced 2024-11-22 15:07:00 -05:00
Add Object::define_own_property() (#228)
This commit introduces the NONE, READ_ONLY, DONT_ENUM and DONT_DELETE property attributes.
This commit is contained in:
parent
42af31ff38
commit
6efb395fdc
6 changed files with 178 additions and 10 deletions
|
@ -626,9 +626,8 @@ int v8__String__WriteUtf8(const v8::String& self, v8::Isolate* isolate,
|
||||||
}
|
}
|
||||||
|
|
||||||
void v8__Template__Set(v8::Template& self, v8::Local<v8::Name> key,
|
void v8__Template__Set(v8::Template& self, v8::Local<v8::Name> key,
|
||||||
v8::Local<v8::Data> value) {
|
v8::Local<v8::Data> value, v8::PropertyAttribute attr) {
|
||||||
// TODO(bnoordhuis) Allow setting PropertyAttributes.
|
self.Set(key, value, attr);
|
||||||
self.Set(key, value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
v8::ObjectTemplate* v8__ObjectTemplate__New(
|
v8::ObjectTemplate* v8__ObjectTemplate__New(
|
||||||
|
@ -673,6 +672,14 @@ MaybeBool v8__Object__CreateDataProperty(v8::Object& self,
|
||||||
return maybe_to_maybe_bool(self.CreateDataProperty(context, key, value));
|
return maybe_to_maybe_bool(self.CreateDataProperty(context, key, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MaybeBool v8__Object__DefineOwnProperty(v8::Object& self,
|
||||||
|
v8::Local<v8::Context> context,
|
||||||
|
v8::Local<v8::Name> key,
|
||||||
|
v8::Local<v8::Value> value,
|
||||||
|
v8::PropertyAttribute attr) {
|
||||||
|
return maybe_to_maybe_bool(self.DefineOwnProperty(context, key, value, attr));
|
||||||
|
}
|
||||||
|
|
||||||
MaybeBool v8__Object__SetAccessor(v8::Object& self,
|
MaybeBool v8__Object__SetAccessor(v8::Object& self,
|
||||||
v8::Local<v8::Context> context,
|
v8::Local<v8::Context> context,
|
||||||
v8::Local<v8::Name> key,
|
v8::Local<v8::Name> key,
|
||||||
|
|
|
@ -59,6 +59,7 @@ mod platform;
|
||||||
mod primitive_array;
|
mod primitive_array;
|
||||||
mod primitives;
|
mod primitives;
|
||||||
mod promise;
|
mod promise;
|
||||||
|
mod property_attribute;
|
||||||
mod scope_traits;
|
mod scope_traits;
|
||||||
mod script;
|
mod script;
|
||||||
mod script_or_module;
|
mod script_or_module;
|
||||||
|
@ -107,6 +108,7 @@ pub use platform::Task;
|
||||||
pub use primitive_array::PrimitiveArray;
|
pub use primitive_array::PrimitiveArray;
|
||||||
pub use primitives::*;
|
pub use primitives::*;
|
||||||
pub use promise::{PromiseRejectEvent, PromiseRejectMessage, PromiseState};
|
pub use promise::{PromiseRejectEvent, PromiseRejectMessage, PromiseState};
|
||||||
|
pub use property_attribute::*;
|
||||||
pub use scope::CallbackScope;
|
pub use scope::CallbackScope;
|
||||||
pub use scope::ContextScope;
|
pub use scope::ContextScope;
|
||||||
pub use scope::FunctionCallbackScope;
|
pub use scope::FunctionCallbackScope;
|
||||||
|
|
|
@ -8,6 +8,7 @@ use crate::Context;
|
||||||
use crate::Local;
|
use crate::Local;
|
||||||
use crate::Name;
|
use crate::Name;
|
||||||
use crate::Object;
|
use crate::Object;
|
||||||
|
use crate::PropertyAttribute;
|
||||||
use crate::ToLocal;
|
use crate::ToLocal;
|
||||||
use crate::Value;
|
use crate::Value;
|
||||||
|
|
||||||
|
@ -44,6 +45,13 @@ extern "C" {
|
||||||
key: *const Name,
|
key: *const Name,
|
||||||
value: *const Value,
|
value: *const Value,
|
||||||
) -> MaybeBool;
|
) -> MaybeBool;
|
||||||
|
fn v8__Object__DefineOwnProperty(
|
||||||
|
object: &Object,
|
||||||
|
context: *const Context,
|
||||||
|
key: *const Name,
|
||||||
|
value: *const Value,
|
||||||
|
attr: PropertyAttribute,
|
||||||
|
) -> MaybeBool;
|
||||||
fn v8__Object__GetIdentityHash(object: &Object) -> int;
|
fn v8__Object__GetIdentityHash(object: &Object) -> int;
|
||||||
|
|
||||||
fn v8__Array__New(isolate: *mut Isolate, length: int) -> *mut Array;
|
fn v8__Array__New(isolate: *mut Isolate, length: int) -> *mut Array;
|
||||||
|
@ -120,6 +128,24 @@ impl Object {
|
||||||
unsafe { v8__Object__CreateDataProperty(self, &*context, &*key, &*value) }
|
unsafe { v8__Object__CreateDataProperty(self, &*context, &*key, &*value) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Implements DefineOwnProperty.
|
||||||
|
///
|
||||||
|
/// In general, CreateDataProperty will be faster, however, does not allow
|
||||||
|
/// for specifying attributes.
|
||||||
|
///
|
||||||
|
/// Returns true on success.
|
||||||
|
pub fn define_own_property(
|
||||||
|
&self,
|
||||||
|
context: Local<Context>,
|
||||||
|
key: Local<Name>,
|
||||||
|
value: Local<Value>,
|
||||||
|
attr: PropertyAttribute,
|
||||||
|
) -> MaybeBool {
|
||||||
|
unsafe {
|
||||||
|
v8__Object__DefineOwnProperty(self, &*context, &*key, &*value, attr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get<'a>(
|
pub fn get<'a>(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut impl ToLocal<'a>,
|
scope: &mut impl ToLocal<'a>,
|
||||||
|
|
94
src/property_attribute.rs
Normal file
94
src/property_attribute.rs
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
#[repr(C)]
|
||||||
|
#[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 {
|
||||||
|
/// Test if no property attributes are set.
|
||||||
|
pub fn is_none(&self) -> bool {
|
||||||
|
*self == NONE
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test if the read-only property attribute is set.
|
||||||
|
pub fn is_read_only(&self) -> bool {
|
||||||
|
self.has(READ_ONLY)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test if the non-enumerable property attribute is set.
|
||||||
|
pub fn is_dont_enum(&self) -> bool {
|
||||||
|
self.has(DONT_ENUM)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Test if the non-configurable property attribute is set.
|
||||||
|
pub fn is_dont_delete(&self) -> bool {
|
||||||
|
self.has(DONT_DELETE)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 PropertyAttribute {
|
||||||
|
fn default() -> Self {
|
||||||
|
NONE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::ops::Add for PropertyAttribute {
|
||||||
|
type Output = Self;
|
||||||
|
|
||||||
|
fn add(self, Self(rhs): Self) -> Self {
|
||||||
|
let Self(lhs) = self;
|
||||||
|
Self(lhs + rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_attr() {
|
||||||
|
assert!(NONE.is_none());
|
||||||
|
assert!(!NONE.is_read_only());
|
||||||
|
assert!(!NONE.is_dont_enum());
|
||||||
|
assert!(!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!(!DONT_ENUM.is_none());
|
||||||
|
assert!(!DONT_ENUM.is_read_only());
|
||||||
|
assert!(DONT_ENUM.is_dont_enum());
|
||||||
|
assert!(!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_eq!(NONE, Default::default());
|
||||||
|
assert_eq!(READ_ONLY, NONE + READ_ONLY);
|
||||||
|
|
||||||
|
let attr = READ_ONLY + DONT_ENUM;
|
||||||
|
assert!(!attr.is_none());
|
||||||
|
assert!(attr.is_read_only());
|
||||||
|
assert!(attr.is_dont_enum());
|
||||||
|
assert!(!attr.is_dont_delete());
|
||||||
|
}
|
|
@ -10,11 +10,18 @@ use crate::Function;
|
||||||
use crate::FunctionCallback;
|
use crate::FunctionCallback;
|
||||||
use crate::Local;
|
use crate::Local;
|
||||||
use crate::Object;
|
use crate::Object;
|
||||||
|
use crate::PropertyAttribute;
|
||||||
use crate::String;
|
use crate::String;
|
||||||
use crate::ToLocal;
|
use crate::ToLocal;
|
||||||
|
use crate::NONE;
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn v8__Template__Set(self_: &Template, key: *const Name, value: *const Data);
|
fn v8__Template__Set(
|
||||||
|
self_: &Template,
|
||||||
|
key: *const Name,
|
||||||
|
value: *const Data,
|
||||||
|
attr: PropertyAttribute,
|
||||||
|
);
|
||||||
|
|
||||||
fn v8__FunctionTemplate__New(
|
fn v8__FunctionTemplate__New(
|
||||||
isolate: &Isolate,
|
isolate: &Isolate,
|
||||||
|
@ -42,8 +49,18 @@ extern "C" {
|
||||||
impl Template {
|
impl Template {
|
||||||
/// Adds a property to each instance created by this template.
|
/// Adds a property to each instance created by this template.
|
||||||
pub fn set(&self, key: Local<Name>, value: Local<Data>) {
|
pub fn set(&self, key: Local<Name>, value: Local<Data>) {
|
||||||
// TODO(bnoordhuis) Allow setting PropertyAttributes.
|
self.set_with_attr(key, value, NONE)
|
||||||
unsafe { v8__Template__Set(self, &*key, &*value) }
|
}
|
||||||
|
|
||||||
|
/// Adds a property to each instance created by this template with
|
||||||
|
/// the specified property attributes.
|
||||||
|
pub fn set_with_attr(
|
||||||
|
&self,
|
||||||
|
key: Local<Name>,
|
||||||
|
value: Local<Data>,
|
||||||
|
attr: PropertyAttribute,
|
||||||
|
) {
|
||||||
|
unsafe { v8__Template__Set(self, &*key, &*value, attr) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -869,19 +869,41 @@ fn object_template() {
|
||||||
let object_templ = v8::ObjectTemplate::new(scope);
|
let object_templ = v8::ObjectTemplate::new(scope);
|
||||||
let function_templ = v8::FunctionTemplate::new(scope, fortytwo_callback);
|
let function_templ = v8::FunctionTemplate::new(scope, fortytwo_callback);
|
||||||
let name = v8_str(scope, "f");
|
let name = v8_str(scope, "f");
|
||||||
object_templ.set(name.into(), function_templ.into());
|
let attr = v8::READ_ONLY + v8::DONT_ENUM + v8::DONT_DELETE;
|
||||||
|
object_templ.set_with_attr(name.into(), function_templ.into(), attr);
|
||||||
let context = v8::Context::new(scope);
|
let context = v8::Context::new(scope);
|
||||||
let mut cs = v8::ContextScope::new(scope, context);
|
let mut cs = v8::ContextScope::new(scope, context);
|
||||||
let scope = cs.enter();
|
let scope = cs.enter();
|
||||||
let object = object_templ.new_instance(scope, context).unwrap();
|
let object = object_templ.new_instance(scope, context).unwrap();
|
||||||
assert!(!object.is_null_or_undefined());
|
assert!(!object.is_null_or_undefined());
|
||||||
let name = v8_str(scope, "g");
|
let name = v8_str(scope, "g");
|
||||||
context
|
context.global(scope).define_own_property(
|
||||||
.global(scope)
|
context,
|
||||||
.set(context, name.into(), object.into());
|
name.into(),
|
||||||
|
object.into(),
|
||||||
|
v8::DONT_ENUM,
|
||||||
|
);
|
||||||
|
let source = r#"
|
||||||
|
{
|
||||||
|
const d = Object.getOwnPropertyDescriptor(globalThis, "g");
|
||||||
|
[d.configurable, d.enumerable, d.writable].toString()
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let actual = eval(scope, context, source).unwrap();
|
||||||
|
let expected = v8_str(scope, "true,false,true");
|
||||||
|
assert!(expected.strict_equals(actual));
|
||||||
let actual = eval(scope, context, "g.f()").unwrap();
|
let actual = eval(scope, context, "g.f()").unwrap();
|
||||||
let expected = v8::Integer::new(scope, 42);
|
let expected = v8::Integer::new(scope, 42);
|
||||||
assert!(expected.strict_equals(actual));
|
assert!(expected.strict_equals(actual));
|
||||||
|
let source = r#"
|
||||||
|
{
|
||||||
|
const d = Object.getOwnPropertyDescriptor(g, "f");
|
||||||
|
[d.configurable, d.enumerable, d.writable].toString()
|
||||||
|
}
|
||||||
|
"#;
|
||||||
|
let actual = eval(scope, context, source).unwrap();
|
||||||
|
let expected = v8_str(scope, "false,false,false");
|
||||||
|
assert!(expected.strict_equals(actual));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue