Skip to content

Commit

Permalink
Stringify elements of napi_get_property_names.
Browse files Browse the repository at this point in the history
  • Loading branch information
goto-bus-stop committed Apr 8, 2020
1 parent 55700eb commit c1fbddc
Show file tree
Hide file tree
Showing 7 changed files with 54 additions and 10 deletions.
10 changes: 8 additions & 2 deletions crates/neon-runtime/src/napi/convert.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
use raw::Local;
use nodejs_sys as napi;

use raw::{Env, Local};

pub unsafe extern "C" fn to_object(_out: &mut Local, _value: &Local) -> bool { unimplemented!() }

pub unsafe extern "C" fn to_string(_out: &mut Local, _value: Local) -> bool { unimplemented!() }
pub unsafe extern "C" fn to_string(out: &mut Local, env: Env, value: Local) -> bool {
let status = napi::napi_coerce_to_string(env, value, out as *mut _);

status == napi::napi_status::napi_ok
}
34 changes: 33 additions & 1 deletion crates/neon-runtime/src/napi/object.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@ 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 @@ -14,7 +17,36 @@ pub unsafe extern "C" fn new(out: &mut Local, env: Env) {
pub unsafe extern "C" fn get_own_property_names(out: &mut Local, env: Env, object: Local) -> bool {
let status = napi::napi_get_property_names(env, object, out as *mut _);

status == napi::napi_status::napi_ok
if status != napi::napi_status::napi_ok {
return false;
}

// Before https://github.com/nodejs/node/pull/27524, `napi_get_property_names` would return
// numbers for numeric indices instead of strings.
let len = array::len(env, *out);
for index in 0..len {
let mut element: 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 element, env, *out, index) {
continue;
}
if tag::is_string(env, element) {
continue;
}
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, element) {
return false;
}
let mut dummy = false;
// If we can't convert assign to this array, something went wrong.
if !set_index(&mut dummy, env, *out, index, stringified) {
return false;
}
}

true
}

// Unused.
Expand Down
2 changes: 1 addition & 1 deletion crates/neon-sys/native/src/neon.cc
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ extern "C" size_t Neon_String_Data(char *out, size_t len, v8::Local<v8::Value> s
return Nan::DecodeWrite(out, len, str, Nan::UTF8);
}

extern "C" bool Neon_Convert_ToString(v8::Local<v8::String> *out, v8::Local<v8::Value> value) {
extern "C" bool Neon_Convert_ToString(v8::Local<v8::String> *out, v8::Isolate *isolate, v8::Local<v8::Value> value) {
Nan::MaybeLocal<v8::String> maybe = Nan::To<v8::String>(value);
return maybe.ToLocal(out);
}
Expand Down
2 changes: 1 addition & 1 deletion crates/neon-sys/native/src/neon.h
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ extern "C" {
int32_t Neon_String_Utf8Length(v8::Local<v8::String> str);
size_t Neon_String_Data(char *out, size_t len, v8::Local<v8::Value> str);

bool Neon_Convert_ToString(v8::Local<v8::String> *out, v8::Local<v8::Value> value);
bool Neon_Convert_ToString(v8::Local<v8::String> *out, v8::Isolate *isolate, v8::Local<v8::Value> value);
bool Neon_Convert_ToObject(v8::Local<v8::Object> *out, v8::Local<v8::Value> *value);

bool Neon_Buffer_New(v8::Local<v8::Object> *out, uint32_t size);
Expand Down
2 changes: 1 addition & 1 deletion crates/neon-sys/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ extern "C" {
pub fn Neon_Class_GetInstanceInternals(obj: Local) -> *mut c_void;

pub fn Neon_Convert_ToObject(out: &mut Local, value: &Local) -> bool;
pub fn Neon_Convert_ToString(out: &mut Local, value: Local) -> bool;
pub fn Neon_Convert_ToString(out: &mut Local, isolate: Isolate, value: Local) -> bool;

pub fn Neon_Error_Throw(val: Local);
pub fn Neon_Error_NewError(out: &mut Local, msg: Local);
Expand Down
7 changes: 5 additions & 2 deletions src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,11 @@ impl<T: Object> SuperType<T> for JsObject {

/// The trait shared by all JavaScript values.
pub trait Value: ValueInternal {
fn to_string<'a, C: Context<'a>>(self, _: &mut C) -> JsResult<'a, JsString> {
build(|out| { unsafe { neon_runtime::convert::to_string(out, self.to_raw()) } })
fn to_string<'a, C: Context<'a>>(self, cx: &mut C) -> JsResult<'a, JsString> {
let env = cx.env();
build(|out| {
unsafe { neon_runtime::convert::to_string(out, env.to_raw(), self.to_raw()) }
})
}

fn as_value<'a, C: Context<'a>>(self, _: &mut C) -> Handle<'a, JsValue> {
Expand Down
7 changes: 5 additions & 2 deletions test/napi/native/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ register_module!(|mut cx| {
let property_names = rust_created.get_own_property_names(&mut cx)?
.to_vec(&mut cx)?
.into_iter()
.map(|value| value.downcast::<JsString, _>(&mut cx).unwrap().value(&mut cx))
.collect::<Vec<_>>();
.map(|value| {
let string: Handle<JsString> = value.downcast_or_throw(&mut cx)?;
Ok(string.value(&mut cx))
})
.collect::<Result<Vec<_>, _>>()?;
assert_eq!(property_names, &["0", "a", "whatever"]);

cx.export_value("rustCreated", rust_created)?;
Expand Down

0 comments on commit c1fbddc

Please sign in to comment.