napi/
env.rs

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