feat(napi): set and get instance data
This commit is contained in:
parent
c621986ce5
commit
c4734e23a1
4 changed files with 141 additions and 0 deletions
|
@ -834,6 +834,68 @@ impl Env {
|
|||
Ok(unsafe { JsDate::from_raw_unchecked(self.0, js_value) })
|
||||
}
|
||||
|
||||
#[cfg(feature = "napi6")]
|
||||
#[inline]
|
||||
/// This API associates data with the currently running Agent. data can later be retrieved using `Env::get_instance_data()`.
|
||||
/// Any existing data associated with the currently running Agent which was set by means of a previous call to `Env::set_instance_data()` will be overwritten.
|
||||
/// If a `finalize_cb` was provided by the previous call, it will not be called.
|
||||
pub fn set_instance_data<T, Hint, F>(&self, native: T, hint: Hint, finalize_cb: F) -> Result<()>
|
||||
where
|
||||
T: 'static,
|
||||
Hint: 'static,
|
||||
F: FnOnce(FinalizeContext<T, Hint>),
|
||||
{
|
||||
check_status!(unsafe {
|
||||
sys::napi_set_instance_data(
|
||||
self.0,
|
||||
Box::leak(Box::new((TaggedObject::new(native), finalize_cb))) as *mut (TaggedObject<T>, F)
|
||||
as *mut c_void,
|
||||
Some(
|
||||
set_instance_finalize_callback::<T, Hint, F>
|
||||
as unsafe extern "C" fn(
|
||||
env: sys::napi_env,
|
||||
finalize_data: *mut c_void,
|
||||
finalize_hint: *mut c_void,
|
||||
),
|
||||
),
|
||||
Box::leak(Box::new(hint)) as *mut Hint as *mut c_void,
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(feature = "napi6")]
|
||||
#[inline]
|
||||
/// This API retrieves data that was previously associated with the currently running Agent via `Env::set_instance_data()`.
|
||||
/// If no data is set, the call will succeed and data will be set to NULL.
|
||||
pub fn get_instance_data<T>(&self) -> Result<Option<&'static mut T>>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
let mut unknown_tagged_object: *mut c_void = ptr::null_mut();
|
||||
unsafe {
|
||||
check_status!(sys::napi_get_instance_data(
|
||||
self.0,
|
||||
&mut unknown_tagged_object
|
||||
))?;
|
||||
let type_id = unknown_tagged_object as *const TypeId;
|
||||
if unknown_tagged_object.is_null() {
|
||||
return Ok(None);
|
||||
}
|
||||
if *type_id == TypeId::of::<T>() {
|
||||
let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
|
||||
(*tagged_object).object.as_mut().map(Some).ok_or(Error {
|
||||
status: Status::InvalidArg,
|
||||
reason: "Invalid argument, nothing attach to js_object".to_owned(),
|
||||
})
|
||||
} else {
|
||||
Err(Error {
|
||||
status: Status::InvalidArg,
|
||||
reason: "Invalid argument, T on unrwap is not the type of wrapped object".to_owned(),
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// # Serialize `Rust Struct` into `JavaScript Value`
|
||||
/// ```
|
||||
/// #[derive(Serialize, Debug, Deserialize)]
|
||||
|
@ -933,6 +995,26 @@ unsafe extern "C" fn raw_finalize<T>(
|
|||
Box::from_raw(tagged_object);
|
||||
}
|
||||
|
||||
#[cfg(feature = "napi6")]
|
||||
unsafe extern "C" fn set_instance_finalize_callback<T, Hint, F>(
|
||||
raw_env: sys::napi_env,
|
||||
finalize_data: *mut c_void,
|
||||
finalize_hint: *mut c_void,
|
||||
) where
|
||||
T: 'static,
|
||||
Hint: 'static,
|
||||
F: FnOnce(FinalizeContext<T, Hint>),
|
||||
{
|
||||
let (value, callback) = *Box::from_raw(finalize_data as *mut (TaggedObject<T>, F));
|
||||
let hint = *Box::from_raw(finalize_hint as *mut Hint);
|
||||
let env = Env::from_raw(raw_env);
|
||||
callback(FinalizeContext {
|
||||
value: value.object.unwrap(),
|
||||
hint,
|
||||
env,
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(feature = "napi3")]
|
||||
unsafe extern "C" fn cleanup_env<T: 'static>(hook_data: *mut c_void) {
|
||||
let cleanup_env_hook = Box::from_raw(hook_data as *mut CleanupEnvHookData<T>);
|
||||
|
|
24
test_module/__test__/napi6/instance-data.spec.ts
Normal file
24
test_module/__test__/napi6/instance-data.spec.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
import test from 'ava'
|
||||
|
||||
import { napiVersion } from '../napi-version'
|
||||
|
||||
const bindings = require('../../index.node')
|
||||
|
||||
test('should set and get instance data', (t) => {
|
||||
if (napiVersion >= 6) {
|
||||
t.is(bindings.getInstanceData(), undefined)
|
||||
bindings.setInstanceData()
|
||||
t.is(bindings.getInstanceData(), 1024)
|
||||
} else {
|
||||
t.is(bindings.getInstanceData, undefined)
|
||||
t.is(bindings.setInstanceData, undefined)
|
||||
}
|
||||
})
|
||||
|
||||
test('should throw if get instance data type mismatched', (t) => {
|
||||
if (napiVersion >= 6) {
|
||||
t.throws(bindings.getWrongTypeInstanceData)
|
||||
} else {
|
||||
t.is(bindings.getWrongTypeInstanceData, undefined)
|
||||
}
|
||||
})
|
29
test_module/src/napi6/instance.rs
Normal file
29
test_module/src/napi6/instance.rs
Normal file
|
@ -0,0 +1,29 @@
|
|||
use napi::*;
|
||||
|
||||
struct NativeObject {
|
||||
count: i64,
|
||||
}
|
||||
|
||||
#[contextless_function]
|
||||
pub fn set_instance_data(env: Env) -> ContextlessResult<JsUndefined> {
|
||||
env.set_instance_data(NativeObject { count: 1024 }, 0, |_ctx| {})?;
|
||||
env.get_undefined().map(Some)
|
||||
}
|
||||
|
||||
#[contextless_function]
|
||||
pub fn get_instance_data(env: Env) -> ContextlessResult<JsNumber> {
|
||||
if let Some(obj) = env.get_instance_data::<NativeObject>()? {
|
||||
env.create_int64(obj.count).map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[contextless_function]
|
||||
pub fn get_wrong_type_instance_data(env: Env) -> ContextlessResult<JsNumber> {
|
||||
if let Some(count) = env.get_instance_data::<i32>()? {
|
||||
env.create_int64(*count as i64).map(Some)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
|
@ -1,8 +1,10 @@
|
|||
use napi::{JsObject, Result};
|
||||
|
||||
mod bigint;
|
||||
mod instance;
|
||||
|
||||
use bigint::*;
|
||||
use instance::*;
|
||||
|
||||
pub fn register_js(exports: &mut JsObject) -> Result<()> {
|
||||
exports.create_named_method("testCreateBigintFromI64", test_create_bigint_from_i64)?;
|
||||
|
@ -13,5 +15,9 @@ pub fn register_js(exports: &mut JsObject) -> Result<()> {
|
|||
exports.create_named_method("testGetBigintI64", test_get_bigint_i64)?;
|
||||
exports.create_named_method("testGetBigintU64", test_get_bigint_u64)?;
|
||||
exports.create_named_method("testGetBigintWords", test_get_bigint_words)?;
|
||||
|
||||
exports.create_named_method("setInstanceData", set_instance_data)?;
|
||||
exports.create_named_method("getInstanceData", get_instance_data)?;
|
||||
exports.create_named_method("getWrongTypeInstanceData", get_wrong_type_instance_data)?;
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue