0
0
Fork 0
mirror of https://github.com/denoland/rusty_v8.git synced 2024-11-28 16:21:04 -05:00

Add more Object methods (#1240)

Specifically Object::get_own_property_descriptor
and Object::get_property_attributes
This commit is contained in:
Luca Casonato 2023-05-25 15:04:50 +02:00 committed by GitHub
parent 2aa6debd2b
commit 43b798a39d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 149 additions and 0 deletions

View file

@ -1426,6 +1426,21 @@ MaybeBool v8__Object__HasPrivate(const v8::Object& self,
ptr_to_local(&context), ptr_to_local(&key)));
}
void v8__Object__GetPropertyAttributes(
const v8::Object& self, const v8::Context& context,
const v8::Value& key, v8::Maybe<v8::PropertyAttribute>* out) {
*out = ptr_to_local(&self)->GetPropertyAttributes(ptr_to_local(&context),
ptr_to_local(&key));
}
const v8::Value* v8__Object__GetOwnPropertyDescriptor(
const v8::Object& self, const v8::Context& context,
const v8::Name& key) {
return maybe_local_to_ptr(ptr_to_local(&self)->GetOwnPropertyDescriptor(
ptr_to_local(&context), ptr_to_local(&key)));
}
const v8::Array* v8__Array__New(v8::Isolate* isolate, int length) {
return local_to_ptr(v8::Array::New(isolate, length));
}

View file

@ -1,6 +1,7 @@
use crate::isolate::Isolate;
use crate::support::int;
use crate::support::MapFnTo;
use crate::support::Maybe;
use crate::support::MaybeBool;
use crate::AccessorConfiguration;
use crate::AccessorNameGetterCallback;
@ -180,6 +181,17 @@ extern "C" {
context: *const Context,
key: *const Private,
) -> MaybeBool;
fn v8__Object__GetPropertyAttributes(
this: *const Object,
context: *const Context,
key: *const Value,
out: *mut Maybe<PropertyAttribute>,
);
fn v8__Object__GetOwnPropertyDescriptor(
this: *const Object,
context: *const Context,
key: *const Name,
) -> *const Value;
fn v8__Array__New(isolate: *mut Isolate, length: int) -> *const Array;
fn v8__Array__New_with_elements(
@ -755,6 +767,46 @@ impl Object {
}
.into()
}
/// Gets the property attributes of a property which can be
/// [PropertyAttribute::NONE] or any combination of
/// [PropertyAttribute::READ_ONLY], [PropertyAttribute::DONT_ENUM] and
/// [PropertyAttribute::DONT_DELETE].
/// Returns [PropertyAttribute::NONE] when the property doesn't exist.
pub fn get_property_attributes(
&self,
scope: &mut HandleScope,
key: Local<Value>,
) -> Option<PropertyAttribute> {
let mut out = Maybe::<PropertyAttribute>::default();
unsafe {
v8__Object__GetPropertyAttributes(
self,
&*scope.get_current_context(),
&*key,
&mut out,
)
};
out.into()
}
/// Implements Object.getOwnPropertyDescriptor(O, P), see
/// https://tc39.es/ecma262/#sec-object.getownpropertydescriptor.
pub fn get_own_property_descriptor<'s>(
&self,
scope: &mut HandleScope<'s>,
key: Local<Name>,
) -> Option<Local<'s, Value>> {
unsafe {
scope.cast_local(|sd| {
v8__Object__GetOwnPropertyDescriptor(
self,
sd.get_current_context(),
&*key,
)
})
}
}
}
/// Object integrity levels can be used to restrict what can be done to an

View file

@ -48,6 +48,11 @@ impl PropertyAttribute {
let Self(rhs) = that;
0 != lhs & rhs
}
pub fn as_u32(&self) -> u32 {
let Self(bits) = self;
*bits
}
}
// Identical to #[derive(Default)] but arguably clearer when made explicit.

View file

@ -6129,6 +6129,83 @@ fn get_constructor_name() {
check_ctor_name(scope, "proto", "Parent");
}
#[test]
fn get_property_attributes() {
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 obj = eval(scope, "({ a: 1 })").unwrap();
let obj = obj.to_object(scope).unwrap();
let key = v8::String::new(scope, "a").unwrap();
let attrs = obj.get_property_attributes(scope, key.into()).unwrap();
assert!(!attrs.is_read_only());
assert!(!attrs.is_dont_enum());
assert!(!attrs.is_dont_delete());
assert!(attrs.is_none());
// doesn't exist
let key = v8::String::new(scope, "b").unwrap();
let attrs = obj.get_property_attributes(scope, key.into()).unwrap();
assert!(attrs.is_none());
// exception
let key = eval(scope, "({ toString() { throw 'foo' } })").unwrap();
let tc = &mut v8::TryCatch::new(scope);
assert!(obj.get_property_attributes(tc, key).is_none());
assert!(tc.has_caught());
}
#[test]
fn get_own_property_descriptor() {
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 obj = eval(scope, "({ a: 1 })").unwrap();
let obj = obj.to_object(scope).unwrap();
let key = v8::String::new(scope, "a").unwrap();
let desc = obj.get_own_property_descriptor(scope, key.into()).unwrap();
let desc = desc.to_object(scope).unwrap();
let value_key = v8::String::new(scope, "value").unwrap();
let value = desc.get(scope, value_key.into()).unwrap();
assert!(value.is_number());
let writable_key = v8::String::new(scope, "writable").unwrap();
let writable = desc.get(scope, writable_key.into()).unwrap();
assert!(writable.is_boolean());
assert!(writable.boolean_value(scope));
let enumerable_key = v8::String::new(scope, "enumerable").unwrap();
let enumerable = desc.get(scope, enumerable_key.into()).unwrap();
assert!(enumerable.is_boolean());
assert!(enumerable.boolean_value(scope));
let configurable_key = v8::String::new(scope, "configurable").unwrap();
let configurable = desc.get(scope, configurable_key.into()).unwrap();
assert!(configurable.is_boolean());
let get_key = v8::String::new(scope, "get").unwrap();
let get = desc.get(scope, get_key.into()).unwrap();
assert!(get.is_undefined());
let set_key = v8::String::new(scope, "set").unwrap();
let set = desc.get(scope, set_key.into()).unwrap();
assert!(set.is_undefined());
// doesn't exist
let b_key = v8::String::new(scope, "b").unwrap();
let desc = obj
.get_own_property_descriptor(scope, b_key.into())
.unwrap();
assert!(desc.is_undefined());
}
#[test]
fn test_prototype_api() {
let _setup_guard = setup::parallel_test();