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)]
53pub 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 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 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 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 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 #[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 #[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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 if status == sys::Status::napi_ok && length > 0 {
606 ptr::copy_nonoverlapping(data, underlying_data.cast(), length);
607 }
608 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 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(), &mut raw_result,
676 )
677 })?;
678
679 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 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 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 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 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 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 #[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 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 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 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 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 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 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 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 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 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 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 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 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 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 #[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 #[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 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 #[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 #[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 #[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 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 let module_filename = unsafe { std::ffi::CStr::from_ptr(char_ptr) };
1402
1403 Ok(module_filename.to_string_lossy().into_owned())
1404 }
1405
1406 #[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 #[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 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 pub fn raw(&self) -> sys::napi_env {
1485 self.0
1486 }
1487}
1488
1489pub 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 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 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}