napi_calm_down/
env.rs

1#![allow(deprecated)]
2
3use std::any::{type_name, TypeId};
4use std::convert::TryInto;
5use std::ffi::CString;
6#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
7use std::future::Future;
8use std::mem;
9use std::os::raw::{c_char, c_void};
10use std::ptr;
11
12use crate::bindgen_runtime::FromNapiValue;
13#[cfg(feature = "napi4")]
14use crate::bindgen_runtime::ToNapiValue;
15use crate::{
16  async_work::{self, AsyncWorkPromise},
17  check_status,
18  js_values::*,
19  sys,
20  task::Task,
21  Error, ExtendedErrorInfo, NodeVersion, Result, Status, ValueType,
22};
23
24#[cfg(feature = "napi8")]
25use crate::async_cleanup_hook::AsyncCleanupHook;
26#[cfg(feature = "napi3")]
27use crate::cleanup_env::{CleanupEnvHook, CleanupEnvHookData};
28#[cfg(feature = "serde-json")]
29use crate::js_values::{De, Ser};
30#[cfg(feature = "napi4")]
31use crate::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunction};
32#[cfg(feature = "napi3")]
33use crate::JsError;
34#[cfg(feature = "serde-json")]
35use serde::de::DeserializeOwned;
36#[cfg(feature = "serde-json")]
37use serde::Serialize;
38
39pub type Callback = unsafe extern "C" fn(sys::napi_env, sys::napi_callback_info) -> sys::napi_value;
40
41pub(crate) static EMPTY_VEC: Vec<u8> = vec![];
42
43#[derive(Clone, Copy)]
44/// `Env` is used to represent a context that the underlying N-API implementation can use to persist VM-specific state.
45///
46/// Specifically, the same `Env` that was passed in when the initial native function was called must be passed to any subsequent nested N-API calls.
47///
48/// Caching the `Env` for the purpose of general reuse, and passing the `Env` between instances of the same addon running on different Worker threads is not allowed.
49///
50/// The `Env` becomes invalid when an instance of a native addon is unloaded.
51///
52/// Notification of this event is delivered through the callbacks given to `Env::add_env_cleanup_hook` and `Env::set_instance_data`.
53pub struct Env(pub(crate) sys::napi_env);
54
55impl From<sys::napi_env> for Env {
56  fn from(env: sys::napi_env) -> Self {
57    Env(env)
58  }
59}
60
61impl Env {
62  #[allow(clippy::missing_safety_doc)]
63  pub unsafe fn from_raw(env: sys::napi_env) -> Self {
64    Env(env)
65  }
66
67  pub fn get_boolean(&self, value: bool) -> Result<JsBoolean> {
68    let mut raw_value = ptr::null_mut();
69    check_status!(unsafe { sys::napi_get_boolean(self.0, value, &mut raw_value) })?;
70    Ok(unsafe { JsBoolean::from_raw_unchecked(self.0, raw_value) })
71  }
72
73  pub fn create_int32(&self, int: i32) -> Result<JsNumber> {
74    let mut raw_value = ptr::null_mut();
75    check_status!(unsafe {
76      sys::napi_create_int32(self.0, int, (&mut raw_value) as *mut sys::napi_value)
77    })?;
78    Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
79  }
80
81  pub fn create_int64(&self, int: i64) -> Result<JsNumber> {
82    let mut raw_value = ptr::null_mut();
83    check_status!(unsafe {
84      sys::napi_create_int64(self.0, int, (&mut raw_value) as *mut sys::napi_value)
85    })?;
86    Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
87  }
88
89  pub fn create_uint32(&self, number: u32) -> Result<JsNumber> {
90    let mut raw_value = ptr::null_mut();
91    check_status!(unsafe { sys::napi_create_uint32(self.0, number, &mut raw_value) })?;
92    Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
93  }
94
95  pub fn create_double(&self, double: f64) -> Result<JsNumber> {
96    let mut raw_value = ptr::null_mut();
97    check_status!(unsafe {
98      sys::napi_create_double(self.0, double, (&mut raw_value) as *mut sys::napi_value)
99    })?;
100    Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
101  }
102
103  /// [n_api_napi_create_bigint_int64](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_int64)
104  #[cfg(feature = "napi6")]
105  pub fn create_bigint_from_i64(&self, value: i64) -> Result<JsBigInt> {
106    let mut raw_value = ptr::null_mut();
107    check_status!(unsafe { sys::napi_create_bigint_int64(self.0, value, &mut raw_value) })?;
108    Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 1))
109  }
110
111  #[cfg(feature = "napi6")]
112  pub fn create_bigint_from_u64(&self, value: u64) -> Result<JsBigInt> {
113    let mut raw_value = ptr::null_mut();
114    check_status!(unsafe { sys::napi_create_bigint_uint64(self.0, value, &mut raw_value) })?;
115    Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 1))
116  }
117
118  #[cfg(feature = "napi6")]
119  pub fn create_bigint_from_i128(&self, value: i128) -> Result<JsBigInt> {
120    let mut raw_value = ptr::null_mut();
121    let sign_bit = i32::from(value <= 0);
122    let words = &value as *const i128 as *const u64;
123    check_status!(unsafe {
124      sys::napi_create_bigint_words(self.0, sign_bit, 2, words, &mut raw_value)
125    })?;
126    Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 2))
127  }
128
129  #[cfg(feature = "napi6")]
130  pub fn create_bigint_from_u128(&self, value: u128) -> Result<JsBigInt> {
131    let mut raw_value = ptr::null_mut();
132    let words = &value as *const u128 as *const u64;
133    check_status!(unsafe { sys::napi_create_bigint_words(self.0, 0, 2, words, &mut raw_value) })?;
134    Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 2))
135  }
136
137  /// [n_api_napi_create_bigint_words](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_words)
138  ///
139  /// The resulting BigInt will be negative when sign_bit is true.
140  #[cfg(feature = "napi6")]
141  pub fn create_bigint_from_words(&self, sign_bit: bool, words: Vec<u64>) -> Result<JsBigInt> {
142    let mut raw_value = ptr::null_mut();
143    let len = words.len();
144    check_status!(unsafe {
145      sys::napi_create_bigint_words(
146        self.0,
147        match sign_bit {
148          true => 1,
149          false => 0,
150        },
151        len,
152        words.as_ptr(),
153        &mut raw_value,
154      )
155    })?;
156    Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, len))
157  }
158
159  pub fn create_string(&self, s: &str) -> Result<JsString> {
160    unsafe { self.create_string_from_c_char(s.as_ptr().cast(), s.len()) }
161  }
162
163  pub fn create_string_from_std(&self, s: String) -> Result<JsString> {
164    unsafe { self.create_string_from_c_char(s.as_ptr().cast(), s.len()) }
165  }
166
167  /// This API is used for C ffi scenario.
168  /// Convert raw *const c_char into JsString
169  ///
170  /// # Safety
171  ///
172  /// Create JsString from known valid utf-8 string
173  pub unsafe fn create_string_from_c_char(
174    &self,
175    data_ptr: *const c_char,
176    len: usize,
177  ) -> Result<JsString> {
178    let mut raw_value = ptr::null_mut();
179    check_status!(unsafe { sys::napi_create_string_utf8(self.0, data_ptr, len, &mut raw_value) })?;
180    Ok(unsafe { JsString::from_raw_unchecked(self.0, raw_value) })
181  }
182
183  pub fn create_string_utf16(&self, chars: &[u16]) -> Result<JsString> {
184    let mut raw_value = ptr::null_mut();
185    check_status!(unsafe {
186      sys::napi_create_string_utf16(self.0, chars.as_ptr(), chars.len(), &mut raw_value)
187    })?;
188    Ok(unsafe { JsString::from_raw_unchecked(self.0, raw_value) })
189  }
190
191  pub fn create_string_latin1(&self, chars: &[u8]) -> Result<JsString> {
192    let mut raw_value = ptr::null_mut();
193    check_status!(unsafe {
194      sys::napi_create_string_latin1(
195        self.0,
196        chars.as_ptr() as *const _,
197        chars.len(),
198        &mut raw_value,
199      )
200    })?;
201    Ok(unsafe { JsString::from_raw_unchecked(self.0, raw_value) })
202  }
203
204  pub fn create_symbol_from_js_string(&self, description: JsString) -> Result<JsSymbol> {
205    let mut result = ptr::null_mut();
206    check_status!(unsafe { sys::napi_create_symbol(self.0, description.0.value, &mut result) })?;
207    Ok(unsafe { JsSymbol::from_raw_unchecked(self.0, result) })
208  }
209
210  pub fn create_symbol(&self, description: Option<&str>) -> Result<JsSymbol> {
211    let mut result = ptr::null_mut();
212    check_status!(unsafe {
213      sys::napi_create_symbol(
214        self.0,
215        description
216          .and_then(|desc| self.create_string(desc).ok())
217          .map(|string| string.0.value)
218          .unwrap_or(ptr::null_mut()),
219        &mut result,
220      )
221    })?;
222    Ok(unsafe { JsSymbol::from_raw_unchecked(self.0, result) })
223  }
224
225  pub fn create_object(&self) -> Result<JsObject> {
226    let mut raw_value = ptr::null_mut();
227    check_status!(unsafe { sys::napi_create_object(self.0, &mut raw_value) })?;
228    Ok(unsafe { JsObject::from_raw_unchecked(self.0, raw_value) })
229  }
230
231  pub fn create_empty_array(&self) -> Result<JsObject> {
232    let mut raw_value = ptr::null_mut();
233    check_status!(unsafe { sys::napi_create_array(self.0, &mut raw_value) })?;
234    Ok(unsafe { JsObject::from_raw_unchecked(self.0, raw_value) })
235  }
236
237  pub fn create_array_with_length(&self, length: usize) -> Result<JsObject> {
238    let mut raw_value = ptr::null_mut();
239    check_status!(unsafe { sys::napi_create_array_with_length(self.0, length, &mut raw_value) })?;
240    Ok(unsafe { JsObject::from_raw_unchecked(self.0, raw_value) })
241  }
242
243  /// This API allocates a node::Buffer object. While this is still a fully-supported data structure, in most cases using a TypedArray will suffice.
244  pub fn create_buffer(&self, length: usize) -> Result<JsBufferValue> {
245    let mut raw_value = ptr::null_mut();
246    let mut data_ptr = ptr::null_mut();
247    check_status!(unsafe {
248      sys::napi_create_buffer(self.0, length, &mut data_ptr, &mut raw_value)
249    })?;
250
251    Ok(JsBufferValue::new(
252      JsBuffer(Value {
253        env: self.0,
254        value: raw_value,
255        value_type: ValueType::Object,
256      }),
257      mem::ManuallyDrop::new(unsafe { Vec::from_raw_parts(data_ptr as *mut _, length, length) }),
258    ))
259  }
260
261  /// This API allocates a node::Buffer object and initializes it with data backed by the passed in buffer.
262  ///
263  /// While this is still a fully-supported data structure, in most cases using a TypedArray will suffice.
264  pub fn create_buffer_with_data(&self, mut data: Vec<u8>) -> Result<JsBufferValue> {
265    let length = data.len();
266    let mut raw_value = ptr::null_mut();
267    let data_ptr = data.as_mut_ptr();
268    let hint_ptr = Box::into_raw(Box::new((length, data.capacity())));
269    check_status!(unsafe {
270      if length == 0 {
271        // Rust uses 0x1 as the data pointer for empty buffers,
272        // but NAPI/V8 only allows multiple buffers to have
273        // the same data pointer if it's 0x0.
274        sys::napi_create_buffer(self.0, length, ptr::null_mut(), &mut raw_value)
275      } else {
276        let status = sys::napi_create_external_buffer(
277          self.0,
278          length,
279          data_ptr.cast(),
280          Some(drop_buffer),
281          hint_ptr.cast(),
282          &mut raw_value,
283        );
284        // electron doesn't support external buffers
285        if status == sys::Status::napi_no_external_buffers_allowed {
286          drop(Box::from_raw(hint_ptr));
287          let mut dest_data_ptr = ptr::null_mut();
288          let status = sys::napi_create_buffer_copy(
289            self.0,
290            length,
291            data.as_ptr().cast(),
292            &mut dest_data_ptr,
293            &mut raw_value,
294          );
295          data = Vec::from_raw_parts(dest_data_ptr.cast(), length, length);
296          status
297        } else {
298          status
299        }
300      }
301    })?;
302    Ok(JsBufferValue::new(
303      JsBuffer(Value {
304        env: self.0,
305        value: raw_value,
306        value_type: ValueType::Object,
307      }),
308      mem::ManuallyDrop::new(data),
309    ))
310  }
311
312  /// # Safety
313  /// Mostly the same with `create_buffer_with_data`
314  ///
315  /// Provided `finalize_callback` will be called when `Buffer` got dropped.
316  ///
317  /// You can pass in `noop_finalize` if you have nothing to do in finalize phase.
318  ///
319  /// # Notes
320  ///
321  /// JavaScript may mutate the data passed in to this buffer when writing the buffer.
322  /// However, some JavaScript runtimes do not support external buffers (notably electron!)
323  /// in which case modifications may be lost.
324  ///
325  /// If you need to support these runtimes, you should create a buffer by other means and then
326  /// later copy the data back out.
327  pub unsafe fn create_buffer_with_borrowed_data<Hint, Finalize>(
328    &self,
329    mut data: *mut u8,
330    length: usize,
331    hint: Hint,
332    finalize_callback: Finalize,
333  ) -> Result<JsBufferValue>
334  where
335    Finalize: FnOnce(Hint, Env),
336  {
337    let mut raw_value = ptr::null_mut();
338    if data.is_null() || data as *const u8 == EMPTY_VEC.as_ptr() {
339      return Err(Error::new(
340        Status::InvalidArg,
341        "Borrowed data should not be null".to_owned(),
342      ));
343    }
344    let hint_ptr = Box::into_raw(Box::new((hint, finalize_callback)));
345    unsafe {
346      let status = sys::napi_create_external_buffer(
347        self.0,
348        length,
349        data as *mut c_void,
350        Some(
351          raw_finalize_with_custom_callback::<Hint, Finalize>
352            as unsafe extern "C" fn(
353              env: sys::napi_env,
354              finalize_data: *mut c_void,
355              finalize_hint: *mut c_void,
356            ),
357        ),
358        hint_ptr.cast(),
359        &mut raw_value,
360      );
361      if status == sys::Status::napi_no_external_buffers_allowed {
362        let (hint, finalize) = *Box::from_raw(hint_ptr);
363        let mut result_data = ptr::null_mut();
364        let status = sys::napi_create_buffer_copy(
365          self.0,
366          length,
367          data.cast(),
368          &mut result_data,
369          &mut raw_value,
370        );
371        data = result_data.cast();
372        finalize(hint, *self);
373        check_status!(status)?;
374      } else {
375        check_status!(status)?;
376      }
377    };
378    Ok(JsBufferValue::new(
379      JsBuffer(Value {
380        env: self.0,
381        value: raw_value,
382        value_type: ValueType::Object,
383      }),
384      mem::ManuallyDrop::new(unsafe { Vec::from_raw_parts(data, length, length) }),
385    ))
386  }
387
388  #[cfg(not(target_family = "wasm"))]
389  /// This function gives V8 an indication of the amount of externally allocated memory that is kept alive by JavaScript objects (i.e. a JavaScript object that points to its own memory allocated by a native module).
390  ///
391  /// Registering externally allocated memory will trigger global garbage collections more often than it would otherwise.
392  ///
393  /// ***ATTENTION ⚠️***, do not use this with `create_buffer_with_data/create_arraybuffer_with_data`, since these two functions already called the `adjust_external_memory` internal.
394  pub fn adjust_external_memory(&mut self, size: i64) -> Result<i64> {
395    let mut changed = 0i64;
396    check_status!(unsafe { sys::napi_adjust_external_memory(self.0, size, &mut changed) })?;
397    Ok(changed)
398  }
399
400  #[cfg(target_family = "wasm")]
401  #[allow(unused_variables)]
402  pub fn adjust_external_memory(&mut self, size: i64) -> Result<i64> {
403    Ok(0)
404  }
405
406  /// This API allocates a node::Buffer object and initializes it with data copied from the passed-in buffer.
407  ///
408  /// While this is still a fully-supported data structure, in most cases using a TypedArray will suffice.
409  pub fn create_buffer_copy<D>(&self, data_to_copy: D) -> Result<JsBufferValue>
410  where
411    D: AsRef<[u8]>,
412  {
413    let length = data_to_copy.as_ref().len();
414    let data_ptr = data_to_copy.as_ref().as_ptr();
415    let mut copy_data = ptr::null_mut();
416    let mut raw_value = ptr::null_mut();
417    check_status!(unsafe {
418      sys::napi_create_buffer_copy(
419        self.0,
420        length,
421        data_ptr as *mut c_void,
422        &mut copy_data,
423        &mut raw_value,
424      )
425    })?;
426    Ok(JsBufferValue::new(
427      JsBuffer(Value {
428        env: self.0,
429        value: raw_value,
430        value_type: ValueType::Object,
431      }),
432      mem::ManuallyDrop::new(unsafe { Vec::from_raw_parts(copy_data as *mut u8, length, length) }),
433    ))
434  }
435
436  pub fn create_arraybuffer(&self, length: usize) -> Result<JsArrayBufferValue> {
437    let mut raw_value = ptr::null_mut();
438    let mut data_ptr = ptr::null_mut();
439    check_status!(unsafe {
440      sys::napi_create_arraybuffer(self.0, length, &mut data_ptr, &mut raw_value)
441    })?;
442
443    Ok(JsArrayBufferValue::new(
444      unsafe { JsArrayBuffer::from_raw_unchecked(self.0, raw_value) },
445      data_ptr as *mut c_void,
446      length,
447    ))
448  }
449
450  pub fn create_arraybuffer_with_data(&self, mut data: Vec<u8>) -> Result<JsArrayBufferValue> {
451    let length = data.len();
452    let mut raw_value = ptr::null_mut();
453    let data_ptr = data.as_mut_ptr();
454    check_status!(unsafe {
455      if length == 0 {
456        // Rust uses 0x1 as the data pointer for empty buffers,
457        // but NAPI/V8 only allows multiple buffers to have
458        // the same data pointer if it's 0x0.
459        sys::napi_create_arraybuffer(self.0, length, ptr::null_mut(), &mut raw_value)
460      } else {
461        let hint_ptr = Box::into_raw(Box::new((length, data.capacity())));
462        let status = sys::napi_create_external_arraybuffer(
463          self.0,
464          data_ptr.cast(),
465          length,
466          Some(drop_buffer),
467          hint_ptr.cast(),
468          &mut raw_value,
469        );
470        if status == sys::Status::napi_no_external_buffers_allowed {
471          drop(Box::from_raw(hint_ptr));
472          let mut underlying_data = ptr::null_mut();
473          let status =
474            sys::napi_create_arraybuffer(self.0, length, &mut underlying_data, &mut raw_value);
475          ptr::copy_nonoverlapping(data_ptr, underlying_data.cast(), length);
476          status
477        } else {
478          status
479        }
480      }
481    })?;
482
483    mem::forget(data);
484    Ok(JsArrayBufferValue::new(
485      JsArrayBuffer(Value {
486        env: self.0,
487        value: raw_value,
488        value_type: ValueType::Object,
489      }),
490      data_ptr.cast(),
491      length,
492    ))
493  }
494
495  /// # Safety
496  /// Mostly the same with `create_arraybuffer_with_data`
497  ///
498  /// Provided `finalize_callback` will be called when `Buffer` got dropped.
499  ///
500  /// You can pass in `noop_finalize` if you have nothing to do in finalize phase.
501  ///
502  /// # Notes
503  ///
504  /// JavaScript may mutate the data passed in to this buffer when writing the buffer.
505  /// However, some JavaScript runtimes do not support external buffers (notably electron!)
506  /// in which case modifications may be lost.
507  ///
508  /// If you need to support these runtimes, you should create a buffer by other means and then
509  /// later copy the data back out.
510  pub unsafe fn create_arraybuffer_with_borrowed_data<Hint, Finalize>(
511    &self,
512    data: *mut u8,
513    length: usize,
514    hint: Hint,
515    finalize_callback: Finalize,
516  ) -> Result<JsArrayBufferValue>
517  where
518    Finalize: FnOnce(Hint, Env),
519  {
520    let mut raw_value = ptr::null_mut();
521    let hint_ptr = Box::into_raw(Box::new((hint, finalize_callback)));
522    unsafe {
523      let status = sys::napi_create_external_arraybuffer(
524        self.0,
525        if length == 0 {
526          // Rust uses 0x1 as the data pointer for empty buffers,
527          // but NAPI/V8 only allows multiple buffers to have
528          // the same data pointer if it's 0x0.
529          ptr::null_mut()
530        } else {
531          data as *mut c_void
532        },
533        length,
534        Some(
535          raw_finalize_with_custom_callback::<Hint, Finalize>
536            as unsafe extern "C" fn(
537              env: sys::napi_env,
538              finalize_data: *mut c_void,
539              finalize_hint: *mut c_void,
540            ),
541        ),
542        hint_ptr.cast(),
543        &mut raw_value,
544      );
545      if status == sys::Status::napi_no_external_buffers_allowed {
546        let (hint, finalize) = *Box::from_raw(hint_ptr);
547        let mut underlying_data = ptr::null_mut();
548        let status =
549          sys::napi_create_arraybuffer(self.0, length, &mut underlying_data, &mut raw_value);
550        ptr::copy_nonoverlapping(data, underlying_data.cast(), length);
551        finalize(hint, *self);
552        check_status!(status)?;
553      } else {
554        check_status!(status)?;
555      }
556    };
557    Ok(JsArrayBufferValue::new(
558      JsArrayBuffer(Value {
559        env: self.0,
560        value: raw_value,
561        value_type: ValueType::Object,
562      }),
563      data as *mut c_void,
564      length,
565    ))
566  }
567
568  /// This API allows an add-on author to create a function object in native code.
569  ///
570  /// This is the primary mechanism to allow calling into the add-on's native code from JavaScript.
571  ///
572  /// The newly created function is not automatically visible from script after this call.
573  ///
574  /// Instead, a property must be explicitly set on any object that is visible to JavaScript, in order for the function to be accessible from script.
575  pub fn create_function(&self, name: &str, callback: Callback) -> Result<JsFunction> {
576    let mut raw_result = ptr::null_mut();
577    let len = name.len();
578    let name = CString::new(name)?;
579    check_status!(unsafe {
580      sys::napi_create_function(
581        self.0,
582        name.as_ptr(),
583        len,
584        Some(callback),
585        ptr::null_mut(),
586        &mut raw_result,
587      )
588    })?;
589
590    Ok(unsafe { JsFunction::from_raw_unchecked(self.0, raw_result) })
591  }
592
593  #[cfg(feature = "napi5")]
594  pub fn create_function_from_closure<R, F>(&self, name: &str, callback: F) -> Result<JsFunction>
595  where
596    F: 'static + Fn(crate::CallContext<'_>) -> Result<R>,
597    R: ToNapiValue,
598  {
599    let closure_data_ptr = Box::into_raw(Box::new(callback));
600
601    let mut raw_result = ptr::null_mut();
602    let len = name.len();
603    let name = CString::new(name)?;
604    check_status!(unsafe {
605      sys::napi_create_function(
606        self.0,
607        name.as_ptr(),
608        len,
609        Some(trampoline::<R, F>),
610        closure_data_ptr.cast(), // We let it borrow the data here
611        &mut raw_result,
612      )
613    })?;
614
615    // Note: based on N-API docs, at this point, we have created an effective
616    // `&'static dyn Fn…` in Rust parlance, in that thanks to `Box::into_raw()`
617    // we are sure the context won't be freed, and thus the callback may use
618    // it to call the actual method thanks to the trampoline…
619    // But we thus have a data leak: there is nothing yet responsible for
620    // running the `drop(Box::from_raw(…))` cleanup code.
621    //
622    // To solve that, according to the docs, we need to attach a finalizer:
623    check_status!(unsafe {
624      sys::napi_add_finalizer(
625        self.0,
626        raw_result,
627        closure_data_ptr.cast(),
628        Some(finalize_box_trampoline::<F>),
629        ptr::null_mut(),
630        ptr::null_mut(),
631      )
632    })?;
633
634    Ok(unsafe { JsFunction::from_raw_unchecked(self.0, raw_result) })
635  }
636
637  /// This API retrieves a napi_extended_error_info structure with information about the last error that occurred.
638  ///
639  /// The content of the napi_extended_error_info returned is only valid up until an n-api function is called on the same env.
640  ///
641  /// Do not rely on the content or format of any of the extended information as it is not subject to SemVer and may change at any time. It is intended only for logging purposes.
642  ///
643  /// This API can be called even if there is a pending JavaScript exception.
644  pub fn get_last_error_info(&self) -> Result<ExtendedErrorInfo> {
645    let mut raw_extended_error = ptr::null();
646    check_status!(unsafe { sys::napi_get_last_error_info(self.0, &mut raw_extended_error) })?;
647    unsafe { ptr::read(raw_extended_error) }.try_into()
648  }
649
650  /// Throw any JavaScript value
651  pub fn throw<T: NapiRaw>(&self, value: T) -> Result<()> {
652    check_status!(unsafe { sys::napi_throw(self.0, value.raw()) })
653  }
654
655  /// This API throws a JavaScript Error with the text provided.
656  pub fn throw_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
657    let code = code.and_then(|s| CString::new(s).ok());
658    let msg = CString::new(msg)?;
659    check_status!(unsafe {
660      sys::napi_throw_error(
661        self.0,
662        code.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()),
663        msg.as_ptr(),
664      )
665    })
666  }
667
668  /// This API throws a JavaScript RangeError with the text provided.
669  pub fn throw_range_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
670    let code = code.and_then(|s| CString::new(s).ok());
671    let msg = CString::new(msg)?;
672    check_status!(unsafe {
673      sys::napi_throw_range_error(
674        self.0,
675        code.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()),
676        msg.as_ptr(),
677      )
678    })
679  }
680
681  /// This API throws a JavaScript TypeError with the text provided.
682  pub fn throw_type_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
683    let code = code.and_then(|s| CString::new(s).ok());
684    let msg = CString::new(msg)?;
685    check_status!(unsafe {
686      sys::napi_throw_type_error(
687        self.0,
688        code.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()),
689        msg.as_ptr(),
690      )
691    })
692  }
693
694  /// This API throws a JavaScript SyntaxError with the text provided.
695  #[cfg(feature = "napi9")]
696  pub fn throw_syntax_error<S: AsRef<str>, C: AsRef<str>>(&self, msg: S, code: Option<C>) {
697    use crate::check_status_or_throw;
698
699    let code = code.as_ref().map(|c| c.as_ref()).unwrap_or("");
700    let c_code = CString::new(code).expect("code must be a valid utf-8 string");
701    let code_ptr = c_code.as_ptr();
702    let msg: CString = CString::new(msg.as_ref()).expect("msg must be a valid utf-8 string");
703    let msg_ptr = msg.as_ptr();
704    check_status_or_throw!(
705      self.0,
706      unsafe { sys::node_api_throw_syntax_error(self.0, code_ptr, msg_ptr,) },
707      "Throw syntax error failed"
708    );
709  }
710
711  #[allow(clippy::expect_fun_call)]
712  /// In the event of an unrecoverable error in a native module
713  ///
714  /// A fatal error can be thrown to immediately terminate the process.
715  pub fn fatal_error(self, location: &str, message: &str) {
716    let location_len = location.len();
717    let message_len = message.len();
718    let location =
719      CString::new(location).expect(format!("Convert [{}] to CString failed", location).as_str());
720    let message =
721      CString::new(message).expect(format!("Convert [{}] to CString failed", message).as_str());
722
723    unsafe {
724      sys::napi_fatal_error(
725        location.as_ptr(),
726        location_len,
727        message.as_ptr(),
728        message_len,
729      )
730    }
731  }
732
733  #[cfg(feature = "napi3")]
734  /// Trigger an 'uncaughtException' in JavaScript.
735  ///
736  /// Useful if an async callback throws an exception with no way to recover.
737  pub fn fatal_exception(&self, err: Error) {
738    unsafe {
739      let js_error = JsError::from(err).into_value(self.0);
740      debug_assert!(sys::napi_fatal_exception(self.0, js_error) == sys::Status::napi_ok);
741    };
742  }
743
744  /// Create JavaScript class
745  pub fn define_class(
746    &self,
747    name: &str,
748    constructor_cb: Callback,
749    properties: &[Property],
750  ) -> Result<JsFunction> {
751    let mut raw_result = ptr::null_mut();
752    let raw_properties = properties
753      .iter()
754      .map(|prop| prop.raw())
755      .collect::<Vec<sys::napi_property_descriptor>>();
756    let c_name = CString::new(name)?;
757    check_status!(unsafe {
758      sys::napi_define_class(
759        self.0,
760        c_name.as_ptr() as *const c_char,
761        name.len(),
762        Some(constructor_cb),
763        ptr::null_mut(),
764        raw_properties.len(),
765        raw_properties.as_ptr(),
766        &mut raw_result,
767      )
768    })?;
769
770    Ok(unsafe { JsFunction::from_raw_unchecked(self.0, raw_result) })
771  }
772
773  #[allow(clippy::needless_pass_by_ref_mut)]
774  pub fn wrap<T: 'static>(&self, js_object: &mut JsObject, native_object: T) -> Result<()> {
775    check_status!(unsafe {
776      sys::napi_wrap(
777        self.0,
778        js_object.0.value,
779        Box::into_raw(Box::new(TaggedObject::new(native_object))).cast(),
780        Some(raw_finalize::<T>),
781        ptr::null_mut(),
782        ptr::null_mut(),
783      )
784    })
785  }
786
787  pub fn unwrap<T: 'static>(&self, js_object: &JsObject) -> Result<&mut T> {
788    unsafe {
789      let mut unknown_tagged_object: *mut c_void = ptr::null_mut();
790      check_status!(sys::napi_unwrap(
791        self.0,
792        js_object.0.value,
793        &mut unknown_tagged_object,
794      ))?;
795
796      let type_id = unknown_tagged_object as *const TypeId;
797      if *type_id == TypeId::of::<T>() {
798        let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
799        (*tagged_object).object.as_mut().ok_or_else(|| {
800          Error::new(
801            Status::InvalidArg,
802            "Invalid argument, nothing attach to js_object".to_owned(),
803          )
804        })
805      } else {
806        Err(Error::new(
807          Status::InvalidArg,
808          format!(
809            "Invalid argument, {} on unwrap is not the type of wrapped object",
810            type_name::<T>()
811          ),
812        ))
813      }
814    }
815  }
816
817  pub fn drop_wrapped<T: 'static>(&self, js_object: &JsObject) -> Result<()> {
818    unsafe {
819      let mut unknown_tagged_object = ptr::null_mut();
820      check_status!(sys::napi_remove_wrap(
821        self.0,
822        js_object.0.value,
823        &mut unknown_tagged_object,
824      ))?;
825      let type_id = unknown_tagged_object as *const TypeId;
826      if *type_id == TypeId::of::<T>() {
827        drop(Box::from_raw(unknown_tagged_object as *mut TaggedObject<T>));
828        Ok(())
829      } else {
830        Err(Error::new(
831          Status::InvalidArg,
832          format!(
833            "Invalid argument, {} on unwrap is not the type of wrapped object",
834            type_name::<T>()
835          ),
836        ))
837      }
838    }
839  }
840
841  /// This API create a new reference with the initial 1 ref count to the Object passed in.
842  pub fn create_reference<T>(&self, value: T) -> Result<Ref<()>>
843  where
844    T: NapiRaw,
845  {
846    let mut raw_ref = ptr::null_mut();
847    let initial_ref_count = 1;
848    let raw_value = unsafe { value.raw() };
849    check_status!(unsafe {
850      sys::napi_create_reference(self.0, raw_value, initial_ref_count, &mut raw_ref)
851    })?;
852    Ok(Ref {
853      raw_ref,
854      count: 1,
855      inner: (),
856    })
857  }
858
859  /// This API create a new reference with the specified reference count to the Object passed in.
860  pub fn create_reference_with_refcount<T>(&self, value: T, ref_count: u32) -> Result<Ref<()>>
861  where
862    T: NapiRaw,
863  {
864    let mut raw_ref = ptr::null_mut();
865    let raw_value = unsafe { value.raw() };
866    check_status!(unsafe {
867      sys::napi_create_reference(self.0, raw_value, ref_count, &mut raw_ref)
868    })?;
869    Ok(Ref {
870      raw_ref,
871      count: ref_count,
872      inner: (),
873    })
874  }
875
876  /// Get reference value from `Ref` with type check
877  ///
878  /// Return error if the type of `reference` provided is mismatched with `T`
879  pub fn get_reference_value<T>(&self, reference: &Ref<()>) -> Result<T>
880  where
881    T: NapiValue,
882  {
883    let mut js_value = ptr::null_mut();
884    check_status!(unsafe {
885      sys::napi_get_reference_value(self.0, reference.raw_ref, &mut js_value)
886    })?;
887    unsafe { T::from_raw(self.0, js_value) }
888  }
889
890  /// Get reference value from `Ref` without type check
891  ///
892  /// Using this API if you are sure the type of `T` is matched with provided `Ref<()>`.
893  ///
894  /// If type mismatched, calling `T::method` would return `Err`.
895  pub fn get_reference_value_unchecked<T>(&self, reference: &Ref<()>) -> Result<T>
896  where
897    T: NapiValue,
898  {
899    let mut js_value = ptr::null_mut();
900    check_status!(unsafe {
901      sys::napi_get_reference_value(self.0, reference.raw_ref, &mut js_value)
902    })?;
903    Ok(unsafe { T::from_raw_unchecked(self.0, js_value) })
904  }
905
906  /// If `size_hint` provided, `Env::adjust_external_memory` will be called under the hood.
907  ///
908  /// If no `size_hint` provided, global garbage collections will be triggered less times than expected.
909  ///
910  /// If getting the exact `native_object` size is difficult, you can provide an approximate value, it's only effect to the GC.
911  pub fn create_external<T: 'static>(
912    &self,
913    native_object: T,
914    size_hint: Option<i64>,
915  ) -> Result<JsExternal> {
916    let mut object_value = ptr::null_mut();
917    check_status!(unsafe {
918      sys::napi_create_external(
919        self.0,
920        Box::into_raw(Box::new(TaggedObject::new(native_object))).cast(),
921        Some(raw_finalize::<T>),
922        Box::into_raw(Box::new(size_hint)).cast(),
923        &mut object_value,
924      )
925    })?;
926    if let Some(changed) = size_hint {
927      if changed != 0 {
928        let mut adjusted_value = 0i64;
929        check_status!(unsafe {
930          sys::napi_adjust_external_memory(self.0, changed, &mut adjusted_value)
931        })?;
932      }
933    };
934    Ok(unsafe { JsExternal::from_raw_unchecked(self.0, object_value) })
935  }
936
937  pub fn get_value_external<T: 'static>(&self, js_external: &JsExternal) -> Result<&mut T> {
938    unsafe {
939      let mut unknown_tagged_object = ptr::null_mut();
940      check_status!(sys::napi_get_value_external(
941        self.0,
942        js_external.0.value,
943        &mut unknown_tagged_object,
944      ))?;
945
946      let type_id = unknown_tagged_object as *const TypeId;
947      if *type_id == TypeId::of::<T>() {
948        let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
949        (*tagged_object).object.as_mut().ok_or_else(|| {
950          Error::new(
951            Status::InvalidArg,
952            "nothing attach to js_external".to_owned(),
953          )
954        })
955      } else {
956        Err(Error::new(
957          Status::InvalidArg,
958          "T on get_value_external is not the type of wrapped object".to_owned(),
959        ))
960      }
961    }
962  }
963
964  pub fn create_error(&self, e: Error) -> Result<JsObject> {
965    let reason = &e.reason;
966    let reason_string = self.create_string(reason.as_str())?;
967    let mut result = ptr::null_mut();
968    check_status!(unsafe {
969      sys::napi_create_error(self.0, ptr::null_mut(), reason_string.0.value, &mut result)
970    })?;
971    Ok(unsafe { JsObject::from_raw_unchecked(self.0, result) })
972  }
973
974  /// Run [Task](./trait.Task.html) in libuv thread pool, return [AsyncWorkPromise](./struct.AsyncWorkPromise.html)
975  pub fn spawn<T: 'static + Task>(&self, task: T) -> Result<AsyncWorkPromise> {
976    async_work::run(self.0, task, None)
977  }
978
979  pub fn run_in_scope<T, F>(&self, executor: F) -> Result<T>
980  where
981    F: FnOnce() -> Result<T>,
982  {
983    let mut handle_scope = ptr::null_mut();
984    check_status!(unsafe { sys::napi_open_handle_scope(self.0, &mut handle_scope) })?;
985
986    let result = executor();
987
988    check_status!(unsafe { sys::napi_close_handle_scope(self.0, handle_scope) })?;
989    result
990  }
991
992  /// Node-API provides an API for executing a string containing JavaScript using the underlying JavaScript engine.
993  /// This function executes a string of JavaScript code and returns its result with the following caveats:
994  /// - Unlike `eval`, this function does not allow the script to access the current lexical scope, and therefore also does not allow to access the [module scope](https://nodejs.org/api/modules.html#the-module-scope), meaning that pseudo-globals such as require will not be available.
995  /// - The script can access the [global scope](https://nodejs.org/api/globals.html). Function and `var` declarations in the script will be added to the [global](https://nodejs.org/api/globals.html#global) object. Variable declarations made using `let` and `const` will be visible globally, but will not be added to the global object.
996  /// - The value of this is [global](https://nodejs.org/api/globals.html) within the script.
997  pub fn run_script<S: AsRef<str>, V: FromNapiValue>(&self, script: S) -> Result<V> {
998    let s = self.create_string(script.as_ref())?;
999    let mut raw_value = ptr::null_mut();
1000    check_status!(unsafe { sys::napi_run_script(self.0, s.raw(), &mut raw_value) })?;
1001    unsafe { V::from_napi_value(self.0, raw_value) }
1002  }
1003
1004  /// `process.versions.napi`
1005  pub fn get_napi_version(&self) -> Result<u32> {
1006    let global = self.get_global()?;
1007    let process: JsObject = global.get_named_property("process")?;
1008    let versions: JsObject = process.get_named_property("versions")?;
1009    let napi_version: JsString = versions.get_named_property("napi")?;
1010    napi_version
1011      .into_utf8()?
1012      .as_str()?
1013      .parse()
1014      .map_err(|e| Error::new(Status::InvalidArg, format!("{}", e)))
1015  }
1016
1017  #[cfg(all(feature = "napi2", not(target_family = "wasm")))]
1018  pub fn get_uv_event_loop(&self) -> Result<*mut sys::uv_loop_s> {
1019    let mut uv_loop: *mut sys::uv_loop_s = ptr::null_mut();
1020    check_status!(unsafe { sys::napi_get_uv_event_loop(self.0, &mut uv_loop) })?;
1021    Ok(uv_loop)
1022  }
1023
1024  #[cfg(feature = "napi3")]
1025  pub fn add_env_cleanup_hook<T, F>(
1026    &mut self,
1027    cleanup_data: T,
1028    cleanup_fn: F,
1029  ) -> Result<CleanupEnvHook<T>>
1030  where
1031    T: 'static,
1032    F: 'static + FnOnce(T),
1033  {
1034    let hook = CleanupEnvHookData {
1035      data: cleanup_data,
1036      hook: Box::new(cleanup_fn),
1037    };
1038    let hook_ref = Box::leak(Box::new(hook));
1039    check_status!(unsafe {
1040      sys::napi_add_env_cleanup_hook(
1041        self.0,
1042        Some(cleanup_env::<T>),
1043        hook_ref as *mut CleanupEnvHookData<T> as *mut _,
1044      )
1045    })?;
1046    Ok(CleanupEnvHook(hook_ref))
1047  }
1048
1049  #[cfg(feature = "napi3")]
1050  pub fn remove_env_cleanup_hook<T>(&mut self, hook: CleanupEnvHook<T>) -> Result<()>
1051  where
1052    T: 'static,
1053  {
1054    check_status!(unsafe {
1055      sys::napi_remove_env_cleanup_hook(self.0, Some(cleanup_env::<T>), hook.0 as *mut _)
1056    })
1057  }
1058
1059  #[cfg(feature = "napi4")]
1060  pub fn create_threadsafe_function<
1061    T: Send,
1062    V: ToNapiValue,
1063    R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
1064  >(
1065    &self,
1066    func: &JsFunction,
1067    max_queue_size: usize,
1068    callback: R,
1069  ) -> Result<ThreadsafeFunction<T>> {
1070    ThreadsafeFunction::create(self.0, func.0.value, max_queue_size, callback)
1071  }
1072
1073  #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
1074  pub fn execute_tokio_future<
1075    T: 'static + Send,
1076    V: 'static + ToNapiValue,
1077    F: 'static + Send + Future<Output = Result<T>>,
1078    R: 'static + FnOnce(&mut Env, T) -> Result<V>,
1079  >(
1080    &self,
1081    fut: F,
1082    resolver: R,
1083  ) -> Result<JsObject> {
1084    use crate::tokio_runtime;
1085
1086    let promise = tokio_runtime::execute_tokio_future(self.0, fut, |env, val| unsafe {
1087      resolver(&mut Env::from_raw(env), val).and_then(|v| ToNapiValue::to_napi_value(env, v))
1088    })?;
1089
1090    Ok(unsafe { JsObject::from_raw_unchecked(self.0, promise) })
1091  }
1092
1093  #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
1094  pub fn spawn_future<
1095    T: 'static + Send + ToNapiValue,
1096    F: 'static + Send + Future<Output = Result<T>>,
1097  >(
1098    &self,
1099    fut: F,
1100  ) -> Result<JsObject> {
1101    use crate::tokio_runtime;
1102
1103    let promise = tokio_runtime::execute_tokio_future(self.0, fut, |env, val| unsafe {
1104      ToNapiValue::to_napi_value(env, val)
1105    })?;
1106
1107    Ok(unsafe { JsObject::from_raw_unchecked(self.0, promise) })
1108  }
1109
1110  /// Creates a deferred promise, which can be resolved or rejected from a background thread.
1111  #[cfg(feature = "napi4")]
1112  pub fn create_deferred<Data: ToNapiValue, Resolver: FnOnce(Env) -> Result<Data>>(
1113    &self,
1114  ) -> Result<(JsDeferred<Data, Resolver>, JsObject)> {
1115    JsDeferred::new(self.raw())
1116  }
1117
1118  /// This API does not observe leap seconds; they are ignored, as ECMAScript aligns with POSIX time specification.
1119  ///
1120  /// This API allocates a JavaScript Date object.
1121  ///
1122  /// JavaScript Date objects are described in [Section 20.3](https://tc39.github.io/ecma262/#sec-date-objects) of the ECMAScript Language Specification.
1123  #[cfg(feature = "napi5")]
1124  pub fn create_date(&self, time: f64) -> Result<JsDate> {
1125    let mut js_value = ptr::null_mut();
1126    check_status!(unsafe { sys::napi_create_date(self.0, time, &mut js_value) })?;
1127    Ok(unsafe { JsDate::from_raw_unchecked(self.0, js_value) })
1128  }
1129
1130  #[cfg(feature = "napi6")]
1131
1132  /// This API associates data with the currently running Agent. data can later be retrieved using `Env::get_instance_data()`.
1133  ///
1134  /// 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.
1135  ///
1136  /// If a `finalize_cb` was provided by the previous call, it will not be called.
1137  pub fn set_instance_data<T, Hint, F>(&self, native: T, hint: Hint, finalize_cb: F) -> Result<()>
1138  where
1139    T: 'static,
1140    Hint: 'static,
1141    F: FnOnce(FinalizeContext<T, Hint>),
1142  {
1143    check_status!(unsafe {
1144      sys::napi_set_instance_data(
1145        self.0,
1146        Box::leak(Box::new((TaggedObject::new(native), finalize_cb))) as *mut (TaggedObject<T>, F)
1147          as *mut c_void,
1148        Some(
1149          set_instance_finalize_callback::<T, Hint, F>
1150            as unsafe extern "C" fn(
1151              env: sys::napi_env,
1152              finalize_data: *mut c_void,
1153              finalize_hint: *mut c_void,
1154            ),
1155        ),
1156        Box::leak(Box::new(hint)) as *mut Hint as *mut c_void,
1157      )
1158    })
1159  }
1160
1161  /// This API retrieves data that was previously associated with the currently running Agent via `Env::set_instance_data()`.
1162  ///
1163  /// If no data is set, the call will succeed and data will be set to NULL.
1164  #[cfg(feature = "napi6")]
1165  pub fn get_instance_data<T>(&self) -> Result<Option<&'static mut T>>
1166  where
1167    T: 'static,
1168  {
1169    let mut unknown_tagged_object: *mut c_void = ptr::null_mut();
1170    unsafe {
1171      check_status!(sys::napi_get_instance_data(
1172        self.0,
1173        &mut unknown_tagged_object
1174      ))?;
1175      let type_id = unknown_tagged_object as *const TypeId;
1176      if unknown_tagged_object.is_null() {
1177        return Ok(None);
1178      }
1179      if *type_id == TypeId::of::<T>() {
1180        let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
1181        (*tagged_object).object.as_mut().map(Some).ok_or_else(|| {
1182          Error::new(
1183            Status::InvalidArg,
1184            "Invalid argument, nothing attach to js_object".to_owned(),
1185          )
1186        })
1187      } else {
1188        Err(Error::new(
1189          Status::InvalidArg,
1190          format!(
1191            "Invalid argument, {} on unwrap is not the type of wrapped object",
1192            type_name::<T>()
1193          ),
1194        ))
1195      }
1196    }
1197  }
1198
1199  /// Registers hook, which is a function of type `FnOnce(Arg)`, as a function to be run with the `arg` parameter once the current Node.js environment exits.
1200  ///
1201  /// Unlike [`add_env_cleanup_hook`](https://docs.rs/napi/latest/napi/struct.Env.html#method.add_env_cleanup_hook), the hook is allowed to be asynchronous.
1202  ///
1203  /// Otherwise, behavior generally matches that of [`add_env_cleanup_hook`](https://docs.rs/napi/latest/napi/struct.Env.html#method.add_env_cleanup_hook).
1204  #[cfg(feature = "napi8")]
1205  pub fn add_removable_async_cleanup_hook<Arg, F>(
1206    &self,
1207    arg: Arg,
1208    cleanup_fn: F,
1209  ) -> Result<AsyncCleanupHook>
1210  where
1211    F: FnOnce(Arg),
1212    Arg: 'static,
1213  {
1214    let mut handle = ptr::null_mut();
1215    check_status!(unsafe {
1216      sys::napi_add_async_cleanup_hook(
1217        self.0,
1218        Some(
1219          async_finalize::<Arg, F>
1220            as unsafe extern "C" fn(handle: sys::napi_async_cleanup_hook_handle, data: *mut c_void),
1221        ),
1222        Box::leak(Box::new((arg, cleanup_fn))) as *mut (Arg, F) as *mut c_void,
1223        &mut handle,
1224      )
1225    })?;
1226    Ok(AsyncCleanupHook(handle))
1227  }
1228
1229  /// This API is very similar to [`add_removable_async_cleanup_hook`](https://docs.rs/napi/latest/napi/struct.Env.html#method.add_removable_async_cleanup_hook)
1230  ///
1231  /// Use this one if you don't want remove the cleanup hook anymore.
1232  #[cfg(feature = "napi8")]
1233  pub fn add_async_cleanup_hook<Arg, F>(&self, arg: Arg, cleanup_fn: F) -> Result<()>
1234  where
1235    F: FnOnce(Arg),
1236    Arg: 'static,
1237  {
1238    check_status!(unsafe {
1239      sys::napi_add_async_cleanup_hook(
1240        self.0,
1241        Some(
1242          async_finalize::<Arg, F>
1243            as unsafe extern "C" fn(handle: sys::napi_async_cleanup_hook_handle, data: *mut c_void),
1244        ),
1245        Box::leak(Box::new((arg, cleanup_fn))) as *mut (Arg, F) as *mut c_void,
1246        ptr::null_mut(),
1247      )
1248    })
1249  }
1250
1251  #[cfg(feature = "napi9")]
1252  pub fn symbol_for(&self, description: &str) -> Result<JsSymbol> {
1253    let mut result = ptr::null_mut();
1254    let len = description.len();
1255    let description = CString::new(description)?;
1256    check_status!(unsafe {
1257      sys::node_api_symbol_for(self.0, description.as_ptr(), len, &mut result)
1258    })?;
1259
1260    Ok(unsafe { JsSymbol::from_raw_unchecked(self.0, result) })
1261  }
1262
1263  #[cfg(feature = "napi9")]
1264  /// This API retrieves the file path of the currently running JS module as a URL. For a file on
1265  /// the local file system it will start with `file://`.
1266  ///
1267  /// # Errors
1268  ///
1269  /// The retrieved string may be empty if the add-on loading process fails to establish the
1270  /// add-on's file name.
1271  pub fn get_module_file_name(&self) -> Result<String> {
1272    let mut char_ptr = ptr::null();
1273    check_status!(
1274      unsafe { sys::node_api_get_module_file_name(self.0, &mut char_ptr) },
1275      "call node_api_get_module_file_name failed"
1276    )?;
1277    // SAFETY: This is safe because `char_ptr` is guaranteed to not be `null`, and point to
1278    // null-terminated string data.
1279    let module_filename = unsafe { std::ffi::CStr::from_ptr(char_ptr) };
1280
1281    Ok(module_filename.to_string_lossy().into_owned())
1282  }
1283
1284  /// ### Serialize `Rust Struct` into `JavaScript Value`
1285  ///
1286  /// ```
1287  /// #[derive(Serialize, Debug, Deserialize)]
1288  /// struct AnObject {
1289  ///     a: u32,
1290  ///     b: Vec<f64>,
1291  ///     c: String,
1292  /// }
1293  ///
1294  /// #[js_function]
1295  /// fn serialize(ctx: CallContext) -> Result<JsUnknown> {
1296  ///     let value = AnyObject { a: 1, b: vec![0.1, 2.22], c: "hello" };
1297  ///     ctx.env.to_js_value(&value)
1298  /// }
1299  /// ```
1300  #[cfg(feature = "serde-json")]
1301  #[allow(clippy::wrong_self_convention)]
1302  pub fn to_js_value<T>(&self, node: &T) -> Result<JsUnknown>
1303  where
1304    T: Serialize,
1305  {
1306    let s = Ser(self);
1307    node.serialize(s).map(JsUnknown)
1308  }
1309
1310  /// ### Deserialize data from `JsValue`
1311  /// ```
1312  /// #[derive(Serialize, Debug, Deserialize)]
1313  /// struct AnObject {
1314  ///     a: u32,
1315  ///     b: Vec<f64>,
1316  ///     c: String,
1317  /// }
1318  ///
1319  /// #[js_function(1)]
1320  /// fn deserialize_from_js(ctx: CallContext) -> Result<JsUndefined> {
1321  ///     let arg0 = ctx.get::<JsUnknown>(0)?;
1322  ///     let de_serialized: AnObject = ctx.env.from_js_value(arg0)?;
1323  ///     ...
1324  /// }
1325  ///
1326  #[cfg(feature = "serde-json")]
1327  pub fn from_js_value<T, V>(&self, value: V) -> Result<T>
1328  where
1329    T: DeserializeOwned,
1330    V: NapiRaw,
1331  {
1332    let value = Value {
1333      env: self.0,
1334      value: unsafe { value.raw() },
1335      value_type: ValueType::Unknown,
1336    };
1337    let mut de = De(&value);
1338    T::deserialize(&mut de)
1339  }
1340
1341  /// This API represents the invocation of the Strict Equality algorithm as defined in [Section 7.2.14](https://tc39.es/ecma262/#sec-strict-equality-comparison) of the ECMAScript Language Specification.
1342  pub fn strict_equals<A: NapiRaw, B: NapiRaw>(&self, a: A, b: B) -> Result<bool> {
1343    let mut result = false;
1344    check_status!(unsafe { sys::napi_strict_equals(self.0, a.raw(), b.raw(), &mut result) })?;
1345    Ok(result)
1346  }
1347
1348  pub fn get_node_version(&self) -> Result<NodeVersion> {
1349    let mut result = ptr::null();
1350    check_status!(unsafe { sys::napi_get_node_version(self.0, &mut result) })?;
1351    let version = unsafe { *result };
1352    version.try_into()
1353  }
1354
1355  /// get raw env ptr
1356  pub fn raw(&self) -> sys::napi_env {
1357    self.0
1358  }
1359}
1360
1361/// This function could be used for `create_buffer_with_borrowed_data` and want do noting when Buffer finalized.
1362pub fn noop_finalize<Hint>(_hint: Hint, _env: Env) {}
1363
1364unsafe extern "C" fn drop_buffer(
1365  _env: sys::napi_env,
1366  finalize_data: *mut c_void,
1367  hint: *mut c_void,
1368) {
1369  let length_ptr = hint as *mut (usize, usize);
1370  let (length, cap) = unsafe { *Box::from_raw(length_ptr) };
1371  mem::drop(unsafe { Vec::from_raw_parts(finalize_data as *mut u8, length, cap) });
1372}
1373
1374pub(crate) unsafe extern "C" fn raw_finalize<T>(
1375  env: sys::napi_env,
1376  finalize_data: *mut c_void,
1377  finalize_hint: *mut c_void,
1378) {
1379  let tagged_object = finalize_data as *mut TaggedObject<T>;
1380  drop(unsafe { Box::from_raw(tagged_object) });
1381  #[cfg(not(target_family = "wasm"))]
1382  if !finalize_hint.is_null() {
1383    let size_hint = unsafe { *Box::from_raw(finalize_hint as *mut Option<i64>) };
1384    if let Some(changed) = size_hint {
1385      if changed != 0 {
1386        let mut adjusted = 0i64;
1387        let status = unsafe { sys::napi_adjust_external_memory(env, -changed, &mut adjusted) };
1388        debug_assert!(
1389          status == sys::Status::napi_ok,
1390          "Calling napi_adjust_external_memory failed"
1391        );
1392      }
1393    };
1394  }
1395}
1396
1397#[cfg(feature = "napi6")]
1398unsafe extern "C" fn set_instance_finalize_callback<T, Hint, F>(
1399  raw_env: sys::napi_env,
1400  finalize_data: *mut c_void,
1401  finalize_hint: *mut c_void,
1402) where
1403  T: 'static,
1404  Hint: 'static,
1405  F: FnOnce(FinalizeContext<T, Hint>),
1406{
1407  let (value, callback) = unsafe { *Box::from_raw(finalize_data as *mut (TaggedObject<T>, F)) };
1408  let hint = unsafe { *Box::from_raw(finalize_hint as *mut Hint) };
1409  let env = unsafe { Env::from_raw(raw_env) };
1410  callback(FinalizeContext {
1411    value: value.object.unwrap(),
1412    hint,
1413    env,
1414  });
1415}
1416
1417#[cfg(feature = "napi3")]
1418unsafe extern "C" fn cleanup_env<T: 'static>(hook_data: *mut c_void) {
1419  let cleanup_env_hook = unsafe { Box::from_raw(hook_data as *mut CleanupEnvHookData<T>) };
1420  (cleanup_env_hook.hook)(cleanup_env_hook.data);
1421}
1422
1423unsafe extern "C" fn raw_finalize_with_custom_callback<Hint, Finalize>(
1424  env: sys::napi_env,
1425  _finalize_data: *mut c_void,
1426  finalize_hint: *mut c_void,
1427) where
1428  Finalize: FnOnce(Hint, Env),
1429{
1430  let (hint, callback) = unsafe { *Box::from_raw(finalize_hint as *mut (Hint, Finalize)) };
1431  callback(hint, unsafe { Env::from_raw(env) });
1432}
1433
1434#[cfg(feature = "napi8")]
1435unsafe extern "C" fn async_finalize<Arg, F>(
1436  handle: sys::napi_async_cleanup_hook_handle,
1437  data: *mut c_void,
1438) where
1439  Arg: 'static,
1440  F: FnOnce(Arg),
1441{
1442  let (arg, callback) = unsafe { *Box::from_raw(data as *mut (Arg, F)) };
1443  callback(arg);
1444  if !handle.is_null() {
1445    let status = unsafe { sys::napi_remove_async_cleanup_hook(handle) };
1446    assert!(
1447      status == sys::Status::napi_ok,
1448      "Remove async cleanup hook failed after async cleanup callback"
1449    );
1450  }
1451}
1452
1453#[cfg(feature = "napi5")]
1454pub(crate) unsafe extern "C" fn trampoline<
1455  R: ToNapiValue,
1456  F: Fn(crate::CallContext) -> Result<R>,
1457>(
1458  raw_env: sys::napi_env,
1459  cb_info: sys::napi_callback_info,
1460) -> sys::napi_value {
1461  use crate::CallContext;
1462
1463  let (raw_this, raw_args, closure_data_ptr, argc) = {
1464    // Fast path for 4 arguments or less.
1465    let mut argc = 4;
1466    let mut raw_args = Vec::with_capacity(4);
1467    let mut raw_this = ptr::null_mut();
1468    let mut closure_data_ptr = ptr::null_mut();
1469
1470    let status = unsafe {
1471      sys::napi_get_cb_info(
1472        raw_env,
1473        cb_info,
1474        &mut argc,
1475        raw_args.as_mut_ptr(),
1476        &mut raw_this,
1477        &mut closure_data_ptr,
1478      )
1479    };
1480    debug_assert!(
1481      Status::from(status) == Status::Ok,
1482      "napi_get_cb_info failed"
1483    );
1484
1485    // Arguments length greater than 4, resize the vector.
1486    if argc > 4 {
1487      raw_args = vec![ptr::null_mut(); argc];
1488      let status = unsafe {
1489        sys::napi_get_cb_info(
1490          raw_env,
1491          cb_info,
1492          &mut argc,
1493          raw_args.as_mut_ptr(),
1494          &mut raw_this,
1495          &mut closure_data_ptr,
1496        )
1497      };
1498      debug_assert!(
1499        Status::from(status) == Status::Ok,
1500        "napi_get_cb_info failed"
1501      );
1502    } else {
1503      unsafe { raw_args.set_len(argc) };
1504    }
1505
1506    (raw_this, raw_args, closure_data_ptr, argc)
1507  };
1508
1509  let closure: &F = Box::leak(unsafe { Box::from_raw(closure_data_ptr.cast()) });
1510  let mut env = unsafe { Env::from_raw(raw_env) };
1511  let call_context = CallContext::new(&mut env, cb_info, raw_this, raw_args.as_slice(), argc);
1512  closure(call_context)
1513    .and_then(|ret: R| unsafe { <R as ToNapiValue>::to_napi_value(env.0, ret) })
1514    .unwrap_or_else(|e| {
1515      unsafe { JsError::from(e).throw_into(raw_env) };
1516      ptr::null_mut()
1517    })
1518}
1519
1520#[cfg(feature = "napi5")]
1521pub(crate) unsafe extern "C" fn trampoline_setter<
1522  V: FromNapiValue,
1523  F: Fn(Env, crate::bindgen_runtime::Object, V) -> Result<()>,
1524>(
1525  raw_env: sys::napi_env,
1526  cb_info: sys::napi_callback_info,
1527) -> sys::napi_value {
1528  use crate::bindgen_runtime::Object;
1529
1530  let (raw_args, raw_this, closure_data_ptr) = {
1531    let mut argc = 1;
1532    let mut raw_args = vec![ptr::null_mut(); 1];
1533    let mut raw_this = ptr::null_mut();
1534    let mut data_ptr = ptr::null_mut();
1535
1536    let status = unsafe {
1537      sys::napi_get_cb_info(
1538        raw_env,
1539        cb_info,
1540        &mut argc,
1541        raw_args.as_mut_ptr(),
1542        &mut raw_this,
1543        &mut data_ptr,
1544      )
1545    };
1546    unsafe { raw_args.set_len(argc) };
1547    debug_assert!(
1548      Status::from(status) == Status::Ok,
1549      "napi_get_cb_info failed"
1550    );
1551
1552    let closure_data_ptr = unsafe { *(data_ptr as *mut PropertyClosures) }.setter_closure;
1553    (raw_args, raw_this, closure_data_ptr)
1554  };
1555
1556  let closure: &F = Box::leak(unsafe { Box::from_raw(closure_data_ptr.cast()) });
1557  let env = unsafe { Env::from_raw(raw_env) };
1558  raw_args
1559    .first()
1560    .ok_or_else(|| Error::new(Status::InvalidArg, "Missing argument in property setter"))
1561    .and_then(|value| unsafe { V::from_napi_value(raw_env, *value) })
1562    .and_then(|value| {
1563      closure(
1564        env,
1565        unsafe { Object::from_raw_unchecked(raw_env, raw_this) },
1566        value,
1567      )
1568    })
1569    .map(|_| std::ptr::null_mut())
1570    .unwrap_or_else(|e| {
1571      unsafe { JsError::from(e).throw_into(raw_env) };
1572      ptr::null_mut()
1573    })
1574}
1575
1576#[cfg(feature = "napi5")]
1577pub(crate) unsafe extern "C" fn trampoline_getter<
1578  R: ToNapiValue,
1579  F: Fn(Env, crate::bindgen_runtime::This) -> Result<R>,
1580>(
1581  raw_env: sys::napi_env,
1582  cb_info: sys::napi_callback_info,
1583) -> sys::napi_value {
1584  let (raw_this, closure_data_ptr) = {
1585    let mut raw_this = ptr::null_mut();
1586    let mut data_ptr = ptr::null_mut();
1587
1588    let status = unsafe {
1589      sys::napi_get_cb_info(
1590        raw_env,
1591        cb_info,
1592        &mut 0,
1593        ptr::null_mut(),
1594        &mut raw_this,
1595        &mut data_ptr,
1596      )
1597    };
1598    debug_assert!(
1599      Status::from(status) == Status::Ok,
1600      "napi_get_cb_info failed"
1601    );
1602
1603    let closure_data_ptr = unsafe { *(data_ptr as *mut PropertyClosures) }.getter_closure;
1604    (raw_this, closure_data_ptr)
1605  };
1606
1607  let closure: &F = Box::leak(unsafe { Box::from_raw(closure_data_ptr.cast()) });
1608  let env = unsafe { Env::from_raw(raw_env) };
1609  closure(env, unsafe {
1610    crate::bindgen_runtime::Object::from_raw_unchecked(raw_env, raw_this)
1611  })
1612  .and_then(|ret: R| unsafe { <R as ToNapiValue>::to_napi_value(env.0, ret) })
1613  .unwrap_or_else(|e| {
1614    unsafe { JsError::from(e).throw_into(raw_env) };
1615    ptr::null_mut()
1616  })
1617}
1618
1619#[cfg(feature = "napi5")]
1620pub(crate) unsafe extern "C" fn finalize_box_trampoline<F>(
1621  _raw_env: sys::napi_env,
1622  closure_data_ptr: *mut c_void,
1623  _finalize_hint: *mut c_void,
1624) {
1625  drop(unsafe { Box::<F>::from_raw(closure_data_ptr.cast()) })
1626}