Skip to content

Commit

Permalink
Improve Object::get_property_names() and `Object::get_own_property_…
Browse files Browse the repository at this point in the history
…names()` (denoland#1049)

This change allows the customization of the behavior of
v8::Object::GetOwnPropertyNames() and v8::Object::GetPropertyNames() by
accepting all the options that the raw V8 API supports.

Signed-off-by: Darshan Sen <[email protected]>
  • Loading branch information
RaisinTen committed Sep 3, 2022
1 parent 1f3e0e1 commit dbf19c8
Show file tree
Hide file tree
Showing 7 changed files with 447 additions and 17 deletions.
4 changes: 3 additions & 1 deletion examples/process.rs
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,9 @@ where
.to_object(scope)
.unwrap();

let props = output.get_property_names(scope).unwrap();
let props = output
.get_property_names(scope, v8::GetPropertyNamesArgsBuilder::new().build())
.unwrap();
for i in 0..props.length() {
let key = props.get_index(scope, i).unwrap();
let value = output.get(scope, key).unwrap();
Expand Down
52 changes: 42 additions & 10 deletions src/binding.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1249,16 +1249,48 @@ const v8::Context* v8__Object__GetCreationContext(const v8::Object& self) {
return maybe_local_to_ptr(ptr_to_local(&self)->GetCreationContext());
}

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)));
// v8::PropertyFilter
static_assert(v8::ALL_PROPERTIES == 0, "v8::ALL_PROPERTIES is not 0");
static_assert(v8::ONLY_WRITABLE == 1, "v8::ONLY_WRITABLE is not 1");
static_assert(v8::ONLY_ENUMERABLE == 2, "v8::ONLY_ENUMERABLE is not 2");
static_assert(v8::ONLY_CONFIGURABLE == 4, "v8::ONLY_CONFIGURABLE is not 4");
static_assert(v8::SKIP_STRINGS == 8, "v8::SKIP_STRINGS is not 8");
static_assert(v8::SKIP_SYMBOLS == 16, "v8::SKIP_SYMBOLS is not 16");

// v8::KeyConversionMode
static_assert(static_cast<int>(v8::KeyConversionMode::kConvertToString) == 0,
"v8::KeyConversionMode::kConvertToString is not 0");
static_assert(static_cast<int>(v8::KeyConversionMode::kKeepNumbers) == 1,
"v8::KeyConversionMode::kKeepNumbers is not 1");
static_assert(static_cast<int>(v8::KeyConversionMode::kNoNumbers) == 2,
"v8::KeyConversionMode::kNoNumbers is not 2");

// v8::KeyCollectionMode
static_assert(static_cast<int>(v8::KeyCollectionMode::kOwnOnly) == 0,
"v8::KeyCollectionMode::kOwnOnly is not 0");
static_assert(static_cast<int>(v8::KeyCollectionMode::kIncludePrototypes) == 1,
"v8::KeyCollectionMode::kIncludePrototypes is not 1");

// v8::IndexFilter
static_assert(static_cast<int>(v8::IndexFilter::kIncludeIndices) == 0,
"v8::IndexFilter::kIncludeIndices is not 0");
static_assert(static_cast<int>(v8::IndexFilter::kSkipIndices) == 1,
"v8::IndexFilter::kSkipIndices is not 1");

const v8::Array* v8__Object__GetOwnPropertyNames(
const v8::Object* self, const v8::Context* context,
v8::PropertyFilter filter, v8::KeyConversionMode key_conversion) {
return maybe_local_to_ptr(ptr_to_local(self)->GetOwnPropertyNames(
ptr_to_local(context), filter, key_conversion));
}

const v8::Array* v8__Object__GetPropertyNames(
const v8::Object* self, const v8::Context* context,
v8::KeyCollectionMode mode, v8::PropertyFilter property_filter,
v8::IndexFilter index_filter, v8::KeyConversionMode key_conversion) {
return maybe_local_to_ptr(ptr_to_local(self)->GetPropertyNames(
ptr_to_local(context), mode, property_filter, index_filter,
key_conversion));
}

MaybeBool v8__Object__Has(const v8::Object& self, const v8::Context& context,
Expand Down
120 changes: 120 additions & 0 deletions src/get_property_names_args_builder.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use crate::PropertyFilter;
use crate::ONLY_ENUMERABLE;
use crate::SKIP_SYMBOLS;

#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub enum KeyConversionMode {
/// kConvertToString will convert integer indices to strings.
ConvertToString,
/// kKeepNumbers will return numbers for integer indices.
KeepNumbers,
NoNumbers,
}

