From 1937d30ebaf0d1498f0fecc7e04e798caaa10ea2 Mon Sep 17 00:00:00 2001 From: Max Bruce Date: Sun, 31 May 2020 14:04:01 -0700 Subject: [PATCH] Add bindings for 'Object::get_(own)_property_names()' (#337) Co-authored-by: Bert Belder --- src/binding.cc | 12 +++++++++ src/object.rs | 31 +++++++++++++++++++++ tests/test_api.rs | 68 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 111 insertions(+) diff --git a/src/binding.cc b/src/binding.cc index b69832ec..32725d22 100644 --- a/src/binding.cc +++ b/src/binding.cc @@ -777,6 +777,18 @@ const v8::Context* v8__Object__CreationContext(const v8::Object& self) { return local_to_ptr(ptr_to_local(&self)->CreationContext()); } +const v8::Array* v8__Object__GetOwnPropertyNames(const v8::Object* self, + const v8::Context* context) { + return maybe_local_to_ptr( + ptr_to_local(self)->GetOwnPropertyNames(ptr_to_local(context))); +} + +const v8::Array* v8__Object__GetPropertyNames(const v8::Object* self, + const v8::Context* context) { + return maybe_local_to_ptr( + ptr_to_local(self)->GetPropertyNames(ptr_to_local(context))); +} + const v8::Array* v8__Array__New(v8::Isolate* isolate, int length) { return local_to_ptr(v8::Array::New(isolate, length)); } diff --git a/src/object.rs b/src/object.rs index c263528a..808f00fe 100644 --- a/src/object.rs +++ b/src/object.rs @@ -71,6 +71,14 @@ extern "C" { ) -> MaybeBool; fn v8__Object__GetIdentityHash(this: *const Object) -> int; fn v8__Object__CreationContext(this: *const Object) -> *const Context; + fn v8__Object__GetOwnPropertyNames( + this: *const Object, + context: *const Context, + ) -> *const Array; + fn v8__Object__GetPropertyNames( + this: *const Object, + context: *const Context, + ) -> *const Array; fn v8__Array__New(isolate: *mut Isolate, length: int) -> *const Array; fn v8__Array__New_with_elements( @@ -253,6 +261,29 @@ impl Object { scope.to_local(ptr).unwrap() } } + + /// This function has the same functionality as GetPropertyNames but the + /// returned array doesn't contain the names of properties from prototype + /// objects. + pub fn get_own_property_names<'sc>( + &self, + scope: &mut impl ToLocal<'sc>, + context: Local, + ) -> Option> { + unsafe { scope.to_local(v8__Object__GetOwnPropertyNames(self, &*context)) } + } + + /// Returns an array containing the names of the filtered properties of this + /// object, including properties from prototype objects. The array returned by + /// this method contains the same values as would be enumerated by a for-in + /// statement over this object. + pub fn get_property_names<'sc>( + &self, + scope: &mut impl ToLocal<'sc>, + context: Local, + ) -> Option> { + unsafe { scope.to_local(v8__Object__GetPropertyNames(self, &*context)) } + } } impl Array { diff --git a/tests/test_api.rs b/tests/test_api.rs index 0334698a..21718d25 100644 --- a/tests/test_api.rs +++ b/tests/test_api.rs @@ -2941,3 +2941,71 @@ fn test_map_api() { ); } } + +#[test] +fn test_object_get_property_names() { + let _setup_guard = setup(); + let mut isolate = v8::Isolate::new(Default::default()); + + let mut hs = v8::HandleScope::new(&mut isolate); + let scope = hs.enter(); + + let context = v8::Context::new(scope); + let mut cs = v8::ContextScope::new(scope, context); + let scope = cs.enter(); + + let js_test_str: v8::Local = + v8::String::new(scope, "test").unwrap().into(); + let js_proto_test_str: v8::Local = + v8::String::new(scope, "proto_test").unwrap().into(); + let js_test_symbol: v8::Local = + eval(scope, context, "Symbol('test_symbol')") + .unwrap() + .try_into() + .unwrap(); + let js_null: v8::Local = v8::null(scope).into(); + let js_sort_fn: v8::Local = + eval(scope, context, "Array.prototype.sort") + .unwrap() + .try_into() + .unwrap(); + + { + let obj = v8::Object::new(scope); + obj.set(context, js_test_str, js_null); + + let proto_obj = v8::Object::new(scope); + proto_obj.set(context, js_proto_test_str, js_null); + obj.set_prototype(context, proto_obj.into()); + + let own_props = obj.get_own_property_names(scope, context).unwrap(); + assert_eq!(own_props.length(), 1); + assert!(own_props.get_index(scope, context, 0).unwrap() == js_test_str); + + let proto_props = proto_obj.get_own_property_names(scope, context).unwrap(); + assert_eq!(proto_props.length(), 1); + assert!( + proto_props.get_index(scope, context, 0).unwrap() == js_proto_test_str + ); + + let all_props = obj.get_property_names(scope, context).unwrap(); + js_sort_fn + .call(scope, context, all_props.into(), &[]) + .unwrap(); + assert_eq!(all_props.length(), 2); + assert!( + all_props.get_index(scope, context, 0).unwrap() == js_proto_test_str + ); + assert!(all_props.get_index(scope, context, 1).unwrap() == js_test_str); + } + + { + let obj = v8::Object::new(scope); + obj.set(context, js_test_str, js_null); + obj.set(context, js_test_symbol, js_null); + + let own_props = obj.get_own_property_names(scope, context).unwrap(); + assert_eq!(own_props.length(), 1); + assert!(own_props.get_index(scope, context, 0).unwrap() == js_test_str); + } +}