1#![allow(deprecated)]
2
3use std::any::{type_name, TypeId};
4use std::convert::TryInto;
5use std::ffi::CString;
6#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
7use std::future::Future;
8use std::mem;
9use std::os::raw::{c_char, c_void};
10use std::ptr;
11
12use crate::bindgen_runtime::FromNapiValue;
13#[cfg(feature = "napi4")]
14use crate::bindgen_runtime::ToNapiValue;
15use crate::{
16 async_work::{self, AsyncWorkPromise},
17 check_status,
18 js_values::*,
19 sys,
20 task::Task,
21 Error, ExtendedErrorInfo, NodeVersion, Result, Status, ValueType,
22};
23
24#[cfg(feature = "napi8")]
25use crate::async_cleanup_hook::AsyncCleanupHook;
26#[cfg(feature = "napi3")]
27use crate::cleanup_env::{CleanupEnvHook, CleanupEnvHookData};
28#[cfg(feature = "serde-json")]
29use crate::js_values::{De, Ser};
30#[cfg(feature = "napi4")]
31use crate::threadsafe_function::{ThreadSafeCallContext, ThreadsafeFunction};
32#[cfg(feature = "napi3")]
33use crate::JsError;
34#[cfg(feature = "serde-json")]
35use serde::de::DeserializeOwned;
36#[cfg(feature = "serde-json")]
37use serde::Serialize;
38
39pub type Callback = unsafe extern "C" fn(sys::napi_env, sys::napi_callback_info) -> sys::napi_value;
40
41pub(crate) static EMPTY_VEC: Vec<u8> = vec![];
42
43#[derive(Clone, Copy)]
44pub struct Env(pub(crate) sys::napi_env);
54
55impl From<sys::napi_env> for Env {
56 fn from(env: sys::napi_env) -> Self {
57 Env(env)
58 }
59}
60
61impl Env {
62 #[allow(clippy::missing_safety_doc)]
63 pub unsafe fn from_raw(env: sys::napi_env) -> Self {
64 Env(env)
65 }
66
67 pub fn get_boolean(&self, value: bool) -> Result<JsBoolean> {
68 let mut raw_value = ptr::null_mut();
69 check_status!(unsafe { sys::napi_get_boolean(self.0, value, &mut raw_value) })?;
70 Ok(unsafe { JsBoolean::from_raw_unchecked(self.0, raw_value) })
71 }
72
73 pub fn create_int32(&self, int: i32) -> Result<JsNumber> {
74 let mut raw_value = ptr::null_mut();
75 check_status!(unsafe {
76 sys::napi_create_int32(self.0, int, (&mut raw_value) as *mut sys::napi_value)
77 })?;
78 Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
79 }
80
81 pub fn create_int64(&self, int: i64) -> Result<JsNumber> {
82 let mut raw_value = ptr::null_mut();
83 check_status!(unsafe {
84 sys::napi_create_int64(self.0, int, (&mut raw_value) as *mut sys::napi_value)
85 })?;
86 Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
87 }
88
89 pub fn create_uint32(&self, number: u32) -> Result<JsNumber> {
90 let mut raw_value = ptr::null_mut();
91 check_status!(unsafe { sys::napi_create_uint32(self.0, number, &mut raw_value) })?;
92 Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
93 }
94
95 pub fn create_double(&self, double: f64) -> Result<JsNumber> {
96 let mut raw_value = ptr::null_mut();
97 check_status!(unsafe {
98 sys::napi_create_double(self.0, double, (&mut raw_value) as *mut sys::napi_value)
99 })?;
100 Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
101 }
102
103 #[cfg(feature = "napi6")]
105 pub fn create_bigint_from_i64(&self, value: i64) -> Result<JsBigInt> {
106 let mut raw_value = ptr::null_mut();
107 check_status!(unsafe { sys::napi_create_bigint_int64(self.0, value, &mut raw_value) })?;
108 Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 1))
109 }
110
111 #[cfg(feature = "napi6")]
112 pub fn create_bigint_from_u64(&self, value: u64) -> Result<JsBigInt> {
113 let mut raw_value = ptr::null_mut();
114 check_status!(unsafe { sys::napi_create_bigint_uint64(self.0, value, &mut raw_value) })?;
115 Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 1))
116 }
117
118 #[cfg(feature = "napi6")]
119 pub fn create_bigint_from_i128(&self, value: i128) -> Result<JsBigInt> {
120 let mut raw_value = ptr::null_mut();
121 let sign_bit = i32::from(value <= 0);
122 let words = &value as *const i128 as *const u64;
123 check_status!(unsafe {
124 sys::napi_create_bigint_words(self.0, sign_bit, 2, words, &mut raw_value)
125 })?;
126 Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 2))
127 }
128
129 #[cfg(feature = "napi6")]
130 pub fn create_bigint_from_u128(&self, value: u128) -> Result<JsBigInt> {
131 let mut raw_value = ptr::null_mut();
132 let words = &value as *const u128 as *const u64;
133 check_status!(unsafe { sys::napi_create_bigint_words(self.0, 0, 2, words, &mut raw_value) })?;
134 Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, 2))
135 }
136
137 #[cfg(feature = "napi6")]
141 pub fn create_bigint_from_words(&self, sign_bit: bool, words: Vec<u64>) -> Result<JsBigInt> {
142 let mut raw_value = ptr::null_mut();
143 let len = words.len();
144 check_status!(unsafe {
145 sys::napi_create_bigint_words(
146 self.0,
147 match sign_bit {
148 true => 1,
149 false => 0,
150 },
151 len,
152 words.as_ptr(),
153 &mut raw_value,
154 )
155 })?;
156 Ok(JsBigInt::from_raw_unchecked(self.0, raw_value, len))
157 }
158
159 pub fn create_string(&self, s: &str) -> Result<JsString> {
160 unsafe { self.create_string_from_c_char(s.as_ptr().cast(), s.len()) }
161 }
162
163 pub fn create_string_from_std(&self, s: String) -> Result<JsString> {
164 unsafe { self.create_string_from_c_char(s.as_ptr().cast(), s.len()) }
165 }
166
167 pub unsafe fn create_string_from_c_char(
174 &self,
175 data_ptr: *const c_char,
176 len: usize,
177 ) -> Result<JsString> {
178 let mut raw_value = ptr::null_mut();
179 check_status!(unsafe { sys::napi_create_string_utf8(self.0, data_ptr, len, &mut raw_value) })?;
180 Ok(unsafe { JsString::from_raw_unchecked(self.0, raw_value) })
181 }
182
183 pub fn create_string_utf16(&self, chars: &[u16]) -> Result<JsString> {
184 let mut raw_value = ptr::null_mut();
185 check_status!(unsafe {
186 sys::napi_create_string_utf16(self.0, chars.as_ptr(), chars.len(), &mut raw_value)
187 })?;
188 Ok(unsafe { JsString::from_raw_unchecked(self.0, raw_value) })
189 }
190
191 pub fn create_string_latin1(&self, chars: &[u8]) -> Result<JsString> {
192 let mut raw_value = ptr::null_mut();
193 check_status!(unsafe {
194 sys::napi_create_string_latin1(
195 self.0,
196 chars.as_ptr() as *const _,
197 chars.len(),
198 &mut raw_value,
199 )
200 })?;
201 Ok(unsafe { JsString::from_raw_unchecked(self.0, raw_value) })
202 }
203
204 pub fn create_symbol_from_js_string(&self, description: JsString) -> Result<JsSymbol> {
205 let mut result = ptr::null_mut();
206 check_status!(unsafe { sys::napi_create_symbol(self.0, description.0.value, &mut result) })?;
207 Ok(unsafe { JsSymbol::from_raw_unchecked(self.0, result) })
208 }
209
210 pub fn create_symbol(&self, description: Option<&str>) -> Result<JsSymbol> {
211 let mut result = ptr::null_mut();
212 check_status!(unsafe {
213 sys::napi_create_symbol(
214 self.0,
215 description
216 .and_then(|desc| self.create_string(desc).ok())
217 .map(|string| string.0.value)
218 .unwrap_or(ptr::null_mut()),
219 &mut result,
220 )
221 })?;
222 Ok(unsafe { JsSymbol::from_raw_unchecked(self.0, result) })
223 }
224
225 pub fn create_object(&self) -> Result<JsObject> {
226 let mut raw_value = ptr::null_mut();
227 check_status!(unsafe { sys::napi_create_object(self.0, &mut raw_value) })?;
228 Ok(unsafe { JsObject::from_raw_unchecked(self.0, raw_value) })
229 }
230
231 pub fn create_empty_array(&self) -> Result<JsObject> {
232 let mut raw_value = ptr::null_mut();
233 check_status!(unsafe { sys::napi_create_array(self.0, &mut raw_value) })?;
234 Ok(unsafe { JsObject::from_raw_unchecked(self.0, raw_value) })
235 }
236
237 pub fn create_array_with_length(&self, length: usize) -> Result<JsObject> {
238 let mut raw_value = ptr::null_mut();
239 check_status!(unsafe { sys::napi_create_array_with_length(self.0, length, &mut raw_value) })?;
240 Ok(unsafe { JsObject::from_raw_unchecked(self.0, raw_value) })
241 }
242
243 pub fn create_buffer(&self, length: usize) -> Result<JsBufferValue> {
245 let mut raw_value = ptr::null_mut();
246 let mut data_ptr = ptr::null_mut();
247 check_status!(unsafe {
248 sys::napi_create_buffer(self.0, length, &mut data_ptr, &mut raw_value)
249 })?;
250
251 Ok(JsBufferValue::new(
252 JsBuffer(Value {
253 env: self.0,
254 value: raw_value,
255 value_type: ValueType::Object,
256 }),
257 mem::ManuallyDrop::new(unsafe { Vec::from_raw_parts(data_ptr as *mut _, length, length) }),
258 ))
259 }
260
261 pub fn create_buffer_with_data(&self, mut data: Vec<u8>) -> Result<JsBufferValue> {
265 let length = data.len();
266 let mut raw_value = ptr::null_mut();
267 let data_ptr = data.as_mut_ptr();
268 let hint_ptr = Box::into_raw(Box::new((length, data.capacity())));
269 check_status!(unsafe {
270 if length == 0 {
271 sys::napi_create_buffer(self.0, length, ptr::null_mut(), &mut raw_value)
275 } else {
276 let status = sys::napi_create_external_buffer(
277 self.0,
278 length,
279 data_ptr.cast(),
280 Some(drop_buffer),
281 hint_ptr.cast(),
282 &mut raw_value,
283 );
284 if status == sys::Status::napi_no_external_buffers_allowed {
286 drop(Box::from_raw(hint_ptr));
287 let mut dest_data_ptr = ptr::null_mut();
288 let status = sys::napi_create_buffer_copy(
289 self.0,
290 length,
291 data.as_ptr().cast(),
292 &mut dest_data_ptr,
293 &mut raw_value,
294 );
295 data = Vec::from_raw_parts(dest_data_ptr.cast(), length, length);
296 status
297 } else {
298 status
299 }
300 }
301 })?;
302 Ok(JsBufferValue::new(
303 JsBuffer(Value {
304 env: self.0,
305 value: raw_value,
306 value_type: ValueType::Object,
307 }),
308 mem::ManuallyDrop::new(data),
309 ))
310 }
311
312 pub unsafe fn create_buffer_with_borrowed_data<Hint, Finalize>(
328 &self,
329 mut data: *mut u8,
330 length: usize,
331 hint: Hint,
332 finalize_callback: Finalize,
333 ) -> Result<JsBufferValue>
334 where
335 Finalize: FnOnce(Hint, Env),
336 {
337 let mut raw_value = ptr::null_mut();
338 if data.is_null() || data as *const u8 == EMPTY_VEC.as_ptr() {
339 return Err(Error::new(
340 Status::InvalidArg,
341 "Borrowed data should not be null".to_owned(),
342 ));
343 }
344 let hint_ptr = Box::into_raw(Box::new((hint, finalize_callback)));
345 unsafe {
346 let status = sys::napi_create_external_buffer(
347 self.0,
348 length,
349 data as *mut c_void,
350 Some(
351 raw_finalize_with_custom_callback::<Hint, Finalize>
352 as unsafe extern "C" fn(
353 env: sys::napi_env,
354 finalize_data: *mut c_void,
355 finalize_hint: *mut c_void,
356 ),
357 ),
358 hint_ptr.cast(),
359 &mut raw_value,
360 );
361 if status == sys::Status::napi_no_external_buffers_allowed {
362 let (hint, finalize) = *Box::from_raw(hint_ptr);
363 let mut result_data = ptr::null_mut();
364 let status = sys::napi_create_buffer_copy(
365 self.0,
366 length,
367 data.cast(),
368 &mut result_data,
369 &mut raw_value,
370 );
371 data = result_data.cast();
372 finalize(hint, *self);
373 check_status!(status)?;
374 } else {
375 check_status!(status)?;
376 }
377 };
378 Ok(JsBufferValue::new(
379 JsBuffer(Value {
380 env: self.0,
381 value: raw_value,
382 value_type: ValueType::Object,
383 }),
384 mem::ManuallyDrop::new(unsafe { Vec::from_raw_parts(data, length, length) }),
385 ))
386 }
387
388 #[cfg(not(target_family = "wasm"))]
389 pub fn adjust_external_memory(&mut self, size: i64) -> Result<i64> {
395 let mut changed = 0i64;
396 check_status!(unsafe { sys::napi_adjust_external_memory(self.0, size, &mut changed) })?;
397 Ok(changed)
398 }
399
400 #[cfg(target_family = "wasm")]
401 #[allow(unused_variables)]
402 pub fn adjust_external_memory(&mut self, size: i64) -> Result<i64> {
403 Ok(0)
404 }
405
406 pub fn create_buffer_copy<D>(&self, data_to_copy: D) -> Result<JsBufferValue>
410 where
411 D: AsRef<[u8]>,
412 {
413 let length = data_to_copy.as_ref().len();
414 let data_ptr = data_to_copy.as_ref().as_ptr();
415 let mut copy_data = ptr::null_mut();
416 let mut raw_value = ptr::null_mut();
417 check_status!(unsafe {
418 sys::napi_create_buffer_copy(
419 self.0,
420 length,
421 data_ptr as *mut c_void,
422 &mut copy_data,
423 &mut raw_value,
424 )
425 })?;
426 Ok(JsBufferValue::new(
427 JsBuffer(Value {
428 env: self.0,
429 value: raw_value,
430 value_type: ValueType::Object,
431 }),
432 mem::ManuallyDrop::new(unsafe { Vec::from_raw_parts(copy_data as *mut u8, length, length) }),
433 ))
434 }
435
436 pub fn create_arraybuffer(&self, length: usize) -> Result<JsArrayBufferValue> {
437 let mut raw_value = ptr::null_mut();
438 let mut data_ptr = ptr::null_mut();
439 check_status!(unsafe {
440 sys::napi_create_arraybuffer(self.0, length, &mut data_ptr, &mut raw_value)
441 })?;
442
443 Ok(JsArrayBufferValue::new(
444 unsafe { JsArrayBuffer::from_raw_unchecked(self.0, raw_value) },
445 data_ptr as *mut c_void,
446 length,
447 ))
448 }
449
450 pub fn create_arraybuffer_with_data(&self, mut data: Vec<u8>) -> Result<JsArrayBufferValue> {
451 let length = data.len();
452 let mut raw_value = ptr::null_mut();
453 let data_ptr = data.as_mut_ptr();
454 check_status!(unsafe {
455 if length == 0 {
456 sys::napi_create_arraybuffer(self.0, length, ptr::null_mut(), &mut raw_value)
460 } else {
461 let hint_ptr = Box::into_raw(Box::new((length, data.capacity())));
462 let status = sys::napi_create_external_arraybuffer(
463 self.0,
464 data_ptr.cast(),
465 length,
466 Some(drop_buffer),
467 hint_ptr.cast(),
468 &mut raw_value,
469 );
470 if status == sys::Status::napi_no_external_buffers_allowed {
471 drop(Box::from_raw(hint_ptr));
472 let mut underlying_data = ptr::null_mut();
473 let status =
474 sys::napi_create_arraybuffer(self.0, length, &mut underlying_data, &mut raw_value);
475 ptr::copy_nonoverlapping(data_ptr, underlying_data.cast(), length);
476 status
477 } else {
478 status
479 }
480 }
481 })?;
482
483 mem::forget(data);
484 Ok(JsArrayBufferValue::new(
485 JsArrayBuffer(Value {
486 env: self.0,
487 value: raw_value,
488 value_type: ValueType::Object,
489 }),
490 data_ptr.cast(),
491 length,
492 ))
493 }
494
495 pub unsafe fn create_arraybuffer_with_borrowed_data<Hint, Finalize>(
511 &self,
512 data: *mut u8,
513 length: usize,
514 hint: Hint,
515 finalize_callback: Finalize,
516 ) -> Result<JsArrayBufferValue>
517 where
518 Finalize: FnOnce(Hint, Env),
519 {
520 let mut raw_value = ptr::null_mut();
521 let hint_ptr = Box::into_raw(Box::new((hint, finalize_callback)));
522 unsafe {
523 let status = sys::napi_create_external_arraybuffer(
524 self.0,
525 if length == 0 {
526 ptr::null_mut()
530 } else {
531 data as *mut c_void
532 },
533 length,
534 Some(
535 raw_finalize_with_custom_callback::<Hint, Finalize>
536 as unsafe extern "C" fn(
537 env: sys::napi_env,
538 finalize_data: *mut c_void,
539 finalize_hint: *mut c_void,
540 ),
541 ),
542 hint_ptr.cast(),
543 &mut raw_value,
544 );
545 if status == sys::Status::napi_no_external_buffers_allowed {
546 let (hint, finalize) = *Box::from_raw(hint_ptr);
547 let mut underlying_data = ptr::null_mut();
548 let status =
549 sys::napi_create_arraybuffer(self.0, length, &mut underlying_data, &mut raw_value);
550 ptr::copy_nonoverlapping(data, underlying_data.cast(), length);
551 finalize(hint, *self);
552 check_status!(status)?;
553 } else {
554 check_status!(status)?;
555 }
556 };
557 Ok(JsArrayBufferValue::new(
558 JsArrayBuffer(Value {
559 env: self.0,
560 value: raw_value,
561 value_type: ValueType::Object,
562 }),
563 data as *mut c_void,
564 length,
565 ))
566 }
567
568 pub fn create_function(&self, name: &str, callback: Callback) -> Result<JsFunction> {
576 let mut raw_result = ptr::null_mut();
577 let len = name.len();
578 let name = CString::new(name)?;
579 check_status!(unsafe {
580 sys::napi_create_function(
581 self.0,
582 name.as_ptr(),
583 len,
584 Some(callback),
585 ptr::null_mut(),
586 &mut raw_result,
587 )
588 })?;
589
590 Ok(unsafe { JsFunction::from_raw_unchecked(self.0, raw_result) })
591 }
592
593 #[cfg(feature = "napi5")]
594 pub fn create_function_from_closure<R, F>(&self, name: &str, callback: F) -> Result<JsFunction>
595 where
596 F: 'static + Fn(crate::CallContext<'_>) -> Result<R>,
597 R: ToNapiValue,
598 {
599 let closure_data_ptr = Box::into_raw(Box::new(callback));
600
601 let mut raw_result = ptr::null_mut();
602 let len = name.len();
603 let name = CString::new(name)?;
604 check_status!(unsafe {
605 sys::napi_create_function(
606 self.0,
607 name.as_ptr(),
608 len,
609 Some(trampoline::<R, F>),
610 closure_data_ptr.cast(), &mut raw_result,
612 )
613 })?;
614
615 check_status!(unsafe {
624 sys::napi_add_finalizer(
625 self.0,
626 raw_result,
627 closure_data_ptr.cast(),
628 Some(finalize_box_trampoline::<F>),
629 ptr::null_mut(),
630 ptr::null_mut(),
631 )
632 })?;
633
634 Ok(unsafe { JsFunction::from_raw_unchecked(self.0, raw_result) })
635 }
636
637 pub fn get_last_error_info(&self) -> Result<ExtendedErrorInfo> {
645 let mut raw_extended_error = ptr::null();
646 check_status!(unsafe { sys::napi_get_last_error_info(self.0, &mut raw_extended_error) })?;
647 unsafe { ptr::read(raw_extended_error) }.try_into()
648 }
649
650 pub fn throw<T: NapiRaw>(&self, value: T) -> Result<()> {
652 check_status!(unsafe { sys::napi_throw(self.0, value.raw()) })
653 }
654
655 pub fn throw_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
657 let code = code.and_then(|s| CString::new(s).ok());
658 let msg = CString::new(msg)?;
659 check_status!(unsafe {
660 sys::napi_throw_error(
661 self.0,
662 code.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()),
663 msg.as_ptr(),
664 )
665 })
666 }
667
668 pub fn throw_range_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
670 let code = code.and_then(|s| CString::new(s).ok());
671 let msg = CString::new(msg)?;
672 check_status!(unsafe {
673 sys::napi_throw_range_error(
674 self.0,
675 code.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()),
676 msg.as_ptr(),
677 )
678 })
679 }
680
681 pub fn throw_type_error(&self, msg: &str, code: Option<&str>) -> Result<()> {
683 let code = code.and_then(|s| CString::new(s).ok());
684 let msg = CString::new(msg)?;
685 check_status!(unsafe {
686 sys::napi_throw_type_error(
687 self.0,
688 code.as_ref().map(|s| s.as_ptr()).unwrap_or(ptr::null_mut()),
689 msg.as_ptr(),
690 )
691 })
692 }
693
694 #[cfg(feature = "napi9")]
696 pub fn throw_syntax_error<S: AsRef<str>, C: AsRef<str>>(&self, msg: S, code: Option<C>) {
697 use crate::check_status_or_throw;
698
699 let code = code.as_ref().map(|c| c.as_ref()).unwrap_or("");
700 let c_code = CString::new(code).expect("code must be a valid utf-8 string");
701 let code_ptr = c_code.as_ptr();
702 let msg: CString = CString::new(msg.as_ref()).expect("msg must be a valid utf-8 string");
703 let msg_ptr = msg.as_ptr();
704 check_status_or_throw!(
705 self.0,
706 unsafe { sys::node_api_throw_syntax_error(self.0, code_ptr, msg_ptr,) },
707 "Throw syntax error failed"
708 );
709 }
710
711 #[allow(clippy::expect_fun_call)]
712 pub fn fatal_error(self, location: &str, message: &str) {
716 let location_len = location.len();
717 let message_len = message.len();
718 let location =
719 CString::new(location).expect(format!("Convert [{}] to CString failed", location).as_str());
720 let message =
721 CString::new(message).expect(format!("Convert [{}] to CString failed", message).as_str());
722
723 unsafe {
724 sys::napi_fatal_error(
725 location.as_ptr(),
726 location_len,
727 message.as_ptr(),
728 message_len,
729 )
730 }
731 }
732
733 #[cfg(feature = "napi3")]
734 pub fn fatal_exception(&self, err: Error) {
738 unsafe {
739 let js_error = JsError::from(err).into_value(self.0);
740 debug_assert!(sys::napi_fatal_exception(self.0, js_error) == sys::Status::napi_ok);
741 };
742 }
743
744 pub fn define_class(
746 &self,
747 name: &str,
748 constructor_cb: Callback,
749 properties: &[Property],
750 ) -> Result<JsFunction> {
751 let mut raw_result = ptr::null_mut();
752 let raw_properties = properties
753 .iter()
754 .map(|prop| prop.raw())
755 .collect::<Vec<sys::napi_property_descriptor>>();
756 let c_name = CString::new(name)?;
757 check_status!(unsafe {
758 sys::napi_define_class(
759 self.0,
760 c_name.as_ptr() as *const c_char,
761 name.len(),
762 Some(constructor_cb),
763 ptr::null_mut(),
764 raw_properties.len(),
765 raw_properties.as_ptr(),
766 &mut raw_result,
767 )
768 })?;
769
770 Ok(unsafe { JsFunction::from_raw_unchecked(self.0, raw_result) })
771 }
772
773 #[allow(clippy::needless_pass_by_ref_mut)]
774 pub fn wrap<T: 'static>(&self, js_object: &mut JsObject, native_object: T) -> Result<()> {
775 check_status!(unsafe {
776 sys::napi_wrap(
777 self.0,
778 js_object.0.value,
779 Box::into_raw(Box::new(TaggedObject::new(native_object))).cast(),
780 Some(raw_finalize::<T>),
781 ptr::null_mut(),
782 ptr::null_mut(),
783 )
784 })
785 }
786
787 pub fn unwrap<T: 'static>(&self, js_object: &JsObject) -> Result<&mut T> {
788 unsafe {
789 let mut unknown_tagged_object: *mut c_void = ptr::null_mut();
790 check_status!(sys::napi_unwrap(
791 self.0,
792 js_object.0.value,
793 &mut unknown_tagged_object,
794 ))?;
795
796 let type_id = unknown_tagged_object as *const TypeId;
797 if *type_id == TypeId::of::<T>() {
798 let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
799 (*tagged_object).object.as_mut().ok_or_else(|| {
800 Error::new(
801 Status::InvalidArg,
802 "Invalid argument, nothing attach to js_object".to_owned(),
803 )
804 })
805 } else {
806 Err(Error::new(
807 Status::InvalidArg,
808 format!(
809 "Invalid argument, {} on unwrap is not the type of wrapped object",
810 type_name::<T>()
811 ),
812 ))
813 }
814 }
815 }
816
817 pub fn drop_wrapped<T: 'static>(&self, js_object: &JsObject) -> Result<()> {
818 unsafe {
819 let mut unknown_tagged_object = ptr::null_mut();
820 check_status!(sys::napi_remove_wrap(
821 self.0,
822 js_object.0.value,
823 &mut unknown_tagged_object,
824 ))?;
825 let type_id = unknown_tagged_object as *const TypeId;
826 if *type_id == TypeId::of::<T>() {
827 drop(Box::from_raw(unknown_tagged_object as *mut TaggedObject<T>));
828 Ok(())
829 } else {
830 Err(Error::new(
831 Status::InvalidArg,
832 format!(
833 "Invalid argument, {} on unwrap is not the type of wrapped object",
834 type_name::<T>()
835 ),
836 ))
837 }
838 }
839 }
840
841 pub fn create_reference<T>(&self, value: T) -> Result<Ref<()>>
843 where
844 T: NapiRaw,
845 {
846 let mut raw_ref = ptr::null_mut();
847 let initial_ref_count = 1;
848 let raw_value = unsafe { value.raw() };
849 check_status!(unsafe {
850 sys::napi_create_reference(self.0, raw_value, initial_ref_count, &mut raw_ref)
851 })?;
852 Ok(Ref {
853 raw_ref,
854 count: 1,
855 inner: (),
856 })
857 }
858
859 pub fn create_reference_with_refcount<T>(&self, value: T, ref_count: u32) -> Result<Ref<()>>
861 where
862 T: NapiRaw,
863 {
864 let mut raw_ref = ptr::null_mut();
865 let raw_value = unsafe { value.raw() };
866 check_status!(unsafe {
867 sys::napi_create_reference(self.0, raw_value, ref_count, &mut raw_ref)
868 })?;
869 Ok(Ref {
870 raw_ref,
871 count: ref_count,
872 inner: (),
873 })
874 }
875
876 pub fn get_reference_value<T>(&self, reference: &Ref<()>) -> Result<T>
880 where
881 T: NapiValue,
882 {
883 let mut js_value = ptr::null_mut();
884 check_status!(unsafe {
885 sys::napi_get_reference_value(self.0, reference.raw_ref, &mut js_value)
886 })?;
887 unsafe { T::from_raw(self.0, js_value) }
888 }
889
890 pub fn get_reference_value_unchecked<T>(&self, reference: &Ref<()>) -> Result<T>
896 where
897 T: NapiValue,
898 {
899 let mut js_value = ptr::null_mut();
900 check_status!(unsafe {
901 sys::napi_get_reference_value(self.0, reference.raw_ref, &mut js_value)
902 })?;
903 Ok(unsafe { T::from_raw_unchecked(self.0, js_value) })
904 }
905
906 pub fn create_external<T: 'static>(
912 &self,
913 native_object: T,
914 size_hint: Option<i64>,
915 ) -> Result<JsExternal> {
916 let mut object_value = ptr::null_mut();
917 check_status!(unsafe {
918 sys::napi_create_external(
919 self.0,
920 Box::into_raw(Box::new(TaggedObject::new(native_object))).cast(),
921 Some(raw_finalize::<T>),
922 Box::into_raw(Box::new(size_hint)).cast(),
923 &mut object_value,
924 )
925 })?;
926 if let Some(changed) = size_hint {
927 if changed != 0 {
928 let mut adjusted_value = 0i64;
929 check_status!(unsafe {
930 sys::napi_adjust_external_memory(self.0, changed, &mut adjusted_value)
931 })?;
932 }
933 };
934 Ok(unsafe { JsExternal::from_raw_unchecked(self.0, object_value) })
935 }
936
937 pub fn get_value_external<T: 'static>(&self, js_external: &JsExternal) -> Result<&mut T> {
938 unsafe {
939 let mut unknown_tagged_object = ptr::null_mut();
940 check_status!(sys::napi_get_value_external(
941 self.0,
942 js_external.0.value,
943 &mut unknown_tagged_object,
944 ))?;
945
946 let type_id = unknown_tagged_object as *const TypeId;
947 if *type_id == TypeId::of::<T>() {
948 let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
949 (*tagged_object).object.as_mut().ok_or_else(|| {
950 Error::new(
951 Status::InvalidArg,
952 "nothing attach to js_external".to_owned(),
953 )
954 })
955 } else {
956 Err(Error::new(
957 Status::InvalidArg,
958 "T on get_value_external is not the type of wrapped object".to_owned(),
959 ))
960 }
961 }
962 }
963
964 pub fn create_error(&self, e: Error) -> Result<JsObject> {
965 let reason = &e.reason;
966 let reason_string = self.create_string(reason.as_str())?;
967 let mut result = ptr::null_mut();
968 check_status!(unsafe {
969 sys::napi_create_error(self.0, ptr::null_mut(), reason_string.0.value, &mut result)
970 })?;
971 Ok(unsafe { JsObject::from_raw_unchecked(self.0, result) })
972 }
973
974 pub fn spawn<T: 'static + Task>(&self, task: T) -> Result<AsyncWorkPromise> {
976 async_work::run(self.0, task, None)
977 }
978
979 pub fn run_in_scope<T, F>(&self, executor: F) -> Result<T>
980 where
981 F: FnOnce() -> Result<T>,
982 {
983 let mut handle_scope = ptr::null_mut();
984 check_status!(unsafe { sys::napi_open_handle_scope(self.0, &mut handle_scope) })?;
985
986 let result = executor();
987
988 check_status!(unsafe { sys::napi_close_handle_scope(self.0, handle_scope) })?;
989 result
990 }
991
992 pub fn run_script<S: AsRef<str>, V: FromNapiValue>(&self, script: S) -> Result<V> {
998 let s = self.create_string(script.as_ref())?;
999 let mut raw_value = ptr::null_mut();
1000 check_status!(unsafe { sys::napi_run_script(self.0, s.raw(), &mut raw_value) })?;
1001 unsafe { V::from_napi_value(self.0, raw_value) }
1002 }
1003
1004 pub fn get_napi_version(&self) -> Result<u32> {
1006 let global = self.get_global()?;
1007 let process: JsObject = global.get_named_property("process")?;
1008 let versions: JsObject = process.get_named_property("versions")?;
1009 let napi_version: JsString = versions.get_named_property("napi")?;
1010 napi_version
1011 .into_utf8()?
1012 .as_str()?
1013 .parse()
1014 .map_err(|e| Error::new(Status::InvalidArg, format!("{}", e)))
1015 }
1016
1017 #[cfg(all(feature = "napi2", not(target_family = "wasm")))]
1018 pub fn get_uv_event_loop(&self) -> Result<*mut sys::uv_loop_s> {
1019 let mut uv_loop: *mut sys::uv_loop_s = ptr::null_mut();
1020 check_status!(unsafe { sys::napi_get_uv_event_loop(self.0, &mut uv_loop) })?;
1021 Ok(uv_loop)
1022 }
1023
1024 #[cfg(feature = "napi3")]
1025 pub fn add_env_cleanup_hook<T, F>(
1026 &mut self,
1027 cleanup_data: T,
1028 cleanup_fn: F,
1029 ) -> Result<CleanupEnvHook<T>>
1030 where
1031 T: 'static,
1032 F: 'static + FnOnce(T),
1033 {
1034 let hook = CleanupEnvHookData {
1035 data: cleanup_data,
1036 hook: Box::new(cleanup_fn),
1037 };
1038 let hook_ref = Box::leak(Box::new(hook));
1039 check_status!(unsafe {
1040 sys::napi_add_env_cleanup_hook(
1041 self.0,
1042 Some(cleanup_env::<T>),
1043 hook_ref as *mut CleanupEnvHookData<T> as *mut _,
1044 )
1045 })?;
1046 Ok(CleanupEnvHook(hook_ref))
1047 }
1048
1049 #[cfg(feature = "napi3")]
1050 pub fn remove_env_cleanup_hook<T>(&mut self, hook: CleanupEnvHook<T>) -> Result<()>
1051 where
1052 T: 'static,
1053 {
1054 check_status!(unsafe {
1055 sys::napi_remove_env_cleanup_hook(self.0, Some(cleanup_env::<T>), hook.0 as *mut _)
1056 })
1057 }
1058
1059 #[cfg(feature = "napi4")]
1060 pub fn create_threadsafe_function<
1061 T: Send,
1062 V: ToNapiValue,
1063 R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
1064 >(
1065 &self,
1066 func: &JsFunction,
1067 max_queue_size: usize,
1068 callback: R,
1069 ) -> Result<ThreadsafeFunction<T>> {
1070 ThreadsafeFunction::create(self.0, func.0.value, max_queue_size, callback)
1071 }
1072
1073 #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
1074 pub fn execute_tokio_future<
1075 T: 'static + Send,
1076 V: 'static + ToNapiValue,
1077 F: 'static + Send + Future<Output = Result<T>>,
1078 R: 'static + FnOnce(&mut Env, T) -> Result<V>,
1079 >(
1080 &self,
1081 fut: F,
1082 resolver: R,
1083 ) -> Result<JsObject> {
1084 use crate::tokio_runtime;
1085
1086 let promise = tokio_runtime::execute_tokio_future(self.0, fut, |env, val| unsafe {
1087 resolver(&mut Env::from_raw(env), val).and_then(|v| ToNapiValue::to_napi_value(env, v))
1088 })?;
1089
1090 Ok(unsafe { JsObject::from_raw_unchecked(self.0, promise) })
1091 }
1092
1093 #[cfg(all(feature = "tokio_rt", feature = "napi4"))]
1094 pub fn spawn_future<
1095 T: 'static + Send + ToNapiValue,
1096 F: 'static + Send + Future<Output = Result<T>>,
1097 >(
1098 &self,
1099 fut: F,
1100 ) -> Result<JsObject> {
1101 use crate::tokio_runtime;
1102
1103 let promise = tokio_runtime::execute_tokio_future(self.0, fut, |env, val| unsafe {
1104 ToNapiValue::to_napi_value(env, val)
1105 })?;
1106
1107 Ok(unsafe { JsObject::from_raw_unchecked(self.0, promise) })
1108 }
1109
1110 #[cfg(feature = "napi4")]
1112 pub fn create_deferred<Data: ToNapiValue, Resolver: FnOnce(Env) -> Result<Data>>(
1113 &self,
1114 ) -> Result<(JsDeferred<Data, Resolver>, JsObject)> {
1115 JsDeferred::new(self.raw())
1116 }
1117
1118 #[cfg(feature = "napi5")]
1124 pub fn create_date(&self, time: f64) -> Result<JsDate> {
1125 let mut js_value = ptr::null_mut();
1126 check_status!(unsafe { sys::napi_create_date(self.0, time, &mut js_value) })?;
1127 Ok(unsafe { JsDate::from_raw_unchecked(self.0, js_value) })
1128 }
1129
1130 #[cfg(feature = "napi6")]
1131
1132 pub fn set_instance_data<T, Hint, F>(&self, native: T, hint: Hint, finalize_cb: F) -> Result<()>
1138 where
1139 T: 'static,
1140 Hint: 'static,
1141 F: FnOnce(FinalizeContext<T, Hint>),
1142 {
1143 check_status!(unsafe {
1144 sys::napi_set_instance_data(
1145 self.0,
1146 Box::leak(Box::new((TaggedObject::new(native), finalize_cb))) as *mut (TaggedObject<T>, F)
1147 as *mut c_void,
1148 Some(
1149 set_instance_finalize_callback::<T, Hint, F>
1150 as unsafe extern "C" fn(
1151 env: sys::napi_env,
1152 finalize_data: *mut c_void,
1153 finalize_hint: *mut c_void,
1154 ),
1155 ),
1156 Box::leak(Box::new(hint)) as *mut Hint as *mut c_void,
1157 )
1158 })
1159 }
1160
1161 #[cfg(feature = "napi6")]
1165 pub fn get_instance_data<T>(&self) -> Result<Option<&'static mut T>>
1166 where
1167 T: 'static,
1168 {
1169 let mut unknown_tagged_object: *mut c_void = ptr::null_mut();
1170 unsafe {
1171 check_status!(sys::napi_get_instance_data(
1172 self.0,
1173 &mut unknown_tagged_object
1174 ))?;
1175 let type_id = unknown_tagged_object as *const TypeId;
1176 if unknown_tagged_object.is_null() {
1177 return Ok(None);
1178 }
1179 if *type_id == TypeId::of::<T>() {
1180 let tagged_object = unknown_tagged_object as *mut TaggedObject<T>;
1181 (*tagged_object).object.as_mut().map(Some).ok_or_else(|| {
1182 Error::new(
1183 Status::InvalidArg,
1184 "Invalid argument, nothing attach to js_object".to_owned(),
1185 )
1186 })
1187 } else {
1188 Err(Error::new(
1189 Status::InvalidArg,
1190 format!(
1191 "Invalid argument, {} on unwrap is not the type of wrapped object",
1192 type_name::<T>()
1193 ),
1194 ))
1195 }
1196 }
1197 }
1198
1199 #[cfg(feature = "napi8")]
1205 pub fn add_removable_async_cleanup_hook<Arg, F>(
1206 &self,
1207 arg: Arg,
1208 cleanup_fn: F,
1209 ) -> Result<AsyncCleanupHook>
1210 where
1211 F: FnOnce(Arg),
1212 Arg: 'static,
1213 {
1214 let mut handle = ptr::null_mut();
1215 check_status!(unsafe {
1216 sys::napi_add_async_cleanup_hook(
1217 self.0,
1218 Some(
1219 async_finalize::<Arg, F>
1220 as unsafe extern "C" fn(handle: sys::napi_async_cleanup_hook_handle, data: *mut c_void),
1221 ),
1222 Box::leak(Box::new((arg, cleanup_fn))) as *mut (Arg, F) as *mut c_void,
1223 &mut handle,
1224 )
1225 })?;
1226 Ok(AsyncCleanupHook(handle))
1227 }
1228
1229 #[cfg(feature = "napi8")]
1233 pub fn add_async_cleanup_hook<Arg, F>(&self, arg: Arg, cleanup_fn: F) -> Result<()>
1234 where
1235 F: FnOnce(Arg),
1236 Arg: 'static,
1237 {
1238 check_status!(unsafe {
1239 sys::napi_add_async_cleanup_hook(
1240 self.0,
1241 Some(
1242 async_finalize::<Arg, F>
1243 as unsafe extern "C" fn(handle: sys::napi_async_cleanup_hook_handle, data: *mut c_void),
1244 ),
1245 Box::leak(Box::new((arg, cleanup_fn))) as *mut (Arg, F) as *mut c_void,
1246 ptr::null_mut(),
1247 )
1248 })
1249 }
1250
1251 #[cfg(feature = "napi9")]
1252 pub fn symbol_for(&self, description: &str) -> Result<JsSymbol> {
1253 let mut result = ptr::null_mut();
1254 let len = description.len();
1255 let description = CString::new(description)?;
1256 check_status!(unsafe {
1257 sys::node_api_symbol_for(self.0, description.as_ptr(), len, &mut result)
1258 })?;
1259
1260 Ok(unsafe { JsSymbol::from_raw_unchecked(self.0, result) })
1261 }
1262
1263 #[cfg(feature = "napi9")]
1264 pub fn get_module_file_name(&self) -> Result<String> {
1272 let mut char_ptr = ptr::null();
1273 check_status!(
1274 unsafe { sys::node_api_get_module_file_name(self.0, &mut char_ptr) },
1275 "call node_api_get_module_file_name failed"
1276 )?;
1277 let module_filename = unsafe { std::ffi::CStr::from_ptr(char_ptr) };
1280
1281 Ok(module_filename.to_string_lossy().into_owned())
1282 }
1283
1284 #[cfg(feature = "serde-json")]
1301 #[allow(clippy::wrong_self_convention)]
1302 pub fn to_js_value<T>(&self, node: &T) -> Result<JsUnknown>
1303 where
1304 T: Serialize,
1305 {
1306 let s = Ser(self);
1307 node.serialize(s).map(JsUnknown)
1308 }
1309
1310 #[cfg(feature = "serde-json")]
1327 pub fn from_js_value<T, V>(&self, value: V) -> Result<T>
1328 where
1329 T: DeserializeOwned,
1330 V: NapiRaw,
1331 {
1332 let value = Value {
1333 env: self.0,
1334 value: unsafe { value.raw() },
1335 value_type: ValueType::Unknown,
1336 };
1337 let mut de = De(&value);
1338 T::deserialize(&mut de)
1339 }
1340
1341 pub fn strict_equals<A: NapiRaw, B: NapiRaw>(&self, a: A, b: B) -> Result<bool> {
1343 let mut result = false;
1344 check_status!(unsafe { sys::napi_strict_equals(self.0, a.raw(), b.raw(), &mut result) })?;
1345 Ok(result)
1346 }
1347
1348 pub fn get_node_version(&self) -> Result<NodeVersion> {
1349 let mut result = ptr::null();
1350 check_status!(unsafe { sys::napi_get_node_version(self.0, &mut result) })?;
1351 let version = unsafe { *result };
1352 version.try_into()
1353 }
1354
1355 pub fn raw(&self) -> sys::napi_env {
1357 self.0
1358 }
1359}
1360
1361pub fn noop_finalize<Hint>(_hint: Hint, _env: Env) {}
1363
1364unsafe extern "C" fn drop_buffer(
1365 _env: sys::napi_env,
1366 finalize_data: *mut c_void,
1367 hint: *mut c_void,
1368) {
1369 let length_ptr = hint as *mut (usize, usize);
1370 let (length, cap) = unsafe { *Box::from_raw(length_ptr) };
1371 mem::drop(unsafe { Vec::from_raw_parts(finalize_data as *mut u8, length, cap) });
1372}
1373
1374pub(crate) unsafe extern "C" fn raw_finalize<T>(
1375 env: sys::napi_env,
1376 finalize_data: *mut c_void,
1377 finalize_hint: *mut c_void,
1378) {
1379 let tagged_object = finalize_data as *mut TaggedObject<T>;
1380 drop(unsafe { Box::from_raw(tagged_object) });
1381 #[cfg(not(target_family = "wasm"))]
1382 if !finalize_hint.is_null() {
1383 let size_hint = unsafe { *Box::from_raw(finalize_hint as *mut Option<i64>) };
1384 if let Some(changed) = size_hint {
1385 if changed != 0 {
1386 let mut adjusted = 0i64;
1387 let status = unsafe { sys::napi_adjust_external_memory(env, -changed, &mut adjusted) };
1388 debug_assert!(
1389 status == sys::Status::napi_ok,
1390 "Calling napi_adjust_external_memory failed"
1391 );
1392 }
1393 };
1394 }
1395}
1396
1397#[cfg(feature = "napi6")]
1398unsafe extern "C" fn set_instance_finalize_callback<T, Hint, F>(
1399 raw_env: sys::napi_env,
1400 finalize_data: *mut c_void,
1401 finalize_hint: *mut c_void,
1402) where
1403 T: 'static,
1404 Hint: 'static,
1405 F: FnOnce(FinalizeContext<T, Hint>),
1406{
1407 let (value, callback) = unsafe { *Box::from_raw(finalize_data as *mut (TaggedObject<T>, F)) };
1408 let hint = unsafe { *Box::from_raw(finalize_hint as *mut Hint) };
1409 let env = unsafe { Env::from_raw(raw_env) };
1410 callback(FinalizeContext {
1411 value: value.object.unwrap(),
1412 hint,
1413 env,
1414 });
1415}
1416
1417#[cfg(feature = "napi3")]
1418unsafe extern "C" fn cleanup_env<T: 'static>(hook_data: *mut c_void) {
1419 let cleanup_env_hook = unsafe { Box::from_raw(hook_data as *mut CleanupEnvHookData<T>) };
1420 (cleanup_env_hook.hook)(cleanup_env_hook.data);
1421}
1422
1423unsafe extern "C" fn raw_finalize_with_custom_callback<Hint, Finalize>(
1424 env: sys::napi_env,
1425 _finalize_data: *mut c_void,
1426 finalize_hint: *mut c_void,
1427) where
1428 Finalize: FnOnce(Hint, Env),
1429{
1430 let (hint, callback) = unsafe { *Box::from_raw(finalize_hint as *mut (Hint, Finalize)) };
1431 callback(hint, unsafe { Env::from_raw(env) });
1432}
1433
1434#[cfg(feature = "napi8")]
1435unsafe extern "C" fn async_finalize<Arg, F>(
1436 handle: sys::napi_async_cleanup_hook_handle,
1437 data: *mut c_void,
1438) where
1439 Arg: 'static,
1440 F: FnOnce(Arg),
1441{
1442 let (arg, callback) = unsafe { *Box::from_raw(data as *mut (Arg, F)) };
1443 callback(arg);
1444 if !handle.is_null() {
1445 let status = unsafe { sys::napi_remove_async_cleanup_hook(handle) };
1446 assert!(
1447 status == sys::Status::napi_ok,
1448 "Remove async cleanup hook failed after async cleanup callback"
1449 );
1450 }
1451}
1452
1453#[cfg(feature = "napi5")]
1454pub(crate) unsafe extern "C" fn trampoline<
1455 R: ToNapiValue,
1456 F: Fn(crate::CallContext) -> Result<R>,
1457>(
1458 raw_env: sys::napi_env,
1459 cb_info: sys::napi_callback_info,
1460) -> sys::napi_value {
1461 use crate::CallContext;
1462
1463 let (raw_this, raw_args, closure_data_ptr, argc) = {
1464 let mut argc = 4;
1466 let mut raw_args = Vec::with_capacity(4);
1467 let mut raw_this = ptr::null_mut();
1468 let mut closure_data_ptr = ptr::null_mut();
1469
1470 let status = unsafe {
1471 sys::napi_get_cb_info(
1472 raw_env,
1473 cb_info,
1474 &mut argc,
1475 raw_args.as_mut_ptr(),
1476 &mut raw_this,
1477 &mut closure_data_ptr,
1478 )
1479 };
1480 debug_assert!(
1481 Status::from(status) == Status::Ok,
1482 "napi_get_cb_info failed"
1483 );
1484
1485 if argc > 4 {
1487 raw_args = vec![ptr::null_mut(); argc];
1488 let status = unsafe {
1489 sys::napi_get_cb_info(
1490 raw_env,
1491 cb_info,
1492 &mut argc,
1493 raw_args.as_mut_ptr(),
1494 &mut raw_this,
1495 &mut closure_data_ptr,
1496 )
1497 };
1498 debug_assert!(
1499 Status::from(status) == Status::Ok,
1500 "napi_get_cb_info failed"
1501 );
1502 } else {
1503 unsafe { raw_args.set_len(argc) };
1504 }
1505
1506 (raw_this, raw_args, closure_data_ptr, argc)
1507 };
1508
1509 let closure: &F = Box::leak(unsafe { Box::from_raw(closure_data_ptr.cast()) });
1510 let mut env = unsafe { Env::from_raw(raw_env) };
1511 let call_context = CallContext::new(&mut env, cb_info, raw_this, raw_args.as_slice(), argc);
1512 closure(call_context)
1513 .and_then(|ret: R| unsafe { <R as ToNapiValue>::to_napi_value(env.0, ret) })
1514 .unwrap_or_else(|e| {
1515 unsafe { JsError::from(e).throw_into(raw_env) };
1516 ptr::null_mut()
1517 })
1518}
1519
1520#[cfg(feature = "napi5")]
1521pub(crate) unsafe extern "C" fn trampoline_setter<
1522 V: FromNapiValue,
1523 F: Fn(Env, crate::bindgen_runtime::Object, V) -> Result<()>,
1524>(
1525 raw_env: sys::napi_env,
1526 cb_info: sys::napi_callback_info,
1527) -> sys::napi_value {
1528 use crate::bindgen_runtime::Object;
1529
1530 let (raw_args, raw_this, closure_data_ptr) = {
1531 let mut argc = 1;
1532 let mut raw_args = vec![ptr::null_mut(); 1];
1533 let mut raw_this = ptr::null_mut();
1534 let mut data_ptr = ptr::null_mut();
1535
1536 let status = unsafe {
1537 sys::napi_get_cb_info(
1538 raw_env,
1539 cb_info,
1540 &mut argc,
1541 raw_args.as_mut_ptr(),
1542 &mut raw_this,
1543 &mut data_ptr,
1544 )
1545 };
1546 unsafe { raw_args.set_len(argc) };
1547 debug_assert!(
1548 Status::from(status) == Status::Ok,
1549 "napi_get_cb_info failed"
1550 );
1551
1552 let closure_data_ptr = unsafe { *(data_ptr as *mut PropertyClosures) }.setter_closure;
1553 (raw_args, raw_this, closure_data_ptr)
1554 };
1555
1556 let closure: &F = Box::leak(unsafe { Box::from_raw(closure_data_ptr.cast()) });
1557 let env = unsafe { Env::from_raw(raw_env) };
1558 raw_args
1559 .first()
1560 .ok_or_else(|| Error::new(Status::InvalidArg, "Missing argument in property setter"))
1561 .and_then(|value| unsafe { V::from_napi_value(raw_env, *value) })
1562 .and_then(|value| {
1563 closure(
1564 env,
1565 unsafe { Object::from_raw_unchecked(raw_env, raw_this) },
1566 value,
1567 )
1568 })
1569 .map(|_| std::ptr::null_mut())
1570 .unwrap_or_else(|e| {
1571 unsafe { JsError::from(e).throw_into(raw_env) };
1572 ptr::null_mut()
1573 })
1574}
1575
1576#[cfg(feature = "napi5")]
1577pub(crate) unsafe extern "C" fn trampoline_getter<
1578 R: ToNapiValue,
1579 F: Fn(Env, crate::bindgen_runtime::This) -> Result<R>,
1580>(
1581 raw_env: sys::napi_env,
1582 cb_info: sys::napi_callback_info,
1583) -> sys::napi_value {
1584 let (raw_this, closure_data_ptr) = {
1585 let mut raw_this = ptr::null_mut();
1586 let mut data_ptr = ptr::null_mut();
1587
1588 let status = unsafe {
1589 sys::napi_get_cb_info(
1590 raw_env,
1591 cb_info,
1592 &mut 0,
1593 ptr::null_mut(),
1594 &mut raw_this,
1595 &mut data_ptr,
1596 )
1597 };
1598 debug_assert!(
1599 Status::from(status) == Status::Ok,
1600 "napi_get_cb_info failed"
1601 );
1602
1603 let closure_data_ptr = unsafe { *(data_ptr as *mut PropertyClosures) }.getter_closure;
1604 (raw_this, closure_data_ptr)
1605 };
1606
1607 let closure: &F = Box::leak(unsafe { Box::from_raw(closure_data_ptr.cast()) });
1608 let env = unsafe { Env::from_raw(raw_env) };
1609 closure(env, unsafe {
1610 crate::bindgen_runtime::Object::from_raw_unchecked(raw_env, raw_this)
1611 })
1612 .and_then(|ret: R| unsafe { <R as ToNapiValue>::to_napi_value(env.0, ret) })
1613 .unwrap_or_else(|e| {
1614 unsafe { JsError::from(e).throw_into(raw_env) };
1615 ptr::null_mut()
1616 })
1617}
1618
1619#[cfg(feature = "napi5")]
1620pub(crate) unsafe extern "C" fn finalize_box_trampoline<F>(
1621 _raw_env: sys::napi_env,
1622 closure_data_ptr: *mut c_void,
1623 _finalize_hint: *mut c_void,
1624) {
1625 drop(unsafe { Box::<F>::from_raw(closure_data_ptr.cast()) })
1626}