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 check_status!(unsafe {
501 if length == 0 {
502 sys::napi_create_arraybuffer(self.0, length, ptr::null_mut(), &mut raw_value)
506 } else {
507 let hint_ptr = Box::into_raw(Box::new((length, data.capacity())));
508 let status = sys::napi_create_external_arraybuffer(
509 self.0,
510 data_ptr.cast(),
511 length,
512 Some(drop_buffer),
513 hint_ptr.cast(),
514 &mut raw_value,
515 );
516 if status == sys::Status::napi_no_external_buffers_allowed {
517 drop(Box::from_raw(hint_ptr));
518 let mut underlying_data = ptr::null_mut();
519 let status =
520 sys::napi_create_arraybuffer(self.0, length, &mut underlying_data, &mut raw_value);
521 ptr::copy_nonoverlapping(data_ptr, underlying_data.cast(), length);
522 status
523 } else {
524 status
525 }
526 }
527 })?;
528
529 mem::forget(data);
530 Ok(JsArrayBufferValue::new(
531 JsArrayBuffer(Value {
532 env: self.0,
533 value: raw_value,
534 value_type: ValueType::Object,
535 }),
536 data_ptr.cast(),
537 length,
538 ))
539 }
540
541 #[cfg(feature = "compat-mode")]
542 #[deprecated(since = "3.0.0", note = "Use `ArrayBuffer::from_external` instead")]
543 pub unsafe fn create_arraybuffer_with_borrowed_data<Hint, Finalize>(
559 &self,
560 data: *mut u8,
561 length: usize,
562 hint: Hint,
563 finalize_callback: Finalize,
564 ) -> Result<JsArrayBufferValue>
565 where
566 Finalize: FnOnce(Env, Hint),
567 {
568 let mut raw_value = ptr::null_mut();
569 let hint_ptr = Box::into_raw(Box::new((hint, finalize_callback)));
570 unsafe {
571 let status = sys::napi_create_external_arraybuffer(
572 self.0,
573 if length == 0 {
574 ptr::null_mut()
578 } else {
579 data as *mut c_void
580 },
581 length,
582 Some(
583 raw_finalize_with_custom_callback::<Hint, Finalize>
584 as unsafe extern "C" fn(
585 env: sys::napi_env,
586 finalize_data: *mut c_void,
587 finalize_hint: *mut c_void,
588 ),
589 ),
590 hint_ptr.cast(),
591 &mut raw_value,
592 );
593 if status == sys::Status::napi_no_external_buffers_allowed {
594 let (hint, finalize) = *Box::from_raw(hint_ptr);
595 let mut underlying_data = ptr::null_mut();
596 let status =
597 sys::napi_create_arraybuffer(self.0, length, &mut underlying_data, &mut raw_value);
598 ptr::copy_nonoverlapping(data, underlying_data.cast(), length);
599 finalize(*self, hint);
600 check_status!(status)?;
601 } else {
602 check_status!(status)?;
603 }
604 };
605 Ok(JsArrayBufferValue::new(
606 JsArrayBuffer(Value {
607 env: self.0,
608 value: raw_value,
609 value_type: ValueType::Object,
610 }),
611 data as *mut c_void,
612 length,
613 ))
614 }
615
616 pub fn create_function<Args: JsValuesTupleIntoVec, Return>(
624 &self,
625 name: &str,
626 callback: Callback,
627 ) -> Result<Function<'_, Args, Return>> {
628 let mut raw_result = ptr::null_mut();
629 let len = name.len();
630 check_status!(unsafe {
631 sys::napi_create_function(
632 self.0,
633 name.as_ptr().cast(),
634 len as isize,
635 Some(callback),
636 ptr::null_mut(),
637 &mut raw_result,
638 )
639 })?;
640
641 unsafe { Function::<Args, Return>::from_napi_value(self.0, raw_result) }
642 }
643
644 #[cfg(feature = "napi5")]
645 pub fn create_function_from_closure<Args: JsValuesTupleIntoVec, Return, F>(
646 &self,
647 name: &str,
648 callback: F,
649 ) -> Result<Function<'_, Args, Return>>
650 where
651 Return: ToNapiValue,
652 F: 'static + Fn(FunctionCallContext) -> Result<Return>,
653 {
654 let closure_data_ptr = Box::into_raw(Box::new(callback));
655
656 let mut raw_result = ptr::null_mut();
657 let len = name.len();
658 check_status!(unsafe {
659 sys::napi_create_function(
660 self.0,
661 name.as_ptr().cast(),
662 len as isize,
663 Some(trampoline::<Return, F>),
664 closure_data_ptr.cast(), &mut raw_result,
666 )
667 })?;
668
669 check_status!(unsafe {
678 sys::napi_add_finalizer(
679 self.0,
680 raw_result,
681 closure_data_ptr.cast(),
682 Some(finalize_box_trampoline::<F>),
683 ptr::null_mut(),
684 ptr::null_mut(),
685 )
686 })?;
687
688 unsafe { Function::from_napi_value(self.0, raw_result) }
689 }
690
691 pub fn get_last_error_info(&self) -> Result<ExtendedErrorInfo> {
699 let mut raw_extended_error = ptr::null();
700 check_status!(unsafe { sys::napi_get_last_error_info(self.0, &mut raw_extended_error) })?;
701 unsafe { ptr::read(raw_extended_error) }.try_into()
702 }
703
704 pub fn throw<T: ToNapiValue>(&self, value: T) -> Result<()> {
706 check_status!(unsafe { sys::napi_throw(self.0, ToNapiValue::to_napi_value(self.0, value)?,) })
707 }
708
709 pub fn throw_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
711 let code = code.and_then(|s| CString::new(s).ok());
712 let msg = CString::new(msg)?;
713 check_status!(unsafe {
714 sys::napi_throw_error(
715 self.0,
716 code.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()),
717 msg.as_ptr(),
718 )
719 })
720 }
721
722 pub fn throw_range_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
724 let code = code.and_then(|s| CString::new(s).ok());
725 let msg = CString::new(msg)?;
726 check_status!(unsafe {
727 sys::napi_throw_range_error(
728 self.0,
729 code.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()),
730 msg.as_ptr(),
731 )
732 })
733 }
734
735 pub fn throw_type_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
737 let code = code.and_then(|s| CString::new(s).ok());
738 let msg = CString::new(msg)?;
739 check_status!(unsafe {
740 sys::napi_throw_type_error(
741 self.0,
742 code.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()),
743 msg.as_ptr(),
744 )
745 })
746 }
747
748 #[cfg(feature = "napi9")]
750 pub fn throw_syntax_error<S: AsRef<str>, C: AsRef<str>>(&self, msg: S, code: Option<C>) {
751 use crate::check_status_or_throw;
752
753 let code = code.as_ref().map(|c| c.as_ref()).unwrap_or("");
754 let c_code = CString::new(code).expect("code must be a valid utf-8 string");
755 let code_ptr = c_code.as_ptr();
756 let msg: CString = CString::new(msg.as_ref()).expect("msg must be a valid utf-8 string");
757 let msg_ptr = msg.as_ptr();
758 check_status_or_throw!(
759 self.0,
760 unsafe { sys::node_api_throw_syntax_error(self.0, code_ptr, msg_ptr,) },
761 "Throw syntax error failed"
762 );
763 }
764
765 #[allow(clippy::expect_fun_call)]
766 pub fn fatal_error(self, location: &str, message: &str) {
770 let location_len = location.len();
771 let message_len = message.len();
772
773 unsafe {
774 sys::napi_fatal_error(
775 location.as_ptr().cast(),
776 location_len as isize,
777 message.as_ptr().cast(),
778 message_len as isize,
779 )
780 }
781 }
782
783 #[cfg(feature = "napi3")]
784 pub fn fatal_exception(&self, err: Error) {
788 unsafe {
789 let js_error = JsError::from(err).into_value(self.0);
790 debug_assert!(sys::napi_fatal_exception(self.0, js_error) == sys::Status::napi_ok);
791 };
792 }
793
794 pub fn define_class<Args: JsValuesTupleIntoVec>(
796 &self,
797 name: &str,
798 constructor_cb: Callback,
799 properties: &[Property],
800 ) -> Result<Function<'_, Args, Unknown<'_>>> {
801 let mut raw_result = ptr::null_mut();
802 let raw_properties = properties
803 .iter()
804 .map(|prop| prop.raw())
805 .collect::<Vec<sys::napi_property_descriptor>>();
806 check_status!(unsafe {
807 sys::napi_define_class(
808 self.0,
809 name.as_ptr().cast(),
810 name.len() as isize,
811 Some(constructor_cb),
812 ptr::null_mut(),
813 raw_properties.len(),
814 raw_properties.as_ptr(),
815 &mut raw_result,
816 )
817 })?;
818
819 unsafe { Function::from_napi_value(self.0, raw_result) }
820 }
821
822 #[cfg(feature = "compat-mode")]
823 #[deprecated(since = "3.0.0", note = "Please use `JsObjectValue::wrap` instead")]
824 #[allow(clippy::needless_pass_by_ref_mut)]
825 pub fn wrap<T: 'static>(
826 &self,
827 js_object: &mut JsObject,
828 native_object: T,
829 size_hint: Option<usize>,
830 ) -> Result<()> {
831 check_status!(unsafe {
832 sys::napi_wrap(
833 self.0,
834 js_object.0.value,
835 Box::into_raw(Box::new(TaggedObject::new(native_object))).cast(),
836 Some(raw_finalize::<TaggedObject<T>>),
837 Box::into_raw(Box::new(size_hint.unwrap_or(0) as i64)).cast(),
838 ptr::null_mut(),
839 )
840 })
841 }
842
843 #[cfg(feature = "compat-mode")]
844 #[deprecated(since = "3.0.0", note = "Please use `JsObjectValue::unwrap` instead")]
845 #[allow(clippy::mut_from_ref)]
846 pub fn unwrap<T: 'static>(&self, js_object: &JsObject) -> Result<&mut T> {
847 unsafe {
848 let mut unknown_tagged_object: *mut c_void = ptr::null_mut();
849 check_status!(sys::napi_unwrap(
850 self.0,
851 js_object.0.value,
852 &mut unknown_tagged_object,
853 ))?;
854
855 let type_id = unknown_tagged_object as *const TypeId;
856 if *type_id == TypeId::of::<T>() {
857 let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
858 (*tagged_object).object.as_mut().ok_or_else(|| {
859 Error::new(
860 Status::InvalidArg,
861 "Invalid argument, nothing attach to js_object".to_owned(),
862 )
863 })
864 } else {
865 Err(Error::new(
866 Status::InvalidArg,
867 format!(
868 "Invalid argument, {} on unwrap is not the type of wrapped object",
869 type_name::<T>()
870 ),
871 ))
872 }
873 }
874 }
875
876 #[cfg(feature = "compat-mode")]
877 #[deprecated(
878 since = "3.0.0",
879 note = "Please use `JsObjectValue::drop_wrapped` instead"
880 )]
881 pub fn drop_wrapped<T: 'static>(&self, js_object: &JsObject) -> Result<()> {
882 unsafe {
883 let mut unknown_tagged_object = ptr::null_mut();
884 check_status!(sys::napi_remove_wrap(
885 self.0,
886 js_object.0.value,
887 &mut unknown_tagged_object,
888 ))?;
889 let type_id = unknown_tagged_object as *const TypeId;
890 if *type_id == TypeId::of::<T>() {
891 drop(Box::from_raw(unknown_tagged_object as *mut TaggedObject<T>));
892 Ok(())
893 } else {
894 Err(Error::new(
895 Status::InvalidArg,
896 format!(
897 "Invalid argument, {} on unwrap is not the type of wrapped object",
898 type_name::<T>()
899 ),
900 ))
901 }
902 }
903 }
904
905 #[cfg(feature = "compat-mode")]
906 #[deprecated(since = "3.0.0", note = "Please use `Ref::new` instead")]
907 pub fn create_reference<'env, T>(&self, value: &T) -> Result<Ref<T>>
909 where
910 T: JsValue<'env>,
911 {
912 Ref::new(self, value)
913 }
914
915 #[cfg(feature = "compat-mode")]
916 #[deprecated(since = "3.0.0", note = "Please use `Ref::get_value` instead")]
917 pub fn get_reference_value<T>(&self, reference: &Ref<T>) -> Result<T>
919 where
920 T: FromNapiValue,
921 {
922 let mut js_value = ptr::null_mut();
923 check_status!(unsafe {
924 sys::napi_get_reference_value(self.0, reference.raw_ref, &mut js_value)
925 })?;
926 unsafe { T::from_napi_value(self.0, js_value) }
927 }
928
929 #[cfg(feature = "compat-mode")]
930 #[deprecated(since = "3.0.0", note = "Please use `ObjectRef::get_value` instead")]
931 pub fn get_reference_value_unchecked<T>(&self, reference: &Ref<T>) -> Result<T>
937 where
938 T: FromNapiValue,
939 {
940 let mut js_value = ptr::null_mut();
941 check_status!(unsafe {
942 sys::napi_get_reference_value(self.0, reference.raw_ref, &mut js_value)
943 })?;
944 unsafe { T::from_napi_value(self.0, js_value) }
945 }
946
947 #[cfg(feature = "compat-mode")]
948 #[deprecated(since = "3.0.0", note = "Please use `External::new` instead")]
949 pub fn create_external<'env, T: 'static>(
955 &'env self,
956 native_object: T,
957 size_hint: Option<i64>,
958 ) -> Result<JsExternal<'env>> {
959 let mut object_value = ptr::null_mut();
960 check_status!(unsafe {
961 sys::napi_create_external(
962 self.0,
963 Box::into_raw(Box::new(TaggedObject::new(native_object))).cast(),
964 Some(raw_finalize::<TaggedObject<T>>),
965 Box::into_raw(Box::new(size_hint.unwrap_or(0))).cast(),
966 &mut object_value,
967 )
968 })?;
969 if let Some(changed) = size_hint {
970 if changed != 0 {
971 let mut adjusted_value = 0i64;
972 check_status!(unsafe {
973 sys::napi_adjust_external_memory(self.0, changed, &mut adjusted_value)
974 })?;
975 }
976 };
977 unsafe { JsExternal::from_napi_value(self.0, object_value) }
978 }
979
980 #[cfg(feature = "compat-mode")]
981 #[deprecated(since = "3.0.0", note = "Please use `&External` instead")]
982 #[allow(clippy::mut_from_ref)]
983 pub fn get_value_external<T: 'static>(&self, js_external: &JsExternal) -> Result<&mut T> {
984 unsafe {
985 let mut unknown_tagged_object = ptr::null_mut();
986 check_status!(sys::napi_get_value_external(
987 self.0,
988 js_external.0.value,
989 &mut unknown_tagged_object,
990 ))?;
991
992 let type_id = unknown_tagged_object as *const TypeId;
993 if *type_id == TypeId::of::<T>() {
994 let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
995 (*tagged_object).object.as_mut().ok_or_else(|| {
996 Error::new(
997 Status::InvalidArg,
998 "nothing attach to js_external".to_owned(),
999 )
1000 })
1001 } else {
1002 Err(Error::new(
1003 Status::InvalidArg,
1004 "T on get_value_external is not the type of wrapped object".to_owned(),
1005 ))
1006 }
1007 }
1008 }
1009
1010 pub fn create_error(&self, e: Error) -> Result<Object<'_>> {
1012 if !e.maybe_raw.is_null() {
1013 let mut result = ptr::null_mut();
1014 check_status!(
1015 unsafe { sys::napi_get_reference_value(self.0, e.maybe_raw, &mut result) },
1016 "Get reference value in create_error failed"
1017 )?;
1018 return Ok(Object::from_raw(self.0, result));
1019 }
1020 let reason = &e.reason;
1021 let reason_string = self.create_string(reason.as_str())?;
1022 let status = self.create_string(e.status.as_ref())?;
1023 let mut result = ptr::null_mut();
1024 check_status!(unsafe {
1025 sys::napi_create_error(self.0, status.0.value, reason_string.0.value, &mut result)
1026 })?;
1027 Ok(Object::from_raw(self.0, result))
1028 }
1029
1030 pub fn spawn<'env, T: 'env + ScopedTask<'env>>(
1032 &self,
1033 task: T,
1034 ) -> Result<AsyncWorkPromise<T::JsValue>> {
1035 async_work::run(self.0, task, None)
1036 }
1037
1038 pub fn run_in_scope<T, F>(&self, executor: F) -> Result<T>
1039 where
1040 F: FnOnce() -> Result<T>,
1041 {
1042 let mut handle_scope = ptr::null_mut();
1043 check_status!(unsafe { sys::napi_open_handle_scope(self.0, &mut handle_scope) })?;
1044
1045 let result = executor();
1046
1047 check_status!(unsafe { sys::napi_close_handle_scope(self.0, handle_scope) })?;
1048 result
1049 }
1050
1051 pub fn run_script<S: AsRef<str>, V: FromNapiValue>(&self, script: S) -> Result<V> {
1057 let s = self.create_string(script.as_ref())?;
1058 let mut raw_value = ptr::null_mut();
1059 check_status!(unsafe { sys::napi_run_script(self.0, s.raw(), &mut raw_value) })?;
1060 unsafe { V::from_napi_value(self.0, raw_value) }
1061 }
1062
1063 pub fn get_napi_version(&self) -> Result<u32> {
1065 let global = self.get_global()?;
1066 let process: Object = global.get_named_property("process")?;
1067 let versions: Object = process.get_named_property("versions")?;
1068 let napi_version: String = versions.get_named_property("napi")?;
1069 napi_version
1070 .parse()
1071 .map_err(|e| Error::new(Status::InvalidArg, format!("{e}")))
1072 }
1073
1074 #[cfg(all(feature = "napi2", not(target_family = "wasm")))]
1075 pub fn get_uv_event_loop(&self) -> Result<*mut sys::uv_loop_s> {
1076 let mut uv_loop: *mut sys::uv_loop_s = ptr::null_mut();
1077 check_status!(unsafe { sys::napi_get_uv_event_loop(self.0, &mut uv_loop) })?;
1078 Ok(uv_loop)
1079 }
1080
1081 #[cfg(feature = "napi3")]
1082 pub fn add_env_cleanup_hook<T, F>(
1083 &self,
1084 cleanup_data: T,
1085 cleanup_fn: F,
1086 ) -> Result<CleanupEnvHook<T>>
1087 where
1088 T: 'static,
1089 F: 'static + FnOnce(T),
1090 {
1091 let hook = CleanupEnvHookData {
1092 data: cleanup_data,
1093 hook: Box::new(cleanup_fn),
1094 };
1095 let hook_ref = Box::leak(Box::new(hook));
1096 #[cfg(not(target_family = "wasm"))]
1097 {
1098 check_status!(unsafe {
1099 sys::napi_add_env_cleanup_hook(
1100 self.0,
1101 Some(cleanup_env::<T>),
1102 (hook_ref as *mut CleanupEnvHookData<T>).cast(),
1103 )
1104 })?;
1105 }
1106
1107 #[cfg(target_family = "wasm")]
1108 {
1109 check_status!(unsafe {
1110 crate::napi_add_env_cleanup_hook(
1111 self.0,
1112 Some(cleanup_env::<T>),
1113 (hook_ref as *mut CleanupEnvHookData<T>).cast(),
1114 )
1115 })?;
1116 }
1117 Ok(CleanupEnvHook(hook_ref))
1118 }
1119
1120 #[cfg(feature = "napi3")]
1121 pub fn remove_env_cleanup_hook<T>(&self, hook: CleanupEnvHook<T>) -> Result<()>
1122 where
1123 T: 'static,
1124 {
1125 check_status!(unsafe {
1126 sys::napi_remove_env_cleanup_hook(self.0, Some(cleanup_env::<T>), hook.0 as *mut _)
1127 })
1128 }
1129
1130 #[cfg(all(feature = "napi4", feature = "compat-mode"))]
1131 #[deprecated(
1132 since = "2.17.0",
1133 note = "Please use `Function::build_threadsafe_function` instead"
1134 )]
1135 #[allow(deprecated)]
1136 pub fn create_threadsafe_function<
1137 T: 'static + Send,
1138 V: 'static + JsValuesTupleIntoVec,
1139 R: 'static + Send + FnMut(ThreadsafeCallContext<T>) -> Result<V>,
1140 >(
1141 &self,
1142 func: &JsFunction,
1143 _max_queue_size: usize,
1144 callback: R,
1145 ) -> Result<ThreadsafeFunction<T, Unknown<'_>, V>> {
1146 ThreadsafeFunction::<T, Unknown, V>::create(self.0, func.0.value, callback)
1147 }
1148
1149 #[cfg(all(feature = "tokio_rt", feature = "napi4", feature = "compat-mode"))]
1150 #[deprecated(since = "3.0.0", note = "Please use `Env::spawn_future` instead")]
1151 pub fn execute_tokio_future<
1152 T: 'static + Send,
1153 V: 'static + ToNapiValue,
1154 F: 'static + Send + Future<Output = Result<T>>,
1155 R: 'static + FnOnce(&mut Env, T) -> Result<V>,
1156 >(
1157 &self,
1158 fut: F,
1159 resolver: R,
1160 ) -> Result<JsObject> {
1161 use crate::tokio_runtime;
1162
1163 let promise = tokio_runtime::execute_tokio_future(self.0, fut, |env, val| unsafe {
1164 resolver(&mut Env::from_raw(env), val).and_then(|v| ToNapiValue::to_napi_value(env, v))
1165 })?;
1166
1167 Ok(unsafe { JsObject::from_raw_unchecked(self.0, promise) })
1168 }
1169
1170 #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
1171 pub fn spawn_future<
1173 T: 'static + Send + ToNapiValue,
1174 F: 'static + Send + Future<Output = Result<T>>,
1175 >(
1176 &self,
1177 fut: F,
1178 ) -> Result<PromiseRaw<'_, T>> {
1179 use crate::tokio_runtime;
1180
1181 let promise = tokio_runtime::execute_tokio_future(self.0, fut, |env, val| unsafe {
1182 ToNapiValue::to_napi_value(env, val)
1183 })?;
1184
1185 Ok(PromiseRaw::new(self.0, promise))
1186 }
1187
1188 #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
1189 pub fn spawn_future_with_callback<
1192 'env,
1193 T: 'static + Send,
1194 V: ToNapiValue,
1195 F: 'static + Send + Future<Output = Result<T>>,
1196 R: 'static + FnOnce(&'env Env, T) -> Result<V>,
1197 >(
1198 &'env self,
1199 fut: F,
1200 callback: R,
1201 ) -> Result<PromiseRaw<'env, V>> {
1202 use crate::tokio_runtime;
1203
1204 let promise = tokio_runtime::execute_tokio_future(self.0, fut, move |env, val| unsafe {
1205 let env = Env::from_raw(env);
1206 let static_env = core::mem::transmute::<&Env, &'env Env>(&env);
1207 let val = callback(static_env, val)?;
1208 ToNapiValue::to_napi_value(env.0, val)
1209 })?;
1210
1211 Ok(PromiseRaw::new(self.0, promise))
1212 }
1213
1214 #[cfg(feature = "napi4")]
1216 pub fn create_deferred<Data: ToNapiValue, Resolver: FnOnce(Env) -> Result<Data>>(
1217 &self,
1218 ) -> Result<(JsDeferred<Data, Resolver>, Object<'_>)> {
1219 JsDeferred::new(self)
1220 }
1221
1222 #[cfg(feature = "napi5")]
1228 pub fn create_date(&self, time: f64) -> Result<JsDate<'_>> {
1229 let mut js_value = ptr::null_mut();
1230 check_status!(unsafe { sys::napi_create_date(self.0, time, &mut js_value) })?;
1231 Ok(JsDate::from_raw(self.0, js_value))
1232 }
1233
1234 #[cfg(feature = "napi6")]
1235 pub fn set_instance_data<T, Hint, F>(&self, native: T, hint: Hint, finalize_cb: F) -> Result<()>
1241 where
1242 T: 'static,
1243 Hint: 'static,
1244 F: FnOnce(FinalizeContext<T, Hint>),
1245 {
1246 check_status!(unsafe {
1247 sys::napi_set_instance_data(
1248 self.0,
1249 Box::into_raw(Box::new((TaggedObject::new(native), finalize_cb))).cast(),
1250 Some(
1251 set_instance_finalize_callback::<T, Hint, F>
1252 as unsafe extern "C" fn(
1253 env: sys::napi_env,
1254 finalize_data: *mut c_void,
1255 finalize_hint: *mut c_void,
1256 ),
1257 ),
1258 Box::into_raw(Box::new(hint)).cast(),
1259 )
1260 })
1261 }
1262
1263 #[cfg(feature = "napi6")]
1267 pub fn get_instance_data<T>(&self) -> Result<Option<&'static mut T>>
1268 where
1269 T: 'static,
1270 {
1271 let mut unknown_tagged_object: *mut c_void = ptr::null_mut();
1272 unsafe {
1273 check_status!(sys::napi_get_instance_data(
1274 self.0,
1275 &mut unknown_tagged_object
1276 ))?;
1277 let type_id = unknown_tagged_object as *const TypeId;
1278 if unknown_tagged_object.is_null() {
1279 return Ok(None);
1280 }
1281 if *type_id == TypeId::of::<T>() {
1282 let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
1283 (*tagged_object).object.as_mut().map(Some).ok_or_else(|| {
1284 Error::new(
1285 Status::InvalidArg,
1286 "Invalid argument, nothing attach to js_object".to_owned(),
1287 )
1288 })
1289 } else {
1290 Err(Error::new(
1291 Status::InvalidArg,
1292 format!(
1293 "Invalid argument, {} on unwrap is not the type of wrapped object",
1294 type_name::<T>()
1295 ),
1296 ))
1297 }
1298 }
1299 }
1300
1301 #[cfg(feature = "napi8")]
1307 pub fn add_removable_async_cleanup_hook<Arg, F>(
1308 &self,
1309 arg: Arg,
1310 cleanup_fn: F,
1311 ) -> Result<AsyncCleanupHook>
1312 where
1313 F: FnOnce(Arg),
1314 Arg: 'static,
1315 {
1316 let mut handle = ptr::null_mut();
1317 check_status!(unsafe {
1318 sys::napi_add_async_cleanup_hook(
1319 self.0,
1320 Some(
1321 async_finalize::<Arg, F>
1322 as unsafe extern "C" fn(handle: sys::napi_async_cleanup_hook_handle, data: *mut c_void),
1323 ),
1324 Box::leak(Box::new((arg, cleanup_fn))) as *mut (Arg, F) as *mut c_void,
1325 &mut handle,
1326 )
1327 })?;
1328 Ok(AsyncCleanupHook(handle))
1329 }
1330
1331 #[cfg(feature = "napi8")]
1335 pub fn add_async_cleanup_hook<Arg, F>(&self, arg: Arg, cleanup_fn: F) -> Result<()>
1336 where
1337 F: FnOnce(Arg),
1338 Arg: 'static,
1339 {
1340 check_status!(unsafe {
1341 sys::napi_add_async_cleanup_hook(
1342 self.0,
1343 Some(
1344 async_finalize::<Arg, F>
1345 as unsafe extern "C" fn(handle: sys::napi_async_cleanup_hook_handle, data: *mut c_void),
1346 ),
1347 Box::leak(Box::new((arg, cleanup_fn))) as *mut (Arg, F) as *mut c_void,
1348 ptr::null_mut(),
1349 )
1350 })
1351 }
1352
1353 #[cfg(feature = "napi9")]
1354 pub fn symbol_for(&self, description: &str) -> Result<JsSymbol<'_>> {
1355 let mut result = ptr::null_mut();
1356 check_status!(unsafe {
1357 sys::node_api_symbol_for(
1358 self.0,
1359 description.as_ptr().cast(),
1360 description.len() as isize,
1361 &mut result,
1362 )
1363 })?;
1364
1365 Ok(JsSymbol(
1366 Value {
1367 env: self.0,
1368 value: result,
1369 value_type: ValueType::Symbol,
1370 },
1371 std::marker::PhantomData,
1372 ))
1373 }
1374
1375 #[cfg(feature = "napi9")]
1376 pub fn get_module_file_name(&self) -> Result<String> {
1384 let mut char_ptr = ptr::null();
1385 check_status!(
1386 unsafe { sys::node_api_get_module_file_name(self.0, &mut char_ptr) },
1387 "call node_api_get_module_file_name failed"
1388 )?;
1389 let module_filename = unsafe { std::ffi::CStr::from_ptr(char_ptr) };
1392
1393 Ok(module_filename.to_string_lossy().into_owned())
1394 }
1395
1396 #[cfg(feature = "serde-json")]
1413 #[allow(clippy::wrong_self_convention)]
1414 pub fn to_js_value<'env, T>(&self, node: &T) -> Result<Unknown<'env>>
1415 where
1416 T: Serialize,
1417 {
1418 let s = Ser(self);
1419 node
1420 .serialize(s)
1421 .map(|v| Unknown(v, std::marker::PhantomData))
1422 }
1423
1424 #[cfg(feature = "serde-json")]
1441 pub fn from_js_value<'v, T, V>(&self, value: V) -> Result<T>
1442 where
1443 T: DeserializeOwned,
1444 V: JsValue<'v>,
1445 {
1446 let value = Value {
1447 env: self.0,
1448 value: value.raw(),
1449 value_type: ValueType::Unknown,
1450 };
1451 let mut de = De(&value);
1452 T::deserialize(&mut de)
1453 }
1454
1455 pub fn strict_equals<'env, A: JsValue<'env>, B: JsValue<'env>>(
1457 &self,
1458 a: A,
1459 b: B,
1460 ) -> Result<bool> {
1461 let mut result = false;
1462 check_status!(unsafe { sys::napi_strict_equals(self.0, a.raw(), b.raw(), &mut result) })?;
1463 Ok(result)
1464 }
1465
1466 pub fn get_node_version(&self) -> Result<NodeVersion> {
1467 let mut result = ptr::null();
1468 check_status!(unsafe { sys::napi_get_node_version(self.0, &mut result) })?;
1469 let version = unsafe { *result };
1470 version.try_into()
1471 }
1472
1473 pub fn raw(&self) -> sys::napi_env {
1475 self.0
1476 }
1477}
1478
1479pub fn noop_finalize<Hint>(_env: Env, _hint: Hint) {}
1481
1482#[cfg(feature = "compat-mode")]
1483unsafe extern "C" fn drop_buffer(
1484 _env: sys::napi_env,
1485 finalize_data: *mut c_void,
1486 hint: *mut c_void,
1487) {
1488 let length_ptr = hint as *mut (usize, usize);
1489 let (length, cap) = unsafe { *Box::from_raw(length_ptr) };
1490 if length == 0 || finalize_data.is_null() {
1491 return;
1492 }
1493 mem::drop(unsafe { Vec::from_raw_parts(finalize_data as *mut u8, length, cap) });
1494}
1495
1496#[cfg_attr(target_family = "wasm", allow(unused_variables))]
1497pub(crate) unsafe extern "C" fn raw_finalize<T>(
1498 env: sys::napi_env,
1499 finalize_data: *mut c_void,
1500 finalize_hint: *mut c_void,
1501) {
1502 let tagged_object = finalize_data as *mut T;
1503 drop(unsafe { Box::from_raw(tagged_object) });
1504 #[cfg(not(target_family = "wasm"))]
1505 if !finalize_hint.is_null() {
1506 let size_hint = unsafe { *Box::from_raw(finalize_hint as *mut i64) };
1507 if size_hint != 0 {
1508 let mut adjusted = 0i64;
1509 let status = unsafe { sys::napi_adjust_external_memory(env, -size_hint, &mut adjusted) };
1510 debug_assert!(
1511 status == sys::Status::napi_ok,
1512 "Calling napi_adjust_external_memory failed"
1513 );
1514 }
1515 };
1516}
1517
1518#[cfg(feature = "napi6")]
1519unsafe extern "C" fn set_instance_finalize_callback<T, Hint, F>(
1520 raw_env: sys::napi_env,
1521 finalize_data: *mut c_void,
1522 finalize_hint: *mut c_void,
1523) where
1524 T: 'static,
1525 Hint: 'static,
1526 F: FnOnce(FinalizeContext<T, Hint>),
1527{
1528 let (value, callback) = unsafe { *Box::from_raw(finalize_data as *mut (TaggedObject<T>, F)) };
1529 let hint = unsafe { *Box::from_raw(finalize_hint as *mut Hint) };
1530 let env = Env::from_raw(raw_env);
1531 callback(FinalizeContext {
1532 value: value.object.unwrap(),
1533 hint,
1534 env,
1535 });
1536}
1537
1538#[cfg(feature = "napi3")]
1539unsafe extern "C" fn cleanup_env<T: 'static>(hook_data: *mut c_void) {
1540 let cleanup_env_hook = unsafe { Box::from_raw(hook_data as *mut CleanupEnvHookData<T>) };
1541 (cleanup_env_hook.hook)(cleanup_env_hook.data);
1542}
1543
1544pub(crate) unsafe extern "C" fn raw_finalize_with_custom_callback<Hint, Finalize>(
1545 env: sys::napi_env,
1546 _finalize_data: *mut c_void,
1547 finalize_hint: *mut c_void,
1548) where
1549 Finalize: FnOnce(Env, Hint),
1550{
1551 let (hint, callback) = unsafe { *Box::from_raw(finalize_hint as *mut (Hint, Finalize)) };
1552 callback(Env::from_raw(env), hint);
1553}
1554
1555#[cfg(feature = "napi8")]
1556unsafe extern "C" fn async_finalize<Arg, F>(
1557 handle: sys::napi_async_cleanup_hook_handle,
1558 data: *mut c_void,
1559) where
1560 Arg: 'static,
1561 F: FnOnce(Arg),
1562{
1563 let (arg, callback) = unsafe { *Box::from_raw(data as *mut (Arg, F)) };
1564 callback(arg);
1565 if !handle.is_null() {
1566 let status = unsafe { sys::napi_remove_async_cleanup_hook(handle) };
1567 assert!(
1568 status == sys::Status::napi_ok,
1569 "Remove async cleanup hook failed after async cleanup callback"
1570 );
1571 }
1572}
1573
1574#[cfg(feature = "napi5")]
1575pub(crate) unsafe extern "C" fn trampoline<
1576 Return: ToNapiValue,
1577 F: Fn(FunctionCallContext) -> Result<Return>,
1578>(
1579 raw_env: sys::napi_env,
1580 cb_info: sys::napi_callback_info,
1581) -> sys::napi_value {
1582 let mut argc = 4;
1584 let mut raw_args = Vec::with_capacity(4);
1585 let mut raw_this = ptr::null_mut();
1586 let mut closure_data_ptr = ptr::null_mut();
1587
1588 check_status!(
1589 unsafe {
1590 sys::napi_get_cb_info(
1591 raw_env,
1592 cb_info,
1593 &mut argc,
1594 raw_args.as_mut_ptr(),
1595 &mut raw_this,
1596 &mut closure_data_ptr,
1597 )
1598 },
1599 "napi_get_cb_info failed"
1600 )
1601 .and_then(|_| {
1602 if argc > 4 {
1604 raw_args = vec![ptr::null_mut(); argc];
1605 check_status!(
1606 unsafe {
1607 sys::napi_get_cb_info(
1608 raw_env,
1609 cb_info,
1610 &mut argc,
1611 raw_args.as_mut_ptr(),
1612 &mut raw_this,
1613 &mut closure_data_ptr,
1614 )
1615 },
1616 "napi_get_cb_info failed"
1617 )?;
1618 } else {
1619 unsafe { raw_args.set_len(argc) };
1620 }
1621 Ok((raw_this, raw_args, closure_data_ptr, argc))
1622 })
1623 .and_then(|(raw_this, raw_args, closure_data_ptr, _argc)| {
1624 let closure: &F = Box::leak(unsafe { Box::from_raw(closure_data_ptr.cast()) });
1625 let mut env = Env::from_raw(raw_env);
1626 closure(FunctionCallContext {
1627 env: &mut env,
1628 this: raw_this,
1629 args: raw_args.as_slice(),
1630 })
1631 })
1632 .and_then(|ret| unsafe { <Return as ToNapiValue>::to_napi_value(raw_env, ret) })
1633 .unwrap_or_else(|e| {
1634 unsafe { JsError::from(e).throw_into(raw_env) };
1635 ptr::null_mut()
1636 })
1637}
1638
1639#[cfg(feature = "napi5")]
1640pub(crate) unsafe extern "C" fn trampoline_setter<
1641 V: FromNapiValue,
1642 F: Fn(Env, crate::bindgen_runtime::This, V) -> Result<()>,
1643>(
1644 raw_env: sys::napi_env,
1645 cb_info: sys::napi_callback_info,
1646) -> sys::napi_value {
1647 use crate::bindgen_runtime::This;
1648
1649 let (raw_args, raw_this, closure_data_ptr) = {
1650 let mut argc = 1;
1651 let mut raw_args = vec![ptr::null_mut(); 1];
1652 let mut raw_this = ptr::null_mut();
1653 let mut data_ptr = ptr::null_mut();
1654
1655 let status = unsafe {
1656 sys::napi_get_cb_info(
1657 raw_env,
1658 cb_info,
1659 &mut argc,
1660 raw_args.as_mut_ptr(),
1661 &mut raw_this,
1662 &mut data_ptr,
1663 )
1664 };
1665 unsafe { raw_args.set_len(argc) };
1666 debug_assert!(
1667 Status::from(status) == Status::Ok,
1668 "napi_get_cb_info failed"
1669 );
1670
1671 let closure_data_ptr = unsafe { *(data_ptr as *mut PropertyClosures) }.setter_closure;
1672 (raw_args, raw_this, closure_data_ptr)
1673 };
1674
1675 let closure: &F = Box::leak(unsafe { Box::from_raw(closure_data_ptr.cast()) });
1676 let env = Env::from_raw(raw_env);
1677 raw_args
1678 .first()
1679 .ok_or_else(|| Error::new(Status::InvalidArg, "Missing argument in property setter"))
1680 .and_then(|value| unsafe { V::from_napi_value(raw_env, *value) })
1681 .and_then(|value| {
1682 closure(
1683 env,
1684 unsafe { This::from_napi_value(raw_env, raw_this)? },
1685 value,
1686 )
1687 })
1688 .map(|_| std::ptr::null_mut())
1689 .unwrap_or_else(|e| {
1690 unsafe { JsError::from(e).throw_into(raw_env) };
1691 ptr::null_mut()
1692 })
1693}
1694
1695#[cfg(feature = "napi5")]
1696pub(crate) unsafe extern "C" fn trampoline_getter<
1697 R: ToNapiValue,
1698 F: Fn(Env, crate::bindgen_runtime::This) -> Result<R>,
1699>(
1700 raw_env: sys::napi_env,
1701 cb_info: sys::napi_callback_info,
1702) -> sys::napi_value {
1703 let (raw_this, closure_data_ptr) = {
1704 let mut raw_this = ptr::null_mut();
1705 let mut data_ptr = ptr::null_mut();
1706
1707 let status = unsafe {
1708 sys::napi_get_cb_info(
1709 raw_env,
1710 cb_info,
1711 &mut 0,
1712 ptr::null_mut(),
1713 &mut raw_this,
1714 &mut data_ptr,
1715 )
1716 };
1717 debug_assert!(
1718 Status::from(status) == Status::Ok,
1719 "napi_get_cb_info failed"
1720 );
1721
1722 let closure_data_ptr = unsafe { *(data_ptr as *mut PropertyClosures) }.getter_closure;
1723 (raw_this, closure_data_ptr)
1724 };
1725
1726 let closure: &F = Box::leak(unsafe { Box::from_raw(closure_data_ptr.cast()) });
1727 let env = Env::from_raw(raw_env);
1728 unsafe { crate::bindgen_runtime::This::from_napi_value(raw_env, raw_this) }
1729 .and_then(|this| closure(env, this))
1730 .and_then(|ret: R| unsafe { <R as ToNapiValue>::to_napi_value(env.0, ret) })
1731 .unwrap_or_else(|e| {
1732 unsafe { JsError::from(e).throw_into(raw_env) };
1733 ptr::null_mut()
1734 })
1735}
1736
1737#[cfg(feature = "napi5")]
1738pub(crate) unsafe extern "C" fn finalize_box_trampoline<F>(
1739 _raw_env: sys::napi_env,
1740 closure_data_ptr: *mut c_void,
1741 _finalize_hint: *mut c_void,
1742) {
1743 drop(unsafe { Box::<F>::from_raw(closure_data_ptr.cast()) })
1744}