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    if length == 0 {
501      // Rust uses 0x1 as the data pointer for empty buffers,
502      // but NAPI/V8 only allows multiple buffers to have
503      // the same data pointer if it's 0x0.
504      check_status!(
505        unsafe { sys::napi_create_arraybuffer(self.0, length, ptr::null_mut(), &mut raw_value) },
506        "Failed to create arraybuffer"
507      )?;
508    } else {
509      let hint_ptr = Box::into_raw(Box::new((length, data.capacity())));
510      let mut status = unsafe {
511        sys::napi_create_external_arraybuffer(
512          self.0,
513          data_ptr.cast(),
514          length,
515          Some(drop_buffer),
516          hint_ptr.cast(),
517          &mut raw_value,
518        )
519      };
520      if status == sys::Status::napi_no_external_buffers_allowed {
521        unsafe { drop(Box::from_raw(hint_ptr)) };
522        let mut underlying_data = ptr::null_mut();
523        status = unsafe {
524          sys::napi_create_arraybuffer(self.0, length, &mut underlying_data, &mut raw_value)
525        };
526        check_status!(status, "Failed to create arraybuffer")?;
527        if length > 0 {
528          unsafe { ptr::copy_nonoverlapping(data_ptr, underlying_data.cast(), length) };
529        }
530      } else {
531        check_status!(status, "Failed to create arraybuffer")?;
532      }
533    }
534
535    mem::forget(data);
536    Ok(JsArrayBufferValue::new(
537      JsArrayBuffer(Value {
538        env: self.0,
539        value: raw_value,
540        value_type: ValueType::Object,
541      }),
542      data_ptr.cast(),
543      length,
544    ))
545  }
546
547  #[cfg(feature = "compat-mode")]
548  #[deprecated(since = "3.0.0", note = "Use `ArrayBuffer::from_external` instead")]
549  /// # Safety
550  /// Mostly the same with `create_arraybuffer_with_data`
551  ///
552  /// Provided `finalize_callback` will be called when `Buffer` got dropped.
553  ///
554  /// You can pass in `noop_finalize` if you have nothing to do in finalize phase.
555  ///
556  /// # Notes
557  ///
558  /// JavaScript may mutate the data passed in to this buffer when writing the buffer.
559  /// However, some JavaScript runtimes do not support external buffers (notably electron!)
560  /// in which case modifications may be lost.
561  ///
562  /// If you need to support these runtimes, you should create a buffer by other means and then
563  /// later copy the data back out.
564  pub unsafe fn create_arraybuffer_with_borrowed_data<Hint, Finalize>(
565    &self,
566    data: *mut u8,
567    length: usize,
568    hint: Hint,
569    finalize_callback: Finalize,
570  ) -> Result<JsArrayBufferValue>
571  where
572    Finalize: FnOnce(Env, Hint),
573  {
574    let mut raw_value = ptr::null_mut();
575    let hint_ptr = Box::into_raw(Box::new((hint, finalize_callback)));
576    unsafe {
577      let status = sys::napi_create_external_arraybuffer(
578        self.0,
579        if length == 0 {
580          // Rust uses 0x1 as the data pointer for empty buffers,
581          // but NAPI/V8 only allows multiple buffers to have
582          // the same data pointer if it's 0x0.
583          ptr::null_mut()
584        } else {
585          data as *mut c_void
586        },
587        length,
588        Some(
589          raw_finalize_with_custom_callback::<Hint, Finalize>
590            as unsafe extern "C" fn(
591              env: sys::napi_env,
592              finalize_data: *mut c_void,
593              finalize_hint: *mut c_void,
594            ),
595        ),
596        hint_ptr.cast(),
597        &mut raw_value,
598      );
599      if status == sys::Status::napi_no_external_buffers_allowed {
600        let (hint, finalize) = *Box::from_raw(hint_ptr);
601        let mut underlying_data = ptr::null_mut();
602        let status =
603          sys::napi_create_arraybuffer(self.0, length, &mut underlying_data, &mut raw_value);
604        // Copy data before calling finalize, since finalize may free the source data
605        if status == sys::Status::napi_ok && length > 0 {
606          ptr::copy_nonoverlapping(data, underlying_data.cast(), length);
607        }
608        // Always call finalize to clean up caller's resources, even on error
609        finalize(*self, hint);
610        check_status!(status, "Failed to create arraybuffer")?;
611      } else {
612        check_status!(status)?;
613      }
614    };
615    Ok(JsArrayBufferValue::new(
616      JsArrayBuffer(Value {
617        env: self.0,
618        value: raw_value,
619        value_type: ValueType::Object,
620      }),
621      data as *mut c_void,
622      length,
623    ))
624  }
625
626  /// This API allows an add-on author to create a function object in native code.
627  ///
628  /// This is the primary mechanism to allow calling into the add-on's native code from JavaScript.
629  ///
630  /// The newly created function is not automatically visible from script after this call.
631  ///
632  /// 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.
633  pub fn create_function<Args: JsValuesTupleIntoVec, Return>(
634    &self,
635    name: &str,
636    callback: Callback,
637  ) -> Result<Function<'_, Args, Return>> {
638    let mut raw_result = ptr::null_mut();
639    let len = name.len();
640    check_status!(unsafe {
641      sys::napi_create_function(
642        self.0,
643        name.as_ptr().cast(),
644        len as isize,
645        Some(callback),
646        ptr::null_mut(),
647        &mut raw_result,
648      )
649    })?;
650
651    unsafe { Function::<Args, Return>::from_napi_value(self.0, raw_result) }
652  }
653
654  #[cfg(feature = "napi5")]
655  pub fn create_function_from_closure<Args: JsValuesTupleIntoVec, Return, F>(
656    &self,
657    name: &str,
658    callback: F,
659  ) -> Result<Function<'_, Args, Return>>
660  where
661    Return: ToNapiValue,
662    F: 'static + Fn(FunctionCallContext) -> Result<Return>,
663  {
664    let closure_data_ptr = Box::into_raw(Box::new(callback));
665
666    let mut raw_result = ptr::null_mut();
667    let len = name.len();
668    check_status!(unsafe {
669      sys::napi_create_function(
670        self.0,
671        name.as_ptr().cast(),
672        len as isize,
673        Some(trampoline::<Return, F>),
674        closure_data_ptr.cast(), // We let it borrow the data here
675        &mut raw_result,
676      )
677    })?;
678
679    // Note: based on N-API docs, at this point, we have created an effective
680    // `&'static dyn Fn…` in Rust parlance, in that thanks to `Box::into_raw()`
681    // we are sure the context won't be freed, and thus the callback may use
682    // it to call the actual method thanks to the trampoline…
683    // But we thus have a data leak: there is nothing yet responsible for
684    // running the `drop(Box::from_raw(…))` cleanup code.
685    //
686    // To solve that, according to the docs, we need to attach a finalizer:
687    check_status!(unsafe {
688      sys::napi_add_finalizer(
689        self.0,
690        raw_result,
691        closure_data_ptr.cast(),
692        Some(finalize_box_trampoline::<F>),
693        ptr::null_mut(),
694        ptr::null_mut(),
695      )
696    })?;
697
698    unsafe { Function::from_napi_value(self.0, raw_result) }
699  }
700
701  /// This API retrieves a napi_extended_error_info structure with information about the last error that occurred.
702  ///
703  /// The content of the napi_extended_error_info returned is only valid up until an n-api function is called on the same env.
704  ///
705  /// 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.
706  ///
707  /// This API can be called even if there is a pending JavaScript exception.
708  pub fn get_last_error_info(&self) -> Result<ExtendedErrorInfo> {
709    let mut raw_extended_error = ptr::null();
710    check_status!(unsafe { sys::napi_get_last_error_info(self.0, &mut raw_extended_error) })?;
711    unsafe { ptr::read(raw_extended_error) }.try_into()
712  }
713
714  /// Throw any JavaScript value
715  pub fn throw<T: ToNapiValue>(&self, value: T) -> Result<()> {
716    check_status!(unsafe { sys::napi_throw(self.0, ToNapiValue::to_napi_value(self.0, value)?,) })
717  }
718
719  /// This API throws a JavaScript Error with the text provided.
720  pub fn throw_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
721    let code = code.and_then(|s| CString::new(s).ok());
722    let msg = CString::new(msg)?;
723    check_status!(unsafe {
724      sys::napi_throw_error(
725        self.0,
726        code.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()),
727        msg.as_ptr(),
728      )
729    })
730  }
731
732  /// This API throws a JavaScript RangeError with the text provided.
733  pub fn throw_range_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
734    let code = code.and_then(|s| CString::new(s).ok());
735    let msg = CString::new(msg)?;
736    check_status!(unsafe {
737      sys::napi_throw_range_error(
738        self.0,
739        code.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()),
740        msg.as_ptr(),
741      )
742    })
743  }
744
745  /// This API throws a JavaScript TypeError with the text provided.
746  pub fn throw_type_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
747    let code = code.and_then(|s| CString::new(s).ok());
748    let msg = CString::new(msg)?;
749    check_status!(unsafe {
750      sys::napi_throw_type_error(
751        self.0,
752        code.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()),
753        msg.as_ptr(),
754      )
755    })
756  }
757
758  /// This API throws a JavaScript SyntaxError with the text provided.
759  #[cfg(feature = "napi9")]
760  pub fn throw_syntax_error<S: AsRef<str>, C: AsRef<str>>(&self, msg: S, code: Option<C>) {
761    use crate::check_status_or_throw;
762
763    let code = code.as_ref().map(|c| c.as_ref()).unwrap_or("");
764    let c_code = CString::new(code).expect("code must be a valid utf-8 string");
765    let code_ptr = c_code.as_ptr();
766    let msg: CString = CString::new(msg.as_ref()).expect("msg must be a valid utf-8 string");
767    let msg_ptr = msg.as_ptr();
768    check_status_or_throw!(
769      self.0,
770      unsafe { sys::node_api_throw_syntax_error(self.0, code_ptr, msg_ptr,) },
771      "Throw syntax error failed"
772    );
773  }
774
775  #[allow(clippy::expect_fun_call)]
776  /// In the event of an unrecoverable error in a native module
777  ///
778  /// A fatal error can be thrown to immediately terminate the process.
779  pub fn fatal_error(self, location: &str, message: &str) {
780    let location_len = location.len();
781    let message_len = message.len();
782
783    unsafe {
784      sys::napi_fatal_error(
785        location.as_ptr().cast(),
786        location_len as isize,
787        message.as_ptr().cast(),
788        message_len as isize,
789      )
790    }
791  }
792
793  #[cfg(feature = "napi3")]
794  /// Trigger an 'uncaughtException' in JavaScript.
795  ///
796  /// Useful if an async callback throws an exception with no way to recover.
797  pub fn fatal_exception(&self, err: Error) {
798    unsafe {
799      let js_error = JsError::from(err).into_value(self.0);
800      debug_assert!(sys::napi_fatal_exception(self.0, js_error) == sys::Status::napi_ok);
801    };
802  }
803
804  /// Create JavaScript class
805  pub fn define_class<Args: JsValuesTupleIntoVec>(
806    &self,
807    name: &str,
808    constructor_cb: Callback,
809    properties: &[Property],
810  ) -> Result<Function<'_, Args, Unknown<'_>>> {
811    let mut raw_result = ptr::null_mut();
812    let raw_properties = properties
813      .iter()
814      .map(|prop| prop.raw())
815      .collect::<Vec<sys::napi_property_descriptor>>();
816    check_status!(unsafe {
817      sys::napi_define_class(
818        self.0,
819        name.as_ptr().cast(),
820        name.len() as isize,
821        Some(constructor_cb),
822        ptr::null_mut(),
823        raw_properties.len(),
824        raw_properties.as_ptr(),
825        &mut raw_result,
826      )
827    })?;
828
829    unsafe { Function::from_napi_value(self.0, raw_result) }
830  }
831
832  #[cfg(feature = "compat-mode")]
833  #[deprecated(since = "3.0.0", note = "Please use `JsObjectValue::wrap` instead")]
834  #[allow(clippy::needless_pass_by_ref_mut)]
835  pub fn wrap<T: 'static>(
836    &self,
837    js_object: &mut JsObject,
838    native_object: T,
839    size_hint: Option<usize>,
840  ) -> Result<()> {
841    check_status!(unsafe {
842      sys::napi_wrap(
843        self.0,
844        js_object.0.value,
845        Box::into_raw(Box::new(TaggedObject::new(native_object))).cast(),
846        Some(raw_finalize::<TaggedObject<T>>),
847        Box::into_raw(Box::new(size_hint.unwrap_or(0) as i64)).cast(),
848        ptr::null_mut(),
849      )
850    })
851  }
852
853  #[cfg(feature = "compat-mode")]
854  #[deprecated(since = "3.0.0", note = "Please use `JsObjectValue::unwrap` instead")]
855  #[allow(clippy::mut_from_ref)]
856  pub fn unwrap<T: 'static>(&self, js_object: &JsObject) -> Result<&mut T> {
857    unsafe {
858      let mut unknown_tagged_object: *mut c_void = ptr::null_mut();
859      check_status!(sys::napi_unwrap(
860        self.0,
861        js_object.0.value,
862        &mut unknown_tagged_object,
863      ))?;
864
865      let type_id = unknown_tagged_object as *const TypeId;
866      if *type_id == TypeId::of::<T>() {
867        let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
868        (*tagged_object).object.as_mut().ok_or_else(|| {
869          Error::new(
870            Status::InvalidArg,
871            "Invalid argument, nothing attach to js_object".to_owned(),
872          )
873        })
874      } else {
875        Err(Error::new(
876          Status::InvalidArg,
877          format!(
878            "Invalid argument, {} on unwrap is not the type of wrapped object",
879            type_name::<T>()
880          ),
881        ))
882      }
883    }
884  }
885
886  #[cfg(feature = "compat-mode")]
887  #[deprecated(
888    since = "3.0.0",
889    note = "Please use `JsObjectValue::drop_wrapped` instead"
890  )]
891  pub fn drop_wrapped<T: 'static>(&self, js_object: &JsObject) -> Result<()> {
892    unsafe {
893      let mut unknown_tagged_object = ptr::null_mut();
894      check_status!(sys::napi_remove_wrap(
895        self.0,
896        js_object.0.value,
897        &mut unknown_tagged_object,
898      ))?;
899      let type_id = unknown_tagged_object as *const TypeId;
900      if *type_id == TypeId::of::<T>() {
901        drop(Box::from_raw(unknown_tagged_object as *mut TaggedObject<T>));
902        Ok(())
903      } else {
904        Err(Error::new(
905          Status::InvalidArg,
906          format!(
907            "Invalid argument, {} on unwrap is not the type of wrapped object",
908            type_name::<T>()
909          ),
910        ))
911      }
912    }
913  }
914
915  #[cfg(feature = "compat-mode")]
916  #[deprecated(since = "3.0.0", note = "Please use `Ref::new` instead")]
917  /// This API create a new reference with the initial 1 ref count to the Object passed in.
918  pub fn create_reference<'env, T>(&self, value: &T) -> Result<Ref<T>>
919  where
920    T: JsValue<'env>,
921  {
922    Ref::new(self, value)
923  }
924
925  #[cfg(feature = "compat-mode")]
926  #[deprecated(since = "3.0.0", note = "Please use `Ref::get_value` instead")]
927  /// Get reference value from `Ref` with type check
928  pub fn get_reference_value<T>(&self, reference: &Ref<T>) -> Result<T>
929  where
930    T: FromNapiValue,
931  {
932    let mut js_value = ptr::null_mut();
933    check_status!(unsafe {
934      sys::napi_get_reference_value(self.0, reference.raw_ref, &mut js_value)
935    })?;
936    unsafe { T::from_napi_value(self.0, js_value) }
937  }
938
939  #[cfg(feature = "compat-mode")]
940  #[deprecated(since = "3.0.0", note = "Please use `ObjectRef::get_value` instead")]
941  /// Get reference value from `Ref` without type check
942  ///
943  /// Using this API if you are sure the type of `T` is matched with provided `Ref<()>`.
944  ///
945  /// If type mismatched, calling `T::method` would return `Err`.
946  pub fn get_reference_value_unchecked<T>(&self, reference: &Ref<T>) -> Result<T>
947  where
948    T: FromNapiValue,
949  {
950    let mut js_value = ptr::null_mut();
951    check_status!(unsafe {
952      sys::napi_get_reference_value(self.0, reference.raw_ref, &mut js_value)
953    })?;
954    unsafe { T::from_napi_value(self.0, js_value) }
955  }
956
957  #[cfg(feature = "compat-mode")]
958  #[deprecated(since = "3.0.0", note = "Please use `External::new` instead")]
959  /// If `size_hint` provided, `Env::adjust_external_memory` will be called under the hood.
960  ///
961  /// If no `size_hint` provided, global garbage collections will be triggered less times than expected.
962  ///
963  /// If getting the exact `native_object` size is difficult, you can provide an approximate value, it's only effect to the GC.
964  pub fn create_external<'env, T: 'static>(
965    &'env self,
966    native_object: T,
967    size_hint: Option<i64>,
968  ) -> Result<JsExternal<'env>> {
969    let mut object_value = ptr::null_mut();
970    check_status!(unsafe {
971      sys::napi_create_external(
972        self.0,
973        Box::into_raw(Box::new(TaggedObject::new(native_object))).cast(),
974        Some(raw_finalize::<TaggedObject<T>>),
975        Box::into_raw(Box::new(size_hint.unwrap_or(0))).cast(),
976        &mut object_value,
977      )
978    })?;
979    if let Some(changed) = size_hint {
980      if changed != 0 {
981        let mut adjusted_value = 0i64;
982        check_status!(unsafe {
983          sys::napi_adjust_external_memory(self.0, changed, &mut adjusted_value)
984        })?;
985      }
986    };
987    unsafe { JsExternal::from_napi_value(self.0, object_value) }
988  }
989
990  #[cfg(feature = "compat-mode")]
991  #[deprecated(since = "3.0.0", note = "Please use `&External` instead")]
992  #[allow(clippy::mut_from_ref)]
993  pub fn get_value_external<T: 'static>(&self, js_external: &JsExternal) -> Result<&mut T> {
994    unsafe {
995      let mut unknown_tagged_object = ptr::null_mut();
996      check_status!(sys::napi_get_value_external(
997        self.0,
998        js_external.0.value,
999        &mut unknown_tagged_object,
1000      ))?;
1001
1002      let type_id = unknown_tagged_object as *const TypeId;
1003      if *type_id == TypeId::of::<T>() {
1004        let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
1005        (*tagged_object).object.as_mut().ok_or_else(|| {
1006          Error::new(
1007            Status::InvalidArg,
1008            "nothing attach to js_external".to_owned(),
1009          )
1010        })
1011      } else {
1012        Err(Error::new(
1013          Status::InvalidArg,
1014          "T on get_value_external is not the type of wrapped object".to_owned(),
1015        ))
1016      }
1017    }
1018  }
1019
1020  /// Create a JavaScript error object from `Error`
1021  pub fn create_error(&self, e: Error) -> Result<Object<'_>> {
1022    if !e.maybe_raw.is_null() {
1023      let mut result = ptr::null_mut();
1024      check_status!(
1025        unsafe { sys::napi_get_reference_value(self.0, e.maybe_raw, &mut result) },
1026        "Get reference value in create_error failed"
1027      )?;
1028      return Ok(Object::from_raw(self.0, result));
1029    }
1030    let reason = &e.reason;
1031    let reason_string = self.create_string(reason.as_str())?;
1032    let status = self.create_string(e.status.as_ref())?;
1033    let mut result = ptr::null_mut();
1034    check_status!(unsafe {
1035      sys::napi_create_error(self.0, status.0.value, reason_string.0.value, &mut result)
1036    })?;
1037    Ok(Object::from_raw(self.0, result))
1038  }
1039
1040  /// Run [Task](./trait.Task.html) in libuv thread pool, return [AsyncWorkPromise](./struct.AsyncWorkPromise.html)
1041  pub fn spawn<'env, T: 'env + ScopedTask<'env>>(
1042    &self,
1043    task: T,
1044  ) -> Result<AsyncWorkPromise<T::JsValue>> {
1045    async_work::run(self.0, task, None)
1046  }
1047
1048  pub fn run_in_scope<T, F>(&self, executor: F) -> Result<T>
1049  where
1050    F: FnOnce() -> Result<T>,
1051  {
1052    let mut handle_scope = ptr::null_mut();
1053    check_status!(unsafe { sys::napi_open_handle_scope(self.0, &mut handle_scope) })?;
1054
1055    let result = executor();
1056
1057    check_status!(unsafe { sys::napi_close_handle_scope(self.0, handle_scope) })?;
1058    result
1059  }
1060
1061  /// Node-API provides an API for executing a string containing JavaScript using the underlying JavaScript engine.
1062  /// This function executes a string of JavaScript code and returns its result with the following caveats:
1063  /// - 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.
1064  /// - 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.
1065  /// - The value of this is [global](https://nodejs.org/api/globals.html) within the script.
1066  pub fn run_script<S: AsRef<str>, V: FromNapiValue>(&self, script: S) -> Result<V> {
1067    let s = self.create_string(script.as_ref())?;
1068    let mut raw_value = ptr::null_mut();
1069    check_status!(unsafe { sys::napi_run_script(self.0, s.raw(), &mut raw_value) })?;
1070    unsafe { V::from_napi_value(self.0, raw_value) }
1071  }
1072
1073  /// `process.versions.napi`
1074  pub fn get_napi_version(&self) -> Result<u32> {
1075    let global = self.get_global()?;
1076    let process: Object = global.get_named_property("process")?;
1077    let versions: Object = process.get_named_property("versions")?;
1078    let napi_version: String = versions.get_named_property("napi")?;
1079    napi_version
1080      .parse()
1081      .map_err(|e| Error::new(Status::InvalidArg, format!("{e}")))
1082  }
1083
1084  #[cfg(all(feature = "napi2", not(target_family = "wasm")))]
1085  pub fn get_uv_event_loop(&self) -> Result<*mut sys::uv_loop_s> {
1086    let mut uv_loop: *mut sys::uv_loop_s = ptr::null_mut();
1087    check_status!(unsafe { sys::napi_get_uv_event_loop(self.0, &mut uv_loop) })?;
1088    Ok(uv_loop)
1089  }
1090
1091  #[cfg(feature = "napi3")]
1092  pub fn add_env_cleanup_hook<T, F>(
1093    &self,
1094    cleanup_data: T,
1095    cleanup_fn: F,
1096  ) -> Result<CleanupEnvHook<T>>
1097  where
1098    T: 'static,
1099    F: 'static + FnOnce(T),
1100  {
1101    let hook = CleanupEnvHookData {
1102      data: cleanup_data,
1103      hook: Box::new(cleanup_fn),
1104    };
1105    let hook_ref = Box::leak(Box::new(hook));
1106    #[cfg(not(target_family = "wasm"))]
1107    {
1108      check_status!(unsafe {
1109        sys::napi_add_env_cleanup_hook(
1110          self.0,
1111          Some(cleanup_env::<T>),
1112          (hook_ref as *mut CleanupEnvHookData<T>).cast(),
1113        )
1114      })?;
1115    }
1116
1117    #[cfg(all(target_family = "wasm", not(feature = "noop")))]
1118    {
1119      check_status!(unsafe {
1120        crate::napi_add_env_cleanup_hook(
1121          self.0,
1122          Some(cleanup_env::<T>),
1123          (hook_ref as *mut CleanupEnvHookData<T>).cast(),
1124        )
1125      })?;
1126    }
1127    Ok(CleanupEnvHook(hook_ref))
1128  }
1129
1130  #[cfg(feature = "napi3")]
1131  pub fn remove_env_cleanup_hook<T>(&self, hook: CleanupEnvHook<T>) -> Result<()>
1132  where
1133    T: 'static,
1134  {
1135    check_status!(unsafe {
1136      sys::napi_remove_env_cleanup_hook(self.0, Some(cleanup_env::<T>), hook.0 as *mut _)
1137    })
1138  }
1139
1140  #[cfg(all(feature = "napi4", feature = "compat-mode"))]
1141  #[deprecated(
1142    since = "2.17.0",
1143    note = "Please use `Function::build_threadsafe_function` instead"
1144  )]
1145  #[allow(deprecated)]
1146  pub fn create_threadsafe_function<
1147    T: 'static + Send,
1148    V: 'static + JsValuesTupleIntoVec,
1149    R: 'static + Send + FnMut(ThreadsafeCallContext<T>) -> Result<V>,
1150  >(
1151    &self,
1152    func: &JsFunction,
1153    _max_queue_size: usize,
1154    callback: R,
1155  ) -> Result<ThreadsafeFunction<T, Unknown<'_>, V>> {
1156    ThreadsafeFunction::<T, Unknown, V>::create(self.0, func.0.value, callback)
1157  }
1158
1159  #[cfg(all(feature = "tokio_rt", feature = "napi4", feature = "compat-mode"))]
1160  #[deprecated(since = "3.0.0", note = "Please use `Env::spawn_future` instead")]
1161  pub fn execute_tokio_future<
1162    T: 'static + Send,
1163    V: 'static + ToNapiValue,
1164    F: 'static + Send + Future<Output = Result<T>>,
1165    R: 'static + FnOnce(&mut Env, T) -> Result<V>,
1166  >(
1167    &self,
1168    fut: F,
1169    resolver: R,
1170  ) -> Result<JsObject> {
1171    use crate::tokio_runtime;
1172
1173    let promise = tokio_runtime::execute_tokio_future(self.0, fut, |env, val| unsafe {
1174      resolver(&mut Env::from_raw(env), val).and_then(|v| ToNapiValue::to_napi_value(env, v))
1175    })?;
1176
1177    Ok(unsafe { JsObject::from_raw_unchecked(self.0, promise) })
1178  }
1179
1180  #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
1181  /// Spawn a future, return a JavaScript Promise which takes the result of the future
1182  pub fn spawn_future<
1183    T: 'static + Send + ToNapiValue,
1184    F: 'static + Send + Future<Output = Result<T>>,
1185  >(
1186    &self,
1187    fut: F,
1188  ) -> Result<PromiseRaw<'_, T>> {
1189    use crate::tokio_runtime;
1190
1191    let promise = tokio_runtime::execute_tokio_future(self.0, fut, |env, val| unsafe {
1192      ToNapiValue::to_napi_value(env, val)
1193    })?;
1194
1195    Ok(PromiseRaw::new(self.0, promise))
1196  }
1197
1198  #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
1199  /// Spawn a future with a callback
1200  /// So you can access the `Env` and resolved value after the future completed
1201  pub fn spawn_future_with_callback<
1202    'env,
1203    T: 'static + Send,
1204    V: ToNapiValue,
1205    F: 'static + Send + Future<Output = Result<T>>,
1206    R: 'static + FnOnce(&'env Env, T) -> Result<V>,
1207  >(
1208    &'env self,
1209    fut: F,
1210    callback: R,
1211  ) -> Result<PromiseRaw<'env, V>> {
1212    use crate::tokio_runtime;
1213
1214    let promise = tokio_runtime::execute_tokio_future(self.0, fut, move |env, val| unsafe {
1215      let env = Env::from_raw(env);
1216      let static_env = core::mem::transmute::<&Env, &'env Env>(&env);
1217      let val = callback(static_env, val)?;
1218      ToNapiValue::to_napi_value(env.0, val)
1219    })?;
1220
1221    Ok(PromiseRaw::new(self.0, promise))
1222  }
1223
1224  /// Creates a deferred promise, which can be resolved or rejected from a background thread.
1225  #[cfg(feature = "napi4")]
1226  pub fn create_deferred<Data: ToNapiValue, Resolver: FnOnce(Env) -> Result<Data>>(
1227    &self,
1228  ) -> Result<(JsDeferred<Data, Resolver>, Object<'_>)> {
1229    JsDeferred::new(self)
1230  }
1231
1232  /// This API does not observe leap seconds; they are ignored, as ECMAScript aligns with POSIX time specification.
1233  ///
1234  /// This API allocates a JavaScript Date object.
1235  ///
1236  /// JavaScript Date objects are described in [Section 20.3](https://tc39.github.io/ecma262/#sec-date-objects) of the ECMAScript Language Specification.
1237  #[cfg(feature = "napi5")]
1238  pub fn create_date(&self, time: f64) -> Result<JsDate<'_>> {
1239    let mut js_value = ptr::null_mut();
1240    check_status!(unsafe { sys::napi_create_date(self.0, time, &mut js_value) })?;
1241    Ok(JsDate::from_raw(self.0, js_value))
1242  }
1243
1244  #[cfg(feature = "napi6")]
1245  /// This API associates data with the currently running Agent. data can later be retrieved using `Env::get_instance_data()`.
1246  ///
1247  /// 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.
1248  ///
1249  /// If a `finalize_cb` was provided by the previous call, it will not be called.
1250  pub fn set_instance_data<T, Hint, F>(&self, native: T, hint: Hint, finalize_cb: F) -> Result<()>
1251  where
1252    T: 'static,
1253    Hint: 'static,
1254    F: FnOnce(FinalizeContext<T, Hint>),
1255  {
1256    check_status!(unsafe {
1257      sys::napi_set_instance_data(
1258        self.0,
1259        Box::into_raw(Box::new((TaggedObject::new(native), finalize_cb))).cast(),
1260        Some(
1261          set_instance_finalize_callback::<T, Hint, F>
1262            as unsafe extern "C" fn(
1263              env: sys::napi_env,
1264              finalize_data: *mut c_void,
1265              finalize_hint: *mut c_void,
1266            ),
1267        ),
1268        Box::into_raw(Box::new(hint)).cast(),
1269      )
1270    })
1271  }
1272
1273  /// This API retrieves data that was previously associated with the currently running Agent via `Env::set_instance_data()`.
1274  ///
1275  /// If no data is set, the call will succeed and data will be set to NULL.
1276  #[cfg(feature = "napi6")]
1277  pub fn get_instance_data<T>(&self) -> Result<Option<&'static mut T>>
1278  where
1279    T: 'static,
1280  {
1281    let mut unknown_tagged_object: *mut c_void = ptr::null_mut();
1282    unsafe {
1283      check_status!(sys::napi_get_instance_data(
1284        self.0,
1285        &mut unknown_tagged_object
1286      ))?;
1287      let type_id = unknown_tagged_object as *const TypeId;
1288      if unknown_tagged_object.is_null() {
1289        return Ok(None);
1290      }
1291      if *type_id == TypeId::of::<T>() {
1292        let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
1293        (*tagged_object).object.as_mut().map(Some).ok_or_else(|| {
1294          Error::new(
1295            Status::InvalidArg,
1296            "Invalid argument, nothing attach to js_object".to_owned(),
1297          )
1298        })
1299      } else {
1300        Err(Error::new(
1301          Status::InvalidArg,
1302          format!(
1303            "Invalid argument, {} on unwrap is not the type of wrapped object",
1304            type_name::<T>()
1305          ),
1306        ))
1307      }
1308    }
1309  }
1310
1311  /// 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.
1312  ///
1313  /// 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.
1314  ///
1315  /// Otherwise, behavior generally matches that of [`add_env_cleanup_hook`](https://docs.rs/napi/latest/napi/struct.Env.html#method.add_env_cleanup_hook).
1316  #[cfg(feature = "napi8")]
1317  pub fn add_removable_async_cleanup_hook<Arg, F>(
1318    &self,
1319    arg: Arg,
1320    cleanup_fn: F,
1321  ) -> Result<AsyncCleanupHook>
1322  where
1323    F: FnOnce(Arg),
1324    Arg: 'static,
1325  {
1326    let mut handle = ptr::null_mut();
1327    check_status!(unsafe {
1328      sys::napi_add_async_cleanup_hook(
1329        self.0,
1330        Some(
1331          async_finalize::<Arg, F>
1332            as unsafe extern "C" fn(handle: sys::napi_async_cleanup_hook_handle, data: *mut c_void),
1333        ),
1334        Box::leak(Box::new((arg, cleanup_fn))) as *mut (Arg, F) as *mut c_void,
1335        &mut handle,
1336      )
1337    })?;
1338    Ok(AsyncCleanupHook(handle))
1339  }
1340
1341  /// 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)
1342  ///
1343  /// Use this one if you don't want remove the cleanup hook anymore.
1344  #[cfg(feature = "napi8")]
1345  pub fn add_async_cleanup_hook<Arg, F>(&self, arg: Arg, cleanup_fn: F) -> Result<()>
1346  where
1347    F: FnOnce(Arg),
1348    Arg: 'static,
1349  {
1350    check_status!(unsafe {
1351      sys::napi_add_async_cleanup_hook(
1352        self.0,
1353        Some(
1354          async_finalize::<Arg, F>
1355            as unsafe extern "C" fn(handle: sys::napi_async_cleanup_hook_handle, data: *mut c_void),
1356        ),
1357        Box::leak(Box::new((arg, cleanup_fn))) as *mut (Arg, F) as *mut c_void,
1358        ptr::null_mut(),
1359      )
1360    })
1361  }
1362
1363  #[cfg(feature = "napi9")]
1364  pub fn symbol_for(&self, description: &str) -> Result<JsSymbol<'_>> {
1365    let mut result = ptr::null_mut();
1366    check_status!(unsafe {
1367      sys::node_api_symbol_for(
1368        self.0,
1369        description.as_ptr().cast(),
1370        description.len() as isize,
1371        &mut result,
1372      )
1373    })?;
1374
1375    Ok(JsSymbol(
1376      Value {
1377        env: self.0,
1378        value: result,
1379        value_type: ValueType::Symbol,
1380      },
1381      std::marker::PhantomData,
1382    ))
1383  }
1384
1385  #[cfg(feature = "napi9")]
1386  /// This API retrieves the file path of the currently running JS module as a URL. For a file on
1387  /// the local file system it will start with `file://`.
1388  ///
1389  /// # Errors
1390  ///
1391  /// The retrieved string may be empty if the add-on loading process fails to establish the
1392  /// add-on's file name.
1393  pub fn get_module_file_name(&self) -> Result<String> {
1394    let mut char_ptr = ptr::null();
1395    check_status!(
1396      unsafe { sys::node_api_get_module_file_name(self.0, &mut char_ptr) },
1397      "call node_api_get_module_file_name failed"
1398    )?;
1399    // SAFETY: This is safe because `char_ptr` is guaranteed to not be `null`, and point to
1400    // null-terminated string data.
1401    let module_filename = unsafe { std::ffi::CStr::from_ptr(char_ptr) };
1402
1403    Ok(module_filename.to_string_lossy().into_owned())
1404  }
1405
1406  /// ### Serialize `Rust Struct` into `JavaScript Value`
1407  ///
1408  /// ```
1409  /// #[derive(Serialize, Debug, Deserialize)]
1410  /// struct AnObject {
1411  ///     a: u32,
1412  ///     b: Vec<f64>,
1413  ///     c: String,
1414  /// }
1415  ///
1416  /// #[js_function]
1417  /// fn serialize(ctx: CallContext) -> Result<JsUnknown> {
1418  ///     let value = AnyObject { a: 1, b: vec![0.1, 2.22], c: "hello" };
1419  ///     ctx.env.to_js_value(&value)
1420  /// }
1421  /// ```
1422  #[cfg(feature = "serde-json")]
1423  #[allow(clippy::wrong_self_convention)]
1424  pub fn to_js_value<'env, T>(&self, node: &T) -> Result<Unknown<'env>>
1425  where
1426    T: Serialize,
1427  {
1428    let s = Ser(self);
1429    node
1430      .serialize(s)
1431      .map(|v| Unknown(v, std::marker::PhantomData))
1432  }
1433
1434  /// ### Deserialize data from `JsValue`
1435  /// ```
1436  /// #[derive(Serialize, Debug, Deserialize)]
1437  /// struct AnObject {
1438  ///     a: u32,
1439  ///     b: Vec<f64>,
1440  ///     c: String,
1441  /// }
1442  ///
1443  /// #[js_function(1)]
1444  /// fn deserialize_from_js(ctx: CallContext) -> Result<JsUndefined> {
1445  ///     let arg0 = ctx.get::<JsUnknown>(0)?;
1446  ///     let de_serialized: AnObject = ctx.env.from_js_value(arg0)?;
1447  ///     ...
1448  /// }
1449  ///
1450  #[cfg(feature = "serde-json")]
1451  pub fn from_js_value<'v, T, V>(&self, value: V) -> Result<T>
1452  where
1453    T: DeserializeOwned,
1454    V: JsValue<'v>,
1455  {
1456    let value = Value {
1457      env: self.0,
1458      value: value.raw(),
1459      value_type: ValueType::Unknown,
1460    };
1461    let mut de = De(&value);
1462    T::deserialize(&mut de)
1463  }
1464
1465  /// 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.
1466  pub fn strict_equals<'env, A: JsValue<'env>, B: JsValue<'env>>(
1467    &self,
1468    a: A,
1469    b: B,
1470  ) -> Result<bool> {
1471    let mut result = false;
1472    check_status!(unsafe { sys::napi_strict_equals(self.0, a.raw(), b.raw(), &mut result) })?;
1473    Ok(result)
1474  }
1475
1476  pub fn get_node_version(&self) -> Result<NodeVersion> {
1477    let mut result = ptr::null();
1478    check_status!(unsafe { sys::napi_get_node_version(self.0, &mut result) })?;
1479    let version = unsafe { *result };
1480    version.try_into()
1481  }
1482
1483  /// get raw env ptr
1484  pub fn raw(&self) -> sys::napi_env {
1485    self.0
1486  }
1487}
1488
1489/// This function could be used for `BufferSlice::from_external` and want do noting when Buffer finalized.
1490pub fn noop_finalize<Hint>(_env: Env, _hint: Hint) {}
1491
1492#[cfg(feature = "compat-mode")]
1493unsafe extern "C" fn drop_buffer(
1494  _env: sys::napi_env,
1495  finalize_data: *mut c_void,
1496  hint: *mut c_void,
1497) {
1498  let length_ptr = hint as *mut (usize, usize);
1499  let (length, cap) = unsafe { *Box::from_raw(length_ptr) };
1500  if length == 0 || finalize_data.is_null() {
1501    return;
1502  }
1503  mem::drop(unsafe { Vec::from_raw_parts(finalize_data as *mut u8, length, cap) });
1504}
1505
1506#[cfg_attr(target_family = "wasm", allow(unused_variables))]
1507pub(crate) unsafe extern "C" fn raw_finalize<T>(
1508  env: sys::napi_env,
1509  finalize_data: *mut c_void,
1510  finalize_hint: *mut c_void,
1511) {
1512  let tagged_object = finalize_data as *mut T;
1513  drop(unsafe { Box::from_raw(tagged_object) });
1514  #[cfg(not(target_family = "wasm"))]
1515  if !finalize_hint.is_null() {
1516    let size_hint = unsafe { *Box::from_raw(finalize_hint as *mut i64) };
1517    if size_hint != 0 {
1518      let mut adjusted = 0i64;
1519      let status = unsafe { sys::napi_adjust_external_memory(env, -size_hint, &mut adjusted) };
1520      debug_assert!(
1521        status == sys::Status::napi_ok,
1522        "Calling napi_adjust_external_memory failed"
1523      );
1524    }
1525  };
1526}
1527
1528#[cfg(feature = "napi6")]
1529unsafe extern "C" fn set_instance_finalize_callback<T, Hint, F>(
1530  raw_env: sys::napi_env,
1531  finalize_data: *mut c_void,
1532  finalize_hint: *mut c_void,
1533) where
1534  T: 'static,
1535  Hint: 'static,
1536  F: FnOnce(FinalizeContext<T, Hint>),
1537{
1538  let (value, callback) = unsafe { *Box::from_raw(finalize_data as *mut (TaggedObject<T>, F)) };
1539  let hint = unsafe { *Box::from_raw(finalize_hint as *mut Hint) };
1540  let env = Env::from_raw(raw_env);
1541  callback(FinalizeContext {
1542    value: value.object.unwrap(),
1543    hint,
1544    env,
1545  });
1546}
1547
1548#[cfg(feature = "napi3")]
1549unsafe extern "C" fn cleanup_env<T: 'static>(hook_data: *mut c_void) {
1550  let cleanup_env_hook = unsafe { Box::from_raw(hook_data as *mut CleanupEnvHookData<T>) };
1551  (cleanup_env_hook.hook)(cleanup_env_hook.data);
1552}
1553
1554pub(crate) unsafe extern "C" fn raw_finalize_with_custom_callback<Hint, Finalize>(
1555  env: sys::napi_env,
1556  _finalize_data: *mut c_void,
1557  finalize_hint: *mut c_void,
1558) where
1559  Finalize: FnOnce(Env, Hint),
1560{
1561  let (hint, callback) = unsafe { *Box::from_raw(finalize_hint as *mut (Hint, Finalize)) };
1562  callback(Env::from_raw(env), hint);
1563}
1564
1565#[cfg(feature = "napi8")]
1566unsafe extern "C" fn async_finalize<Arg, F>(
1567  handle: sys::napi_async_cleanup_hook_handle,
1568  data: *mut c_void,
1569) where
1570  Arg: 'static,
1571  F: FnOnce(Arg),
1572{
1573  let (arg, callback) = unsafe { *Box::from_raw(data as *mut (Arg, F)) };
1574  callback(arg);
1575  if !handle.is_null() {
1576    let status = unsafe { sys::napi_remove_async_cleanup_hook(handle) };
1577    assert!(
1578      status == sys::Status::napi_ok,
1579      "Remove async cleanup hook failed after async cleanup callback"
1580    );
1581  }
1582}
1583
1584#[cfg(feature = "napi5")]
1585pub(crate) unsafe extern "C" fn trampoline<
1586  Return: ToNapiValue,
1587  F: Fn(FunctionCallContext) -> Result<Return>,
1588>(
1589  raw_env: sys::napi_env,
1590  cb_info: sys::napi_callback_info,
1591) -> sys::napi_value {
1592  // Fast path for 4 arguments or less.
1593  let mut argc = 4;
1594  let mut raw_args = Vec::with_capacity(4);
1595  let mut raw_this = ptr::null_mut();
1596  let mut closure_data_ptr = ptr::null_mut();
1597
1598  check_status!(
1599    unsafe {
1600      sys::napi_get_cb_info(
1601        raw_env,
1602        cb_info,
1603        &mut argc,
1604        raw_args.as_mut_ptr(),
1605        &mut raw_this,
1606        &mut closure_data_ptr,
1607      )
1608    },
1609    "napi_get_cb_info failed"
1610  )
1611  .and_then(|_| {
1612    // Arguments length greater than 4, resize the vector.
1613    if argc > 4 {
1614      raw_args = vec![ptr::null_mut(); argc];
1615      check_status!(
1616        unsafe {
1617          sys::napi_get_cb_info(
1618            raw_env,
1619            cb_info,
1620            &mut argc,
1621            raw_args.as_mut_ptr(),
1622            &mut raw_this,
1623            &mut closure_data_ptr,
1624          )
1625        },
1626        "napi_get_cb_info failed"
1627      )?;
1628    } else {
1629      unsafe { raw_args.set_len(argc) };
1630    }
1631    Ok((raw_this, raw_args, closure_data_ptr, argc))
1632  })
1633  .and_then(|(raw_this, raw_args, closure_data_ptr, _argc)| {
1634    let closure: &F = Box::leak(unsafe { Box::from_raw(closure_data_ptr.cast()) });
1635    let mut env = Env::from_raw(raw_env);
1636    closure(FunctionCallContext {
1637      env: &mut env,
1638      this: raw_this,
1639      args: raw_args.as_slice(),
1640    })
1641  })
1642  .and_then(|ret| unsafe { <Return as ToNapiValue>::to_napi_value(raw_env, ret) })
1643  .unwrap_or_else(|e| {
1644    unsafe { JsError::from(e).throw_into(raw_env) };
1645    ptr::null_mut()
1646  })
1647}
1648
1649#[cfg(feature = "napi5")]
1650pub(crate) unsafe extern "C" fn trampoline_setter<
1651  V: FromNapiValue,
1652  F: Fn(Env, crate::bindgen_runtime::This, V) -> Result<()>,
1653>(
1654  raw_env: sys::napi_env,
1655  cb_info: sys::napi_callback_info,
1656) -> sys::napi_value {
1657  use crate::bindgen_runtime::This;
1658
1659  let (raw_args, raw_this, closure_data_ptr) = {
1660    let mut argc = 1;
1661    let mut raw_args = vec![ptr::null_mut(); 1];
1662    let mut raw_this = ptr::null_mut();
1663    let mut data_ptr = ptr::null_mut();
1664
1665    let status = unsafe {
1666      sys::napi_get_cb_info(
1667        raw_env,
1668        cb_info,
1669        &mut argc,
1670        raw_args.as_mut_ptr(),
1671        &mut raw_this,
1672        &mut data_ptr,
1673      )
1674    };
1675    unsafe { raw_args.set_len(argc) };
1676    debug_assert!(
1677      Status::from(status) == Status::Ok,
1678      "napi_get_cb_info failed"
1679    );
1680
1681    let closure_data_ptr = unsafe { *(data_ptr as *mut PropertyClosures) }.setter_closure;
1682    (raw_args, raw_this, closure_data_ptr)
1683  };
1684
1685  let closure: &F = Box::leak(unsafe { Box::from_raw(closure_data_ptr.cast()) });
1686  let env = Env::from_raw(raw_env);
1687  raw_args
1688    .first()
1689    .ok_or_else(|| Error::new(Status::InvalidArg, "Missing argument in property setter"))
1690    .and_then(|value| unsafe { V::from_napi_value(raw_env, *value) })
1691    .and_then(|value| {
1692      closure(
1693        env,
1694        unsafe { This::from_napi_value(raw_env, raw_this)? },
1695        value,
1696      )
1697    })
1698    .map(|_| std::ptr::null_mut())
1699    .unwrap_or_else(|e| {
1700      unsafe { JsError::from(e).throw_into(raw_env) };
1701      ptr::null_mut()
1702    })
1703}
1704
1705#[cfg(feature = "napi5")]
1706pub(crate) unsafe extern "C" fn trampoline_getter<
1707  R: ToNapiValue,
1708  F: Fn(Env, crate::bindgen_runtime::This) -> Result<R>,
1709>(
1710  raw_env: sys::napi_env,
1711  cb_info: sys::napi_callback_info,
1712) -> sys::napi_value {
1713  let (raw_this, closure_data_ptr) = {
1714    let mut raw_this = ptr::null_mut();
1715    let mut data_ptr = ptr::null_mut();
1716
1717    let status = unsafe {
1718      sys::napi_get_cb_info(
1719        raw_env,
1720        cb_info,
1721        &mut 0,
1722        ptr::null_mut(),
1723        &mut raw_this,
1724        &mut data_ptr,
1725      )
1726    };
1727    debug_assert!(
1728      Status::from(status) == Status::Ok,
1729      "napi_get_cb_info failed"
1730    );
1731
1732    let closure_data_ptr = unsafe { *(data_ptr as *mut PropertyClosures) }.getter_closure;
1733    (raw_this, closure_data_ptr)
1734  };
1735
1736  let closure: &F = Box::leak(unsafe { Box::from_raw(closure_data_ptr.cast()) });
1737  let env = Env::from_raw(raw_env);
1738  unsafe { crate::bindgen_runtime::This::from_napi_value(raw_env, raw_this) }
1739    .and_then(|this| closure(env, this))
1740    .and_then(|ret: R| unsafe { <R as ToNapiValue>::to_napi_value(env.0, ret) })
1741    .unwrap_or_else(|e| {
1742      unsafe { JsError::from(e).throw_into(raw_env) };
1743      ptr::null_mut()
1744    })
1745}
1746
1747#[cfg(feature = "napi5")]
1748pub(crate) unsafe extern "C" fn finalize_box_trampoline<F>(
1749  _raw_env: sys::napi_env,
1750  closure_data_ptr: *mut c_void,
1751  _finalize_hint: *mut c_void,
1752) {
1753  drop(unsafe { Box::<F>::from_raw(closure_data_ptr.cast()) })
1754}