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) })
|
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`
|
/// # Serialize `Rust Struct` into `JavaScript Value`
|
||||||
/// ```
|
/// ```
|
||||||
/// #[derive(Serialize, Debug, Deserialize)]
|
/// #[derive(Serialize, Debug, Deserialize)]
|
||||||
|
@ -933,6 +995,26 @@ unsafe extern "C" fn raw_finalize<T>(
|
||||||
Box::from_raw(tagged_object);
|
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")]
|
#[cfg(feature = "napi3")]
|
||||||
unsafe extern "C" fn cleanup_env<T: 'static>(hook_data: *mut c_void) {
|
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>);
|
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};
|
use napi::{JsObject, Result};
|
||||||
|
|
||||||
mod bigint;
|
mod bigint;
|
||||||
|
mod instance;
|
||||||
|
|
||||||
use bigint::*;
|
use bigint::*;
|
||||||
|
use instance::*;
|
||||||
|
|
||||||
pub fn register_js(exports: &mut JsObject) -> Result<()> {
|
pub fn register_js(exports: &mut JsObject) -> Result<()> {
|
||||||
exports.create_named_method("testCreateBigintFromI64", test_create_bigint_from_i64)?;
|
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("testGetBigintI64", test_get_bigint_i64)?;
|
||||||
exports.create_named_method("testGetBigintU64", test_get_bigint_u64)?;
|
exports.create_named_method("testGetBigintU64", test_get_bigint_u64)?;
|
||||||
exports.create_named_method("testGetBigintWords", test_get_bigint_words)?;
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue