feat(napi): implement create_external and get_value_external

This commit is contained in:
LongYinan 2020-06-19 16:16:28 +08:00
parent 26bd7ddb62
commit 79401d693e
No known key found for this signature in database
GPG key ID: A3FFE134A3E20881
4 changed files with 80 additions and 1 deletions

View file

@ -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](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_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_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_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_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 | ✅ | | [napi_create_object](https://nodejs.org/api/n-api.html#n_api_napi_create_object) | 1 | v8.0.0 | ✅ |

View file

@ -530,6 +530,48 @@ impl Env {
} }
} }
pub fn create_external<T: 'static>(&self, native_object: T) -> Result<Value<Object>> {
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::<T>),
ptr::null_mut(),
&mut object_value,
)
};
check_status(status)?;
Ok(Value::from_raw_value(self, object_value, Object))
}
pub fn get_value_external<T: 'static>(&self, js_object: &Value<Object>) -> 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::<T>() {
let tagged_object: *mut TaggedObject<T> = 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<Value<Object>> { pub fn create_error(&self, e: Error) -> Result<Value<Object>> {
let reason = e.reason.unwrap_or("".to_owned()); let reason = e.reason.unwrap_or("".to_owned());
let reason_string = self.create_string(reason.as_str())?; let reason_string = self.create_string(reason.as_str())?;

View file

@ -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)
})

View file

@ -24,6 +24,16 @@ fn init(env: &Env, exports: &mut Value<Object>) -> Result<()> {
"testObjectIsDate", "testObjectIsDate",
env.create_function("testObjectIsDate", test_object_is_date)?, 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(()) Ok(())
} }
@ -84,3 +94,21 @@ fn test_object_is_date(ctx: CallContext) -> Result<Value<Boolean>> {
let obj: Value<Object> = ctx.get::<Object>(0)?; let obj: Value<Object> = ctx.get::<Object>(0)?;
Ok(Env::get_boolean(ctx.env, obj.is_date()?)?) Ok(Env::get_boolean(ctx.env, obj.is_date()?)?)
} }
struct NativeObject {
count: i32,
}
#[js_function(1)]
fn create_external(ctx: CallContext) -> Result<Value<Object>> {
let count = ctx.get::<Number>(0)?.try_into()?;
let native = NativeObject { count };
ctx.env.create_external(native)
}
#[js_function(1)]
fn get_external_count(ctx: CallContext) -> Result<Value<Number>> {
let attached_obj = ctx.get::<Object>(0)?;
let native_object = ctx.env.get_value_external::<NativeObject>(&attached_obj)?;
ctx.env.create_int32(native_object.count)
}