Skip to content

Commit

Permalink
Use napi_get_all_property_names API.
Browse files Browse the repository at this point in the history
  • Loading branch information
goto-bus-stop committed Apr 10, 2020
1 parent a9ac8ef commit 1da63e4
Showing 1 changed file with 11 additions and 64 deletions.
75 changes: 11 additions & 64 deletions crates/neon-runtime/src/napi/object.rs
Expand Up @@ -2,9 +2,6 @@ use std::mem::MaybeUninit;

use nodejs_sys as napi;

use array;
use convert;
use tag;
use raw::{Env, Local};

/// Mutates the `out` argument to refer to a `napi_value` containing a newly created JavaScript Object.
Expand All @@ -15,70 +12,20 @@ pub unsafe extern "C" fn new(out: &mut Local, env: Env) {
/// Mutates the `out` argument to refer to a `napi_value` containing the own property names of the
/// `object` as a JavaScript Array.
pub unsafe extern "C" fn get_own_property_names(out: &mut Local, env: Env, object: Local) -> bool {
// Node.js 13+ have `napi_get_all_property_names`, which does the conversion right and allows
// us to ask for only own properties or prototype properties or anything we like.
// Unfortunately, earlier versions do not support that method, so we have to implement it
// manually.
//
// So we use a temporary array for the raw names:
let mut raw_names = MaybeUninit::uninit();
if napi::napi_get_property_names(env, object, raw_names.as_mut_ptr()) != napi::napi_status::napi_ok {
return false;
}
// And a "fixed" array for the actual return value:
let mut fixed_names = MaybeUninit::uninit();
if napi::napi_create_array(env, fixed_names.as_mut_ptr()) != napi::napi_status::napi_ok {
let mut property_names = MaybeUninit::uninit();

if napi::napi_get_all_property_names(
env,
object,
napi::napi_key_collection_mode::napi_key_own_only,
napi::napi_key_filter::napi_key_skip_symbols,
napi::napi_key_conversion::napi_key_numbers_to_strings,
property_names.as_mut_ptr(),
) != napi::napi_status::napi_ok {
return false;
}

let raw_names = raw_names.assume_init();
let fixed_names = fixed_names.assume_init();

*out = fixed_names;

let raw_len = array::len(env, raw_names);
let mut fixed_len = 0;
for index in 0..raw_len {
let mut property_name: Local = std::mem::zeroed();

// In general, getters may cause arbitrary JS code to be run, but this is a newly created
// Array from an official internal API so it doesn't do anything strange.
if !get_index(&mut property_name, env, raw_names, index) {
continue;
}

// Before https://github.com/nodejs/node/pull/27524, `napi_get_property_names` would return
// numbers for numeric indices instead of strings.
// Make sure we always return strings.
let property_name = if !tag::is_string(env, property_name) {
let mut stringified: Local = std::mem::zeroed();
// If we can't convert to a string, something went wrong.
if !convert::to_string(&mut stringified, env, property_name) {
return false;
}
stringified
} else {
property_name
};

let mut is_own_property = false;
// May return a non-OK status if `key` is not a string or a Symbol, but here it is always
// a string.
if napi::napi_has_own_property(env, object, property_name, &mut is_own_property as *mut _) != napi::napi_status::napi_ok {
return false;
}

if !is_own_property {
continue;
}

let mut dummy = false;
// If we can't convert assign to this array, something went wrong.
if !set_index(&mut dummy, env, fixed_names, fixed_len, property_name) {
return false;
}
fixed_len += 1;
}
*out = property_names.assume_init();

true
}
Expand Down

0 comments on commit 1da63e4

Please sign in to comment.