nodex_api/
env.rs

1use std::mem::MaybeUninit;
2
3use crate::{
4    api::{self, napi_node_version},
5    prelude::*,
6};
7
8#[repr(C)]
9#[derive(Clone, Copy, Debug)]
10pub struct NapiEnv(pub(crate) napi_env);
11
12impl AsRef<napi_env> for NapiEnv {
13    fn as_ref(&self) -> &napi_env {
14        &self.0
15    }
16}
17
18impl NapiEnv {
19    /// create `NapiEnv` from raw napi_env
20    #[inline]
21    pub fn from_raw(env: napi_env) -> NapiEnv {
22        NapiEnv(env)
23    }
24
25    /// access raw napi_env from `NapiEnv`
26    #[inline]
27    pub fn raw(&self) -> napi_env {
28        self.0
29    }
30
31    /// This API returns the global object.
32    #[inline]
33    pub fn global(&self) -> NapiResult<JsGlobal> {
34        JsGlobal::new(*self)
35    }
36
37    /// get node version
38    /// the returned buffer is statically allocated and does not need to be freed.
39    #[inline]
40    pub fn node_version(&self) -> NapiResult<napi_node_version> {
41        let value = napi_call!(=napi_get_node_version, *self);
42        unsafe { Ok(std::ptr::read(value)) }
43    }
44
45    /// get napi version
46    #[inline]
47    pub fn napi_version(&self) -> NapiResult<u32> {
48        Ok(napi_call!(=napi_get_version, *self))
49    }
50
51    /// Return null object
52    #[inline]
53    pub fn null(&self) -> NapiResult<JsNull> {
54        JsNull::new(*self)
55    }
56
57    /// Return undefined object
58    #[inline]
59    pub fn undefined(&self) -> NapiResult<JsUndefined> {
60        JsUndefined::new(*self)
61    }
62
63    /// This API is used to convert from the C int32_t type to the JavaScript number type.
64    /// The JavaScript number type is described in Section 6.1.6 of the ECMAScript Language Specification.
65    #[inline]
66    pub fn int32(&self, value: i32) -> NapiResult<JsNumber> {
67        JsNumber::int32(*self, value)
68    }
69
70    /// This API is used to convert from the C uint32_t type to the JavaScript number type.
71    /// The JavaScript number type is described in Section 6.1.6 of the ECMAScript Language Specification.
72    #[inline]
73    pub fn uint32(&self, value: u32) -> NapiResult<JsNumber> {
74        JsNumber::uint32(*self, value)
75    }
76
77    /// This API is used to convert from the C int64_t type to the JavaScript number type.
78    /// The JavaScript number type is described in Section 6.1.6 of the ECMAScript Language Specification. Note the complete range of int64_t cannot be represented with full precision in JavaScript. Integer values outside the range of Number.MIN_SAFE_INTEGER -(2**53 - 1) - Number.MAX_SAFE_INTEGER (2**53 - 1) will lose precision.
79    #[inline]
80    pub fn int64(&self, value: i64) -> NapiResult<JsNumber> {
81        JsNumber::int64(*self, value)
82    }
83
84    /// This API is used to convert from the C double type to the JavaScript number type.
85    /// The JavaScript number type is described in Section 6.1.6 of the ECMAScript Language Specification.
86    #[inline]
87    pub fn double(&self, value: f64) -> NapiResult<JsNumber> {
88        JsNumber::double(*self, value)
89    }
90
91    /// This API creates a JavaScript string value from a UTF8-encoded C string. The native string is copied.
92    /// The JavaScript string type is described in Section 6.1.4 of the ECMAScript Language Specification.
93    #[inline]
94    pub fn string(&self, s: impl AsRef<str>) -> NapiResult<JsString> {
95        JsString::new(*self, s)
96    }
97
98    /// Create an empty js array.
99    #[inline]
100    pub fn array(&self) -> NapiResult<JsArray> {
101        JsArray::empty(*self)
102    }
103
104    #[cfg(feature = "v6")]
105    /// Create a bigint_int64.
106    #[inline]
107    pub fn bigint_i64(&self, value: i64) -> NapiResult<JsBigInt<i64>> {
108        JsBigInt::<i64>::new_i64(*self, value)
109    }
110
111    #[cfg(feature = "v6")]
112    /// Create a bigint_unt64.
113    #[inline]
114    pub fn bigint_u64(&self, value: u64) -> NapiResult<JsBigInt<u64>> {
115        JsBigInt::<u64>::new_u64(*self, value)
116    }
117
118    /// Create a boolean.
119    #[inline]
120    pub fn boolean(&self, boolean: bool) -> NapiResult<JsBoolean> {
121        JsBoolean::new(*self, boolean)
122    }
123
124    /// Create a Buffer<N>
125    #[inline]
126    pub fn buffer<const N: usize>(&self) -> NapiResult<JsBuffer<N>> {
127        JsBuffer::<N>::create(*self)
128    }
129
130    /// Create a Buffer<N> from [u8]
131    #[inline]
132    pub fn buffer_copy<const N: usize>(&self, data: [u8; N]) -> NapiResult<JsBuffer<N>> {
133        JsBuffer::<N>::create_copy(*self, data)
134    }
135
136    /// Create an ArrayBuffer
137    #[inline]
138    pub fn arraybuffer(&self, buffer: impl AsRef<[u8]>) -> NapiResult<JsArrayBuffer> {
139        JsArrayBuffer::new(*self, buffer)
140    }
141
142    #[cfg(feature = "v5")]
143    /// Create a Date.
144    pub fn date(&self, time: f64) -> NapiResult<JsDate> {
145        JsDate::new(*self, time)
146    }
147
148    /// This API creates a JavaScript symbol value from a UTF8-encoded C string.
149    /// The JavaScript symbol type is described in Section 19.4 of the ECMAScript Language Specification.
150    #[inline]
151    pub fn symbol(&self) -> NapiResult<JsSymbol> {
152        JsSymbol::new(*self)
153    }
154
155    /// Symbol with description.
156    #[inline]
157    pub fn symbol_description(&self, desc: JsString) -> NapiResult<JsSymbol> {
158        JsSymbol::description(*self, desc)
159    }
160
161    /// This API allocates a default JavaScript Object. It is the equivalent of doing new Object() in JavaScript.
162    /// The JavaScript Object type is described in Section 6.1.7 of the ECMAScript Language Specification.
163    #[inline]
164    pub fn object(&self) -> NapiResult<JsObject> {
165        JsObject::new(*self)
166    }
167
168    /// The async context
169    #[inline]
170    pub fn context(&self, name: impl AsRef<str>) -> NapiResult<NapiAsyncContext> {
171        NapiAsyncContext::new(*self, name)
172    }
173
174    /// Create an external data.
175    #[inline]
176    pub fn external<T>(
177        &self,
178        value: T,
179        finalizer: impl FnOnce(NapiEnv, T) -> NapiResult<()> + 'static,
180    ) -> NapiResult<JsExternal<T>> {
181        JsExternal::<T>::new(*self, value, finalizer)
182    }
183
184    /// Create a js function with a rust closure.
185    #[inline]
186    pub fn func<T: FromJsArgs, R>(
187        &self,
188        func: impl FnMut(JsObject, T) -> NapiResult<R> + 'static,
189    ) -> NapiResult<Function<R>>
190    where
191        T: FromJsArgs,
192        R: NapiValueT,
193    {
194        Function::<R>::new(*self, Option::<String>::None, func)
195    }
196
197    /// Create a named js function with a rust closure.
198    #[inline]
199    pub fn func_named<T: FromJsArgs, R>(
200        &self,
201        name: impl AsRef<str>,
202        func: impl FnMut(JsObject, T) -> NapiResult<R> + 'static,
203    ) -> NapiResult<Function<R>>
204    where
205        T: FromJsArgs,
206        R: NapiValueT,
207    {
208        Function::<R>::new(*self, Some(name), func)
209    }
210
211    /// Create a named js function with a rust function
212    #[inline]
213    pub fn function_named(
214        &self,
215        name: impl AsRef<str>,
216        func: extern "C" fn(env: NapiEnv, info: napi_callback_info) -> napi_value,
217    ) -> NapiResult<Function<JsValue>> {
218        let value = napi_call!(
219            =napi_create_function,
220            *self,
221            name.as_ref().as_ptr() as CharPointer,
222            name.as_ref().len(),
223            Some(func),
224            std::ptr::null_mut(),
225        );
226
227        Ok(Function::<JsValue>::from_value(JsValue::from_raw(
228            *self, value,
229        )))
230    }
231
232    /// Create a js function with a rust function
233    #[inline]
234    pub fn function(
235        &self,
236        func: extern "C" fn(env: NapiEnv, info: napi_callback_info) -> napi_value,
237    ) -> NapiResult<Function<JsValue>> {
238        let value = napi_call!(
239            =napi_create_function,
240            *self,
241            std::ptr::null(),
242            0,
243            Some(func),
244            std::ptr::null_mut(),
245        );
246
247        Ok(Function::<JsValue>::from_value(JsValue::from_raw(
248            *self, value,
249        )))
250    }
251
252    /// Create a js class with a rust closure
253    #[inline]
254    pub fn class<T, R>(
255        &self,
256        name: impl AsRef<str>,
257        func: impl FnMut(JsObject, T) -> NapiResult<R> + 'static,
258        properties: impl AsRef<[NapiPropertyDescriptor]>,
259    ) -> NapiResult<JsClass>
260    where
261        T: FromJsArgs,
262        R: NapiValueT,
263    {
264        JsClass::new(*self, name, func, properties)
265    }
266
267    /// Create an async work with shared state
268    #[inline]
269    pub fn async_work<T>(
270        &self,
271        name: impl AsRef<str>,
272        state: T,
273        execute: impl FnMut(&mut T) + Send + 'static,
274        complete: impl FnMut(NapiEnv, NapiStatus, T) -> NapiResult<()> + 'static,
275    ) -> NapiResult<NapiAsyncWork<T>> {
276        NapiAsyncWork::new(*self, name, state, execute, complete)
277    }
278
279    /// Create a promise with a work & complete closure.
280    #[inline]
281    pub fn promise<T, L: NapiValueT + Copy + 'static, R: NapiValueT + Copy + 'static>(
282        &self,
283        mut work: impl FnMut(&mut T) + Send + 'static,
284        mut complete: impl FnMut(JsPromise<L, R>, NapiStatus, T) -> NapiResult<()> + 'static,
285    ) -> NapiResult<JsPromise<L, R>>
286    where
287        T: Default,
288    {
289        JsPromise::<L, R>::spawn(*self, work, complete)
290    }
291
292    #[cfg(feature = "v4")]
293    /// Create a NapiThreadsafeFunction.
294    #[inline]
295    pub fn tsfn<Data, R, const N: usize>(
296        &self,
297        name: impl AsRef<str>,
298        func: Function<R>,
299        finalizer: impl FnOnce(NapiEnv) -> NapiResult<()> + 'static,
300        callback: impl FnMut(Function<R>, Data) -> NapiResult<()> + 'static,
301    ) -> NapiResult<NapiThreadsafeFunction<Data, N>>
302    where
303        R: NapiValueT,
304    {
305        NapiThreadsafeFunction::<Data, N>::new(*self, name, func, finalizer, callback)
306    }
307
308    /// This method allows the efficient definition of multiple properties on a given object. The
309    /// properties are defined using property descriptors (see napi_property_descriptor). Given an
310    /// array of such property descriptors, this API will set the properties on the object one at a
311    /// time, as defined by DefineOwnProperty() (described in Section 9.1.6 of the ECMA-262
312    /// specification).
313    #[inline]
314    pub fn define_properties(
315        &self,
316        object: impl NapiValueT,
317        properties: impl AsRef<[NapiPropertyDescriptor]>,
318    ) -> NapiResult<()> {
319        napi_call!(
320            napi_define_properties,
321            *self,
322            object.raw(),
323            properties.as_ref().len(),
324            properties.as_ref().as_ptr() as *const _,
325        )
326    }
327
328    /// This API throws the JavaScript value provided.
329    #[inline]
330    pub fn throw<T: NapiValueT>(&self, to_throw: T) -> NapiResult<()> {
331        napi_call!(napi_throw, *self, to_throw.raw())
332    }
333
334    /// This API throws a JavaScript Error with the text provided.
335    #[inline]
336    pub fn throw_error(&self, msg: impl AsRef<str>) -> NapiResult<()> {
337        use std::ffi::CString;
338        let msg = napi_s!(msg.as_ref())?;
339        napi_call!(napi_throw_error, *self, std::ptr::null(), msg.as_ptr())
340    }
341
342    /// This API throws a JavaScript Error with the text provided.
343    #[inline]
344    pub fn throw_error_code(&self, msg: impl AsRef<str>, code: impl AsRef<str>) -> NapiResult<()> {
345        use std::ffi::CString;
346        let msg = napi_s!(msg.as_ref())?;
347        let code = napi_s!(code.as_ref())?;
348        napi_call!(napi_throw_error, *self, code.as_ptr(), msg.as_ptr())
349    }
350
351    /// This API throws a JavaScript TypeError with the text provided.
352    #[inline]
353    pub fn throw_type_error(&self, msg: impl AsRef<str>) -> NapiResult<()> {
354        let msg = napi_s!(msg.as_ref()).map_err(|_| NapiStatus::StringExpected)?;
355        napi_call!(napi_throw_type_error, *self, std::ptr::null(), msg.as_ptr())
356    }
357
358    /// This API throws a JavaScript TypeError with the text provided.
359    #[inline]
360    pub fn throw_type_error_code(
361        &self,
362        msg: impl AsRef<str>,
363        code: impl AsRef<str>,
364    ) -> NapiResult<()> {
365        let msg = napi_s!(msg.as_ref()).map_err(|_| NapiStatus::StringExpected)?;
366        let code = napi_s!(code.as_ref())?;
367        napi_call!(napi_throw_type_error, *self, code.as_ptr(), msg.as_ptr())
368    }
369
370    /// This API throws a JavaScript TypeError with the text provided.
371    #[inline]
372    pub fn throw_range_error(
373        &self,
374        msg: impl AsRef<str>,
375        code: Option<impl AsRef<str>>,
376    ) -> NapiResult<()> {
377        use std::ffi::CString;
378        let msg = napi_s!(msg.as_ref())?;
379        napi_call!(
380            napi_throw_range_error,
381            *self,
382            std::ptr::null(),
383            msg.as_ptr()
384        )
385    }
386
387    /// This API throws a JavaScript TypeError with the text provided.
388    #[inline]
389    pub fn throw_range_error_code(
390        &self,
391        msg: impl AsRef<str>,
392        code: impl AsRef<str>,
393    ) -> NapiResult<()> {
394        use std::ffi::CString;
395        let msg = napi_s!(msg.as_ref())?;
396        let code = napi_s!(code.as_ref())?;
397        napi_call!(napi_throw_range_error, *self, code.as_ptr(), msg.as_ptr())
398    }
399
400    #[inline]
401    pub fn fatal_error(&self, msg: impl AsRef<str>) {
402        crate::fatal_error(msg, Option::<String>::None);
403    }
404
405    /// Get and clear last exception
406    /// This API can be called even if there is a pending JavaScript exception.
407    #[inline]
408    pub fn get_and_clear_last_exception(&self) -> NapiResult<Option<JsError>> {
409        let err = napi_call!(=napi_get_and_clear_last_exception, *self);
410        if err.is_null() {
411            Ok(None)
412        } else {
413            Ok(Some(JsError(JsValue(*self, err))))
414        }
415    }
416
417    /// This API retrieves a napi_extended_error_info structure with information about the last
418    /// error that occurred.
419    ///
420    /// The content of the napi_extended_error_info returned is only valid up until a Node-API
421    /// function is called on the same env. This includes a call to napi_is_exception_pending
422    /// so it may often be necessary to make a copy of the information so that it can be used
423    /// later. The pointer returned in error_message points to a statically-defined string so
424    /// it is safe to use that pointer if you have copied it out of the error_message field
425    /// (which will be overwritten) before another Node-API function was called.
426    ///
427    /// Do not rely on the content or format of any of the extended information as it is not
428    /// subject to SemVer and may change at any time. It is intended only for logging purposes.
429    ///
430    /// This API can be called even if there is a pending JavaScript exception.
431    #[inline]
432    pub fn get_last_error_info(&self) -> NapiResult<NapiExtendedErrorInfo> {
433        let info = napi_call!(=napi_get_last_error_info, *self);
434        unsafe { Ok(std::ptr::read(info)) }
435    }
436
437    /// Return true if an exception is pending.
438    /// This API can be called even if there is a pending JavaScript exception.
439    #[inline]
440    pub fn is_exception_pending(&self) -> NapiResult<bool> {
441        Ok(napi_call!(=napi_is_exception_pending, *self))
442    }
443
444    /// Create a js Error.
445    pub fn error(&self, msg: impl AsRef<str>) -> NapiResult<JsError> {
446        JsError::error(*self, msg, Option::<String>::None)
447    }
448
449    /// Trigger an 'uncaughtException' in JavaScript. Useful if an async callback throws an
450    /// exception with no way to recover.
451    #[inline]
452    #[cfg(feature = "v3")]
453    pub fn fatal_exception(&self, err: JsError) -> NapiResult<()> {
454        napi_call!(napi_fatal_exception, *self, err.raw())
455    }
456
457    /// Create a handle scope
458    #[inline]
459    pub fn handle_scope(&self) -> NapiResult<NapiHandleScope> {
460        NapiHandleScope::open(*self)
461    }
462
463    /// Run in a scope.
464    #[inline]
465    pub fn scope<T>(&self, task: impl Fn(NapiHandleScope) -> T) -> NapiResult<T> {
466        Ok(task(self.handle_scope()?))
467    }
468
469    /// Create a escapable handle scope
470    #[inline]
471    pub fn escapable_handle_scope(&self) -> NapiResult<NapiEscapableHandleScope> {
472        NapiEscapableHandleScope::open(*self)
473    }
474
475    /// Run in an escapable scope.
476    pub fn escapable_scope<T>(
477        &self,
478        task: impl Fn(NapiEscapableHandleScope) -> T,
479    ) -> NapiResult<T> {
480        Ok(task(self.escapable_handle_scope()?))
481    }
482
483    #[cfg(feature = "v3")]
484    /// Registers fun as a function to be run with the arg parameter once the current
485    /// Node.js environment exits.
486    ///
487    /// A function can safely be specified multiple times with different arg values.
488    ///
489    /// In that case, it will be called multiple times as well. Providing the same fun
490    /// and arg values multiple times is not allowed and will lead the process to abort.
491    ///
492    /// The hooks will be called in reverse order, i.e. the most recently added one
493    /// will be called first.
494    ///
495    /// Removing this hook can be done by using napi_remove_env_cleanup_hook. Typically,
496    /// that happens when the resource for which this hook was added is being torn down anyway.
497    /// For asynchronous cleanup, napi_add_async_cleanup_hook is available.
498    #[inline]
499    pub fn add_cleanup_hook<Hook>(&self, hook: Hook) -> NapiResult<CleanupHookHandler>
500    where
501        Hook: FnOnce() -> NapiResult<()>,
502    {
503        let hook: Box<Box<dyn FnOnce() -> NapiResult<()>>> = Box::new(Box::new(hook));
504
505        unsafe extern "C" fn cleanup_hook(data: *mut std::os::raw::c_void) {
506            unsafe {
507                let hook: Box<Box<dyn FnOnce() -> NapiResult<()>>> = Box::from_raw(data as _);
508                if let Err(e) = hook() {
509                    log::error!("[{}] cleanup hook error.", e);
510                }
511            }
512        }
513
514        let args = Box::into_raw(hook) as _;
515
516        napi_call!(napi_add_env_cleanup_hook, *self, Some(cleanup_hook), args);
517
518        Ok(CleanupHookHandler {
519            env: *self,
520            hook: Some(cleanup_hook),
521            args,
522        })
523    }
524
525    #[cfg(feature = "v8")]
526    /// Registers hook, which is a function of type napi_async_cleanup_hook, as a function
527    /// to be run with the remove_handle and arg parameters once the current Node.js
528    /// environment exits.
529    ///
530    /// Unlike napi_add_env_cleanup_hook, the hook is allowed to be asynchronous.
531    ///
532    /// Otherwise, behavior generally matches that of napi_add_env_cleanup_hook.
533    ///
534    /// If remove_handle is not NULL, an opaque value will be stored in it that must later
535    /// be passed to napi_remove_async_cleanup_hook, regardless of whether the hook has
536    /// already been invoked. Typically, that happens when the resource for which this hook
537    /// was added is being torn down anyway.
538    #[inline]
539    pub fn add_async_cleanup_hook<Hook>(
540        &self,
541        hook: Hook,
542    ) -> NapiResult<Option<AsyncCleanupHookHandler>>
543    where
544        Hook: FnOnce(AsyncCleanupHookHandler) -> NapiResult<()>,
545    {
546        let hook: Box<Box<dyn FnOnce(AsyncCleanupHookHandler) -> NapiResult<()>>> =
547            Box::new(Box::new(hook));
548
549        // The body of the function should initiate the asynchronous cleanup actions at the end of
550        // which handle must be passed in a call to napi_remove_async_cleanup_hook.
551        unsafe extern "C" fn async_cleanup_hook(
552            handle: napi_async_cleanup_hook_handle,
553            data: *mut std::os::raw::c_void,
554        ) {
555            unsafe {
556                let hook: Box<Box<dyn FnOnce(AsyncCleanupHookHandler) -> NapiResult<()>>> =
557                    Box::from_raw(data as _);
558                if let Err(e) = hook(AsyncCleanupHookHandler(handle)) {
559                    log::error!("[{}] cleanup hook error.", e);
560                }
561            }
562        }
563
564        let maybe_handler = napi_call!(
565            =napi_add_async_cleanup_hook,
566            *self,
567            Some(async_cleanup_hook),
568            Box::into_raw(hook) as _,
569        );
570
571        if maybe_handler.is_null() {
572            return Ok(None);
573        }
574
575        Ok(Some(AsyncCleanupHookHandler(maybe_handler)))
576    }
577
578    /// This function gives V8 an indication of the amount of externally allocated memory that is
579    /// kept alive by JavaScript objects (i.e. a JavaScript object that points to its own memory
580    /// allocated by a native module). Registering externally allocated memory will trigger global
581    /// garbage collections more often than it would otherwise.
582    #[inline]
583    pub fn adjust_external_memory(&self, changes: i64) -> NapiResult<i64> {
584        Ok(napi_call!(=napi_adjust_external_memory, *self, changes))
585    }
586
587    /// This function executes a string of JavaScript code and returns its result with the
588    /// following caveats:
589    ///
590    /// * Unlike eval, this function does not allow the script to access the current lexical
591    /// scope, and therefore also does not allow to access the module scope, meaning that
592    /// pseudo-globals such as require will not be available.
593    /// * The script can access the global scope. Function and var declarations in the script
594    /// will be added to the global object. Variable declarations made using let and const will
595    /// be visible globally, but will not be added to the global object.
596    /// * The value of this is global within the script.
597    #[inline]
598    pub fn run_script<R: NapiValueT>(&self, script: impl AsRef<str>) -> NapiResult<R> {
599        let result = napi_call!(
600            =napi_run_script,
601            *self,
602            JsString::new(*self, script)?.raw(),
603        );
604        Ok(R::from_raw(*self, result))
605    }
606
607    #[cfg(feature = "v2")]
608    #[inline]
609    pub fn get_uv_event_loop(&self) -> NapiResult<uv_loop_s> {
610        unsafe { Ok(*napi_call!(=napi_get_uv_event_loop, *self)) }
611    }
612
613    #[cfg(feature = "v6")]
614    #[allow(clippy::type_complexity)]
615    #[inline]
616    /// This API associates data with the currently running Agent. data can later be retrieved
617    /// using napi_get_instance_data(). Any existing data associated with the currently running
618    /// Agent which was set by means of a previous call to napi_set_instance_data() will be
619    /// overwritten. If a finalize_cb was provided by the previous call, it will not be called.
620    pub fn set_instance_data<T, F>(&self, data: T, finalizer: F) -> NapiResult<()>
621    where
622        F: FnOnce(NapiEnv, T) -> NapiResult<()>,
623    {
624        let data = Box::into_raw(Box::new(data)) as DataPointer;
625
626        // NB: Because we add a closure to the napi finalizer, it's better
627        // to **CAPTURE** the leaked data from rust side, so here we just
628        // ignore the passed in native data pointer.
629        unsafe extern "C" fn finalizer_trampoline<T>(
630            env: NapiEnv,
631            data: DataPointer,
632            finalizer: DataPointer,
633        ) {
634            // NB: here we collect the memory of finalizer closure
635            let finalizer: Box<Box<dyn FnOnce(NapiEnv, T) -> NapiResult<()>>> =
636                Box::from_raw(finalizer as _);
637
638            let data: Box<T> = Box::from_raw(data as _);
639
640            if let Err(err) = finalizer(env, *data) {
641                log::error!("NapiValueT::finalizer(): {}", err);
642            }
643        }
644
645        let finalizer: Box<Box<dyn FnOnce(NapiEnv, T) -> NapiResult<()>>> =
646            Box::new(Box::new(finalizer));
647
648        napi_call!(
649            napi_set_instance_data,
650            *self,
651            data,
652            Some(finalizer_trampoline::<T>),
653            Box::into_raw(finalizer) as _,
654        )
655    }
656
657    #[cfg(feature = "v6")]
658    /// This API retrieves data that was previously associated with the currently running Agent via
659    /// napi_set_instance_data(). If no data is set, the call will succeed and data will be set to
660    /// NULL.
661    #[inline]
662    pub fn get_instance_data<T>(&self) -> NapiResult<Option<&mut T>> {
663        let data = napi_call!(=napi_get_instance_data, *self) as *mut T;
664        if data.is_null() {
665            Ok(None)
666        } else {
667            unsafe { Ok(Some(&mut *data)) }
668        }
669    }
670}
671
672#[cfg(feature = "v3")]
673pub struct CleanupHookHandler {
674    env: NapiEnv,
675    hook: Option<unsafe extern "C" fn(data: *mut std::os::raw::c_void)>,
676    args: *mut std::os::raw::c_void,
677}
678
679#[cfg(feature = "v3")]
680impl CleanupHookHandler {
681    pub fn remove(self) -> NapiResult<()> {
682        napi_call!(napi_remove_env_cleanup_hook, self.env, self.hook, self.args)
683    }
684}
685
686#[cfg(feature = "v8")]
687#[derive(Debug)]
688pub struct AsyncCleanupHookHandler(napi_async_cleanup_hook_handle);
689
690#[cfg(feature = "v8")]
691impl AsyncCleanupHookHandler {
692    pub fn remove(self) -> NapiResult<()> {
693        napi_call!(napi_remove_async_cleanup_hook, self.0)
694    }
695}