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