feat(napi): implement env cleanup hook
This commit is contained in:
parent
973d3ee008
commit
45411a59ea
8 changed files with 106 additions and 8 deletions
|
@ -4,7 +4,7 @@ use crate::error::check_status;
|
|||
use crate::{sys, Either, Env, Error, JsUndefined, NapiValue, Result, Status};
|
||||
|
||||
pub struct CallContext<'env> {
|
||||
pub env: &'env Env,
|
||||
pub env: &'env mut Env,
|
||||
raw_this: sys::napi_value,
|
||||
callback_info: sys::napi_callback_info,
|
||||
args: &'env [sys::napi_value],
|
||||
|
@ -14,7 +14,7 @@ pub struct CallContext<'env> {
|
|||
|
||||
impl<'env> CallContext<'env> {
|
||||
pub fn new(
|
||||
env: &'env Env,
|
||||
env: &'env mut Env,
|
||||
callback_info: sys::napi_callback_info,
|
||||
raw_this: sys::napi_value,
|
||||
args: &'env [sys::napi_value],
|
||||
|
|
8
napi/src/cleanup_env.rs
Normal file
8
napi/src/cleanup_env.rs
Normal file
|
@ -0,0 +1,8 @@
|
|||
pub(crate) struct CleanupEnvHookData<T: 'static> {
|
||||
pub(crate) data: T,
|
||||
pub(crate) hook: Box<dyn FnOnce(T) -> ()>,
|
||||
}
|
||||
|
||||
#[repr(transparent)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct CleanupEnvHook<T: 'static>(pub(crate) *mut CleanupEnvHookData<T>);
|
|
@ -5,6 +5,7 @@ use std::mem;
|
|||
use std::os::raw::{c_char, c_void};
|
||||
use std::ptr;
|
||||
|
||||
use super::cleanup_env::{CleanupEnvHook, CleanupEnvHookData};
|
||||
use crate::async_work::{self, AsyncWorkPromise};
|
||||
use crate::error::check_status;
|
||||
use crate::js_values::*;
|
||||
|
@ -455,13 +456,12 @@ impl Env {
|
|||
let tagged_object: *mut TaggedObject<T> = mem::transmute(unknown_tagged_object);
|
||||
(*tagged_object).object.as_mut().ok_or(Error {
|
||||
status: Status::InvalidArg,
|
||||
reason: "Invalid argument, nothing attach to js_external".to_owned(),
|
||||
reason: "nothing attach to js_external".to_owned(),
|
||||
})
|
||||
} else {
|
||||
Err(Error {
|
||||
status: Status::InvalidArg,
|
||||
reason: "Invalid argument, T on get_value_external is not the type of wrapped object"
|
||||
.to_owned(),
|
||||
reason: "T on get_value_external is not the type of wrapped object".to_owned(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -519,6 +519,41 @@ impl Env {
|
|||
Ok(uv_loop)
|
||||
}
|
||||
|
||||
#[cfg(napi3)]
|
||||
pub fn add_env_cleanup_hook<T, F>(
|
||||
&mut self,
|
||||
cleanup_data: T,
|
||||
cleanup_fn: F,
|
||||
) -> Result<CleanupEnvHook<T>>
|
||||
where
|
||||
T: 'static,
|
||||
F: 'static + FnOnce(T) -> (),
|
||||
{
|
||||
let hook = CleanupEnvHookData {
|
||||
data: cleanup_data,
|
||||
hook: Box::new(cleanup_fn),
|
||||
};
|
||||
let hook_ref = Box::leak(Box::new(hook));
|
||||
check_status(unsafe {
|
||||
sys::napi_add_env_cleanup_hook(
|
||||
self.0,
|
||||
Some(cleanup_env::<T>),
|
||||
hook_ref as *mut CleanupEnvHookData<T> as *mut _,
|
||||
)
|
||||
})?;
|
||||
Ok(CleanupEnvHook(hook_ref))
|
||||
}
|
||||
|
||||
#[cfg(napi3)]
|
||||
pub fn remove_env_cleanup_hook<T>(&mut self, hook: CleanupEnvHook<T>) -> Result<()>
|
||||
where
|
||||
T: 'static,
|
||||
{
|
||||
check_status(unsafe {
|
||||
sys::napi_remove_env_cleanup_hook(self.0, Some(cleanup_env::<T>), hook.0 as *mut _)
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(all(feature = "libuv", napi4))]
|
||||
pub fn execute<
|
||||
T: 'static + Send,
|
||||
|
@ -665,3 +700,8 @@ unsafe extern "C" fn raw_finalize<T>(
|
|||
let tagged_object: *mut TaggedObject<T> = mem::transmute(finalize_data);
|
||||
Box::from_raw(tagged_object);
|
||||
}
|
||||
|
||||
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>);
|
||||
(cleanup_env_hook.hook)(cleanup_env_hook.data);
|
||||
}
|
||||
|
|
|
@ -92,6 +92,7 @@
|
|||
|
||||
mod async_work;
|
||||
mod call_context;
|
||||
mod cleanup_env;
|
||||
mod env;
|
||||
mod error;
|
||||
mod js_values;
|
||||
|
@ -100,6 +101,8 @@ mod module;
|
|||
mod promise;
|
||||
mod status;
|
||||
mod task;
|
||||
#[cfg(napi3)]
|
||||
pub use cleanup_env::CleanupEnvHook;
|
||||
#[cfg(napi4)]
|
||||
pub mod threadsafe_function;
|
||||
#[cfg(all(feature = "tokio_rt", napi4))]
|
||||
|
|
|
@ -124,15 +124,14 @@ impl<T: ToJs> ThreadsafeFunction<T> {
|
|||
pub fn create(env: &Env, func: JsFunction, to_js: T, max_queue_size: u64) -> Result<Self> {
|
||||
let mut async_resource_name = ptr::null_mut();
|
||||
let s = "napi_rs_threadsafe_function";
|
||||
let status = unsafe {
|
||||
check_status(unsafe {
|
||||
sys::napi_create_string_utf8(
|
||||
env.0,
|
||||
s.as_ptr() as *const c_char,
|
||||
s.len() as u64,
|
||||
&mut async_resource_name,
|
||||
)
|
||||
};
|
||||
check_status(status)?;
|
||||
})?;
|
||||
|
||||
let initial_thread_count: u64 = 1;
|
||||
let mut result = ptr::null_mut();
|
||||
|
|
17
test_module/__test__/cleanup-env.spec.ts
Normal file
17
test_module/__test__/cleanup-env.spec.ts
Normal file
|
@ -0,0 +1,17 @@
|
|||
import test from 'ava'
|
||||
|
||||
const bindings = require('../index.node')
|
||||
|
||||
test('should be able to add cleanup hook', (t) => {
|
||||
t.notThrows(() => {
|
||||
const ret = bindings.addCleanupHook()
|
||||
t.is(typeof ret, 'object')
|
||||
})
|
||||
})
|
||||
|
||||
test('should be able to remove cleanup hook', (t) => {
|
||||
t.notThrows(() => {
|
||||
const ret = bindings.addCleanupHook()
|
||||
bindings.removeCleanupHook(ret)
|
||||
})
|
||||
})
|
27
test_module/src/cleanup_env.rs
Normal file
27
test_module/src/cleanup_env.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
use napi::{
|
||||
CallContext, CleanupEnvHook, ContextlessResult, Env, JsExternal, JsUndefined, Module, Result,
|
||||
};
|
||||
|
||||
#[contextless_function]
|
||||
fn add_cleanup_hook(mut env: Env) -> ContextlessResult<JsExternal> {
|
||||
let hook = env.add_env_cleanup_hook((), |_| {
|
||||
println!("cleanup hook executed");
|
||||
})?;
|
||||
env.create_external(hook).map(Some)
|
||||
}
|
||||
|
||||
#[js_function(1)]
|
||||
fn remove_cleanup_hook(ctx: CallContext) -> Result<JsUndefined> {
|
||||
let hook_external = ctx.get::<JsExternal>(0)?;
|
||||
let hook = *ctx
|
||||
.env
|
||||
.get_value_external::<CleanupEnvHook<()>>(&hook_external)?;
|
||||
ctx.env.remove_env_cleanup_hook(hook)?;
|
||||
ctx.env.get_undefined()
|
||||
}
|
||||
|
||||
pub fn register_js(module: &mut Module) -> Result<()> {
|
||||
module.create_named_method("addCleanupHook", add_cleanup_hook)?;
|
||||
module.create_named_method("removeCleanupHook", remove_cleanup_hook)?;
|
||||
Ok(())
|
||||
}
|
|
@ -7,6 +7,8 @@ extern crate serde_derive;
|
|||
|
||||
use napi::{Module, Result};
|
||||
|
||||
#[cfg(napi3)]
|
||||
mod cleanup_env;
|
||||
#[cfg(napi4)]
|
||||
mod libuv;
|
||||
#[cfg(napi4)]
|
||||
|
@ -54,6 +56,8 @@ fn init(module: &mut Module) -> Result<()> {
|
|||
env::register_js(module)?;
|
||||
object::register_js(module)?;
|
||||
global::register_js(module)?;
|
||||
#[cfg(napi3)]
|
||||
cleanup_env::register_js(module)?;
|
||||
#[cfg(napi4)]
|
||||
napi4::register_js(module)?;
|
||||
#[cfg(napi4)]
|
||||
|
|
Loading…
Reference in a new issue