Merge pull request #76 from napi-rs/create-external

feat(napi): implement create_external and get_value_external
This commit is contained in:
LongYinan 2020-06-19 17:15:05 +08:00 committed by GitHub
commit 91c1ab9ea4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 82 additions and 3 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_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 | ✅ |

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>> {
let reason = e.reason.unwrap_or("".to_owned());
let reason_string = self.create_string(reason.as_str())?;

View file

@ -4,7 +4,7 @@ pub trait Task {
type Output: Send + Sized + 'static;
type JsValue: ValueType;
fn compute(&self) -> Result<Self::Output>;
fn compute(&mut self) -> Result<Self::Output>;
fn resolve(&self, env: &mut Env, output: Self::Output) -> Result<Value<Self::JsValue>>;
}

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",
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(())
}
@ -41,7 +51,7 @@ impl Task for ComputeFib {
type Output = u32;
type JsValue = Number;
fn compute(&self) -> Result<Self::Output> {
fn compute(&mut self) -> Result<Self::Output> {
Ok(fibonacci_native(self.n))
}
@ -84,3 +94,21 @@ fn test_object_is_date(ctx: CallContext) -> Result<Value<Boolean>> {
let obj: Value<Object> = ctx.get::<Object>(0)?;
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)
}