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)]
44/// `Env` is used to represent a context that the underlying N-API implementation can use to persist VM-specific state.
45///
46/// Specifically, the same `Env` that was passed in when the initial native function was called must be passed to any subsequent nested N-API calls.
47///
48/// Caching the `Env` for the purpose of general reuse, and passing the `Env` between instances of the same addon running on different Worker threads is not allowed.
49///
50/// The `Env` becomes invalid when an instance of a native addon is unloaded.
51///
52/// Notification of this event is delivered through the callbacks given to `Env::add_env_cleanup_hook` and `Env::set_instance_data`.
53pub 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 /// [n_api_napi_create_bigint_int64](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_int64)
104 #[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 /// [n_api_napi_create_bigint_words](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_words)
138 ///
139 /// The resulting BigInt will be negative when sign_bit is true.
140 #[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 /// This API is used for C ffi scenario.
168 /// Convert raw *const c_char into JsString
169 ///
170 /// # Safety
171 ///
172 /// Create JsString from known valid utf-8 string
173 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 /// This API allocates a node::Buffer object. While this is still a fully-supported data structure, in most cases using a TypedArray will suffice.
244 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 /// This API allocates a node::Buffer object and initializes it with data backed by the passed in buffer.
262 ///
263 /// While this is still a fully-supported data structure, in most cases using a TypedArray will suffice.
264 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 // Rust uses 0x1 as the data pointer for empty buffers,
272 // but NAPI/V8 only allows multiple buffers to have
273 // the same data pointer if it's 0x0.
274 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 // electron doesn't support external buffers
285 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 /// # Safety
313 /// Mostly the same with `create_buffer_with_data`
314 ///
315 /// Provided `finalize_callback` will be called when `Buffer` got dropped.
316 ///
317 /// You can pass in `noop_finalize` if you have nothing to do in finalize phase.
318 ///
319 /// # Notes
320 ///
321 /// JavaScript may mutate the data passed in to this buffer when writing the buffer.
322 /// However, some JavaScript runtimes do not support external buffers (notably electron!)
323 /// in which case modifications may be lost.
324 ///
325 /// If you need to support these runtimes, you should create a buffer by other means and then
326 /// later copy the data back out.
327 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 /// This function gives V8 an indication of the amount of externally allocated memory that is kept alive by JavaScript objects (i.e. a JavaScript object that points to its own memory allocated by a native module).
390 ///
391 /// Registering externally allocated memory will trigger global garbage collections more often than it would otherwise.
392 ///
393 /// ***ATTENTION ⚠️***, do not use this with `create_buffer_with_data/create_arraybuffer_with_data`, since these two functions already called the `adjust_external_memory` internal.
394 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 /// This API allocates a node::Buffer object and initializes it with data copied from the passed-in buffer.
407 ///
408 /// While this is still a fully-supported data structure, in most cases using a TypedArray will suffice.
409 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 // Rust uses 0x1 as the data pointer for empty buffers,
457 // but NAPI/V8 only allows multiple buffers to have
458 // the same data pointer if it's 0x0.
459 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 /// # Safety
496 /// Mostly the same with `create_arraybuffer_with_data`
497 ///
498 /// Provided `finalize_callback` will be called when `Buffer` got dropped.
499 ///
500 /// You can pass in `noop_finalize` if you have nothing to do in finalize phase.
501 ///
502 /// # Notes
503 ///
504 /// JavaScript may mutate the data passed in to this buffer when writing the buffer.
505 /// However, some JavaScript runtimes do not support external buffers (notably electron!)
506 /// in which case modifications may be lost.
507 ///
508 /// If you need to support these runtimes, you should create a buffer by other means and then
509 /// later copy the data back out.
510 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 // Rust uses 0x1 as the data pointer for empty buffers,
527 // but NAPI/V8 only allows multiple buffers to have
528 // the same data pointer if it's 0x0.
529 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 /// This API allows an add-on author to create a function object in native code.
569 ///
570 /// This is the primary mechanism to allow calling into the add-on's native code from JavaScript.
571 ///
572 /// The newly created function is not automatically visible from script after this call.
573 ///
574 /// Instead, a property must be explicitly set on any object that is visible to JavaScript, in order for the function to be accessible from script.
575 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(), // We let it borrow the data here
611 &mut raw_result,
612 )
613 })?;
614
615 // Note: based on N-API docs, at this point, we have created an effective
616 // `&'static dyn Fn…` in Rust parlance, in that thanks to `Box::into_raw()`
617 // we are sure the context won't be freed, and thus the callback may use
618 // it to call the actual method thanks to the trampoline…
619 // But we thus have a data leak: there is nothing yet responsible for
620 // running the `drop(Box::from_raw(…))` cleanup code.
621 //
622 // To solve that, according to the docs, we need to attach a finalizer:
623 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 /// This API retrieves a napi_extended_error_info structure with information about the last error that occurred.
638 ///
639 /// The content of the napi_extended_error_info returned is only valid up until an n-api function is called on the same env.
640 ///
641 /// Do not rely on the content or format of any of the extended information as it is not subject to SemVer and may change at any time. It is intended only for logging purposes.
642 ///
643 /// This API can be called even if there is a pending JavaScript exception.
644 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 /// Throw any JavaScript value
651 pub fn throw<T: NapiRaw>(&self, value: T) -> Result<()> {
652 check_status!(unsafe { sys::napi_throw(self.0, value.raw()) })
653 }
654
655 /// This API throws a JavaScript Error with the text provided.
656 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 /// This API throws a JavaScript RangeError with the text provided.
669 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 /// This API throws a JavaScript TypeError with the text provided.
682 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 /// This API throws a JavaScript SyntaxError with the text provided.
695 #[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 /// In the event of an unrecoverable error in a native module
713 ///
714 /// A fatal error can be thrown to immediately terminate the process.
715 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 /// Trigger an 'uncaughtException' in JavaScript.
735 ///
736 /// Useful if an async callback throws an exception with no way to recover.
737 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 /// Create JavaScript class
745 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 /// This API create a new reference with the initial 1 ref count to the Object passed in.
842 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 /// This API create a new reference with the specified reference count to the Object passed in.
860 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 /// Get reference value from `Ref` with type check
877 ///
878 /// Return error if the type of `reference` provided is mismatched with `T`
879 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 /// Get reference value from `Ref` without type check
891 ///
892 /// Using this API if you are sure the type of `T` is matched with provided `Ref<()>`.
893 ///
894 /// If type mismatched, calling `T::method` would return `Err`.
895 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 /// If `size_hint` provided, `Env::adjust_external_memory` will be called under the hood.
907 ///
908 /// If no `size_hint` provided, global garbage collections will be triggered less times than expected.
909 ///
910 /// If getting the exact `native_object` size is difficult, you can provide an approximate value, it's only effect to the GC.
911 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 /// Run [Task](./trait.Task.html) in libuv thread pool, return [AsyncWorkPromise](./struct.AsyncWorkPromise.html)
975 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 /// Node-API provides an API for executing a string containing JavaScript using the underlying JavaScript engine.
993 /// This function executes a string of JavaScript code and returns its result with the following caveats:
994 /// - Unlike `eval`, this function does not allow the script to access the current lexical scope, and therefore also does not allow to access the [module scope](https://nodejs.org/api/modules.html#the-module-scope), meaning that pseudo-globals such as require will not be available.
995 /// - The script can access the [global scope](https://nodejs.org/api/globals.html). Function and `var` declarations in the script will be added to the [global](https://nodejs.org/api/globals.html#global) object. Variable declarations made using `let` and `const` will be visible globally, but will not be added to the global object.
996 /// - The value of this is [global](https://nodejs.org/api/globals.html) within the script.
997 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 /// `process.versions.napi`
1005 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 /// Creates a deferred promise, which can be resolved or rejected from a background thread.
1111 #[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 /// This API does not observe leap seconds; they are ignored, as ECMAScript aligns with POSIX time specification.
1119 ///
1120 /// This API allocates a JavaScript Date object.
1121 ///
1122 /// JavaScript Date objects are described in [Section 20.3](https://tc39.github.io/ecma262/#sec-date-objects) of the ECMAScript Language Specification.
1123 #[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 /// This API associates data with the currently running Agent. data can later be retrieved using `Env::get_instance_data()`.
1133 ///
1134 /// Any existing data associated with the currently running Agent which was set by means of a previous call to `Env::set_instance_data()` will be overwritten.
1135 ///
1136 /// If a `finalize_cb` was provided by the previous call, it will not be called.
1137 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 /// This API retrieves data that was previously associated with the currently running Agent via `Env::set_instance_data()`.
1162 ///
1163 /// If no data is set, the call will succeed and data will be set to NULL.
1164 #[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 /// Registers hook, which is a function of type `FnOnce(Arg)`, as a function to be run with the `arg` parameter once the current Node.js environment exits.
1200 ///
1201 /// Unlike [`add_env_cleanup_hook`](https://docs.rs/napi/latest/napi/struct.Env.html#method.add_env_cleanup_hook), the hook is allowed to be asynchronous.
1202 ///
1203 /// Otherwise, behavior generally matches that of [`add_env_cleanup_hook`](https://docs.rs/napi/latest/napi/struct.Env.html#method.add_env_cleanup_hook).
1204 #[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 /// This API is very similar to [`add_removable_async_cleanup_hook`](https://docs.rs/napi/latest/napi/struct.Env.html#method.add_removable_async_cleanup_hook)
1230 ///
1231 /// Use this one if you don't want remove the cleanup hook anymore.
1232 #[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 /// This API retrieves the file path of the currently running JS module as a URL. For a file on
1265 /// the local file system it will start with `file://`.
1266 ///
1267 /// # Errors
1268 ///
1269 /// The retrieved string may be empty if the add-on loading process fails to establish the
1270 /// add-on's file name.
1271 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 // SAFETY: This is safe because `char_ptr` is guaranteed to not be `null`, and point to
1278 // null-terminated string data.
1279 let module_filename = unsafe { std::ffi::CStr::from_ptr(char_ptr) };
1280
1281 Ok(module_filename.to_string_lossy().into_owned())
1282 }
1283
1284 /// ### Serialize `Rust Struct` into `JavaScript Value`
1285 ///
1286 /// ```
1287 /// #[derive(Serialize, Debug, Deserialize)]
1288 /// struct AnObject {
1289 /// a: u32,
1290 /// b: Vec<f64>,
1291 /// c: String,
1292 /// }
1293 ///
1294 /// #[js_function]
1295 /// fn serialize(ctx: CallContext) -> Result<JsUnknown> {
1296 /// let value = AnyObject { a: 1, b: vec![0.1, 2.22], c: "hello" };
1297 /// ctx.env.to_js_value(&value)
1298 /// }
1299 /// ```
1300 #[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 /// ### Deserialize data from `JsValue`
1311 /// ```
1312 /// #[derive(Serialize, Debug, Deserialize)]
1313 /// struct AnObject {
1314 /// a: u32,
1315 /// b: Vec<f64>,
1316 /// c: String,
1317 /// }
1318 ///
1319 /// #[js_function(1)]
1320 /// fn deserialize_from_js(ctx: CallContext) -> Result<JsUndefined> {
1321 /// let arg0 = ctx.get::<JsUnknown>(0)?;
1322 /// let de_serialized: AnObject = ctx.env.from_js_value(arg0)?;
1323 /// ...
1324 /// }
1325 ///
1326 #[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 /// This API represents the invocation of the Strict Equality algorithm as defined in [Section 7.2.14](https://tc39.es/ecma262/#sec-strict-equality-comparison) of the ECMAScript Language Specification.
1342 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 /// get raw env ptr
1356 pub fn raw(&self) -> sys::napi_env {
1357 self.0
1358 }
1359}
1360
1361/// This function could be used for `create_buffer_with_borrowed_data` and want do noting when Buffer finalized.
1362pub 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: *mut (usize, usize) = hint as *mut (usize, usize);
1370 let (length: usize, cap: usize) = unsafe { *Box::from_raw(length_ptr) };
1371 mem::drop(unsafe { Vec::from_raw_parts(ptr:finalize_data as *mut u8, length, capacity: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: *mut TaggedObject = 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: Option = unsafe { *Box::from_raw(finalize_hint as *mut Option<i64>) };
1384 if let Some(changed: i64) = size_hint {
1385 if changed != 0 {
1386 let mut adjusted: i64 = 0i64;
1387 let status: i32 = 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: TaggedObject, callback: F) = unsafe { *Box::from_raw(finalize_data as *mut (TaggedObject<T>, F)) };
1408 let hint: Hint = unsafe { *Box::from_raw(finalize_hint as *mut Hint) };
1409 let env: 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: Box> = 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: Hint, callback: Finalize) = 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: Arg, callback: F) = unsafe { *Box::from_raw(data as *mut (Arg, F)) };
1443 callback(arg);
1444 if !handle.is_null() {
1445 let status: i32 = 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 // Fast path for 4 arguments or less.
1465 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 // Arguments length greater than 4, resize the vector.
1486 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}
1627