From 79401d693eb3ed20de322a28b1a55bbbca85a105 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Fri, 19 Jun 2020 16:16:28 +0800 Subject: [PATCH 1/2] feat(napi): implement create_external and get_value_external --- README.md | 2 +- napi/src/lib.rs | 42 ++++++++++++++++++++ test_module/__test__/create-external.spec.js | 9 +++++ test_module/src/lib.rs | 28 +++++++++++++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 test_module/__test__/create-external.spec.js diff --git a/README.md b/README.md index d79319b7..0581122d 100644 --- a/README.md +++ b/README.md @@ -136,7 +136,7 @@ npm test | [napi_create_buffer](https://nodejs.org/api/n-api.html#n_api_napi_create_buffer) | 1 | v8.0.0 | ✅ | | [napi_create_buffer_copy](https://nodejs.org/api/n-api.html#n_api_napi_create_buffer_copy) | 1 | v8.0.0 | ⛔️ | | [napi_create_date](https://nodejs.org/api/n-api.html#n_api_napi_create_date) | 5 | v11.11.0 | ⛔️ | -| [napi_create_external](https://nodejs.org/api/n-api.html#n_api_napi_create_external) | 1 | v8.0.0 | ⛔️ | +| [napi_create_external](https://nodejs.org/api/n-api.html#n_api_napi_create_external) | 1 | v8.0.0 | ✅ | | [napi_create_external_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_create_external_arraybuffer) | 1 | v8.0.0 | ✅ | | [napi_create_external_buffer](https://nodejs.org/api/n-api.html#n_api_napi_create_external_buffer) | 1 | v8.0.0 | ✅ | | [napi_create_object](https://nodejs.org/api/n-api.html#n_api_napi_create_object) | 1 | v8.0.0 | ✅ | diff --git a/napi/src/lib.rs b/napi/src/lib.rs index 4498af2a..113a2dfa 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -530,6 +530,48 @@ impl Env { } } + pub fn create_external(&self, native_object: T) -> Result> { + let mut object_value = ptr::null_mut(); + let status = unsafe { + sys::napi_create_external( + self.0, + Box::into_raw(Box::new(TaggedObject::new(native_object))) as *mut c_void, + Some(raw_finalize::), + ptr::null_mut(), + &mut object_value, + ) + }; + + check_status(status)?; + Ok(Value::from_raw_value(self, object_value, Object)) + } + + pub fn get_value_external(&self, js_object: &Value) -> Result<&mut T> { + unsafe { + let mut unknown_tagged_object = ptr::null_mut(); + let status = + sys::napi_get_value_external(self.0, js_object.raw_value, &mut unknown_tagged_object); + check_status(status)?; + + let type_id: *const TypeId = mem::transmute(unknown_tagged_object); + if *type_id == TypeId::of::() { + let tagged_object: *mut TaggedObject = mem::transmute(unknown_tagged_object); + (*tagged_object).object.as_mut().ok_or(Error { + status: Status::InvalidArg, + reason: Some("Invalid argument, nothing attach to js_object".to_owned()), + }) + } else { + Err(Error { + status: Status::InvalidArg, + reason: Some( + "Invalid argument, T on get_value_external is not the type of wrapped object" + .to_owned(), + ), + }) + } + } + } + pub fn create_error(&self, e: Error) -> Result> { let reason = e.reason.unwrap_or("".to_owned()); let reason_string = self.create_string(reason.as_str())?; diff --git a/test_module/__test__/create-external.spec.js b/test_module/__test__/create-external.spec.js new file mode 100644 index 00000000..8bc60eaa --- /dev/null +++ b/test_module/__test__/create-external.spec.js @@ -0,0 +1,9 @@ +const test = require('ava') + +const bindings = require('../index.node') + +test('should create external object and get it back', (t) => { + const fixture = 42 + const externalObject = bindings.createExternal(42) + t.is(bindings.getExternalCount(externalObject), fixture) +}) diff --git a/test_module/src/lib.rs b/test_module/src/lib.rs index a079f40a..12766e82 100644 --- a/test_module/src/lib.rs +++ b/test_module/src/lib.rs @@ -24,6 +24,16 @@ fn init(env: &Env, exports: &mut Value) -> Result<()> { "testObjectIsDate", env.create_function("testObjectIsDate", test_object_is_date)?, )?; + + exports.set_named_property( + "createExternal", + env.create_function("createExternal", create_external)?, + )?; + + exports.set_named_property( + "getExternalCount", + env.create_function("getExternalCount", get_external_count)?, + )?; Ok(()) } @@ -84,3 +94,21 @@ fn test_object_is_date(ctx: CallContext) -> Result> { let obj: Value = ctx.get::(0)?; Ok(Env::get_boolean(ctx.env, obj.is_date()?)?) } + +struct NativeObject { + count: i32, +} + +#[js_function(1)] +fn create_external(ctx: CallContext) -> Result> { + let count = ctx.get::(0)?.try_into()?; + let native = NativeObject { count }; + ctx.env.create_external(native) +} + +#[js_function(1)] +fn get_external_count(ctx: CallContext) -> Result> { + let attached_obj = ctx.get::(0)?; + let native_object = ctx.env.get_value_external::(&attached_obj)?; + ctx.env.create_int32(native_object.count) +} From 17cb852a6ef4d1577943f5698e3d38d88c395a8b Mon Sep 17 00:00:00 2001 From: LongYinan Date: Fri, 19 Jun 2020 16:19:06 +0800 Subject: [PATCH 2/2] refactor(napi): self in Task::compute could be mutable --- napi/src/task.rs | 2 +- test_module/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/napi/src/task.rs b/napi/src/task.rs index 3951a403..7ff0ffb8 100644 --- a/napi/src/task.rs +++ b/napi/src/task.rs @@ -4,7 +4,7 @@ pub trait Task { type Output: Send + Sized + 'static; type JsValue: ValueType; - fn compute(&self) -> Result; + fn compute(&mut self) -> Result; fn resolve(&self, env: &mut Env, output: Self::Output) -> Result>; } diff --git a/test_module/src/lib.rs b/test_module/src/lib.rs index 12766e82..8b690273 100644 --- a/test_module/src/lib.rs +++ b/test_module/src/lib.rs @@ -51,7 +51,7 @@ impl Task for ComputeFib { type Output = u32; type JsValue = Number; - fn compute(&self) -> Result { + fn compute(&mut self) -> Result { Ok(fibonacci_native(self.n)) }