/// Keys/Properties filter enums:
///
/// KeyCollectionMode limits the range of collected properties. kOwnOnly limits
/// the collected properties to the given Object only. kIncludesPrototypes will
/// include all keys of the objects's prototype chain as well.
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub enum KeyCollectionMode {
/// OwnOnly limits the collected properties to the given Object only.
OwnOnly,
/// kIncludesPrototypes will include all keys of the objects's prototype chain
/// as well.
IncludePrototypes,
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub enum IndexFilter {
/// kIncludesIndices allows for integer indices to be collected.
IncludeIndices,
/// kSkipIndices will exclude integer indices from being collected.
SkipIndices,
}

pub struct GetPropertyNamesArgs {
pub mode: KeyCollectionMode,
pub property_filter: PropertyFilter,
pub index_filter: IndexFilter,
pub key_conversion: KeyConversionMode,
}

impl Default for GetPropertyNamesArgs {
fn default() -> Self {
GetPropertyNamesArgs {
mode: KeyCollectionMode::IncludePrototypes,
property_filter: ONLY_ENUMERABLE | SKIP_SYMBOLS,
index_filter: IndexFilter::IncludeIndices,
key_conversion: KeyConversionMode::KeepNumbers,
}
}
}

pub struct GetPropertyNamesArgsBuilder {
mode: KeyCollectionMode,
property_filter: PropertyFilter,
index_filter: IndexFilter,
key_conversion: KeyConversionMode,
}

impl Default for GetPropertyNamesArgsBuilder {
fn default() -> Self {
Self::new()
}
}

impl GetPropertyNamesArgsBuilder {
pub fn new() -> Self {
Self {
mode: KeyCollectionMode::IncludePrototypes,
property_filter: ONLY_ENUMERABLE | SKIP_SYMBOLS,
index_filter: IndexFilter::IncludeIndices,
key_conversion: KeyConversionMode::KeepNumbers,
}
}

pub fn build(&self) -> GetPropertyNamesArgs {
GetPropertyNamesArgs {
mode: self.mode,
property_filter: self.property_filter,
index_filter: self.index_filter,
key_conversion: self.key_conversion,
}
}

pub fn mode(
&mut self,
mode: KeyCollectionMode,
) -> &mut GetPropertyNamesArgsBuilder {
self.mode = mode;
self
}

pub fn property_filter(
&mut self,
property_filter: PropertyFilter,
) -> &mut GetPropertyNamesArgsBuilder {
self.property_filter = property_filter;
self
}

pub fn index_filter(
&mut self,
index_filter: IndexFilter,
) -> &mut GetPropertyNamesArgsBuilder {
self.index_filter = index_filter;
self
}

pub fn key_conversion(
&mut self,
key_conversion: KeyConversionMode,
) -> &mut Self {
self.key_conversion = key_conversion;
self
}
}
4 changes: 4 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ mod external_references;
pub mod fast_api;
mod fixed_array;
mod function;
mod get_property_names_args_builder;
mod handle;
pub mod icu;
mod isolate;
Expand All @@ -55,6 +56,7 @@ mod primitives;
mod private;
mod promise;
mod property_attribute;
mod property_filter;
mod proxy;
mod scope;
mod script;
Expand Down Expand Up @@ -88,6 +90,7 @@ pub use exception::*;
pub use external_references::ExternalReference;
pub use external_references::ExternalReferences;
pub use function::*;
pub use get_property_names_args_builder::*;
pub use handle::Global;
pub use handle::Handle;
pub use handle::Local;
Expand Down Expand Up @@ -118,6 +121,7 @@ pub use primitives::*;
pub use private::*;
pub use promise::{PromiseRejectEvent, PromiseRejectMessage, PromiseState};
pub use property_attribute::*;
pub use property_filter::*;
pub use proxy::*;
pub use scope::CallbackScope;
pub use scope::ContextScope;
Expand Down
29 changes: 27 additions & 2 deletions src/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,18 @@ use crate::AccessorNameGetterCallback;
use crate::AccessorNameSetterCallback;
use crate::Array;
use crate::Context;
use crate::GetPropertyNamesArgs;
use crate::HandleScope;
use crate::IndexFilter;
use crate::KeyCollectionMode;
use crate::KeyConversionMode;
use crate::Local;
use crate::Map;
use crate::Name;
use crate::Object;
use crate::Private;
use crate::PropertyAttribute;
use crate::PropertyFilter;
use crate::Value;
use std::convert::TryFrom;
use std::num::NonZeroI32;
Expand Down Expand Up @@ -87,10 +92,16 @@ extern "C" {
fn v8__Object__GetOwnPropertyNames(
this: *const Object,
context: *const Context,
filter: PropertyFilter,
key_conversion: KeyConversionMode,
) -> *const Array;
fn v8__Object__GetPropertyNames(
this: *const Object,
context: *const Context,
mode: KeyCollectionMode,
property_filter: PropertyFilter,
index_filter: IndexFilter,
key_conversion: KeyConversionMode,
) -> *const Array;
fn v8__Object__Has(
this: *const Object,
Expand Down Expand Up @@ -414,10 +425,16 @@ impl Object {
pub fn get_own_property_names<'s>(
&self,
scope: &mut HandleScope<'s>,
args: GetPropertyNamesArgs,
) -> Option<Local<'s, Array>> {
unsafe {
scope.cast_local(|sd| {
v8__Object__GetOwnPropertyNames(self, sd.get_current_context())
v8__Object__GetOwnPropertyNames(
self,
sd.get_current_context(),
args.property_filter,
args.key_conversion,
)
})
}
}
Expand All @@ -429,10 +446,18 @@ impl Object {
pub fn get_property_names<'s>(
&self,
scope: &mut HandleScope<'s>,
args: GetPropertyNamesArgs,
) -> Option<Local<'s, Array>> {
unsafe {
scope.cast_local(|sd| {
v8__Object__GetPropertyNames(self, sd.get_current_context())
v8__Object__GetPropertyNames(
self,
sd.get_current_context(),
args.mode,
args.property_filter,
args.index_filter,
args.key_conversion,
)
})
}
}
Expand Down
Loading

0 comments on commit dbf19c8

Please sign in to comment.