1#![allow(deprecated)]
2
3use std::ptr;
4
5use super::{Either, FromNapiValue, ToNapiValue, TypeName, Unknown, ValidateNapiValue};
6
7#[cfg(feature = "napi4")]
8use crate::threadsafe_function::{ThreadsafeCallContext, ThreadsafeFunction};
9pub use crate::JsFunction;
10use crate::{
11 check_pending_exception, check_status, sys, Env, JsUndefined, NapiRaw, NapiValue, Result,
12 ValueType,
13};
14
15impl ValidateNapiValue for JsFunction {}
16
17pub trait JsValuesTupleIntoVec {
18 fn into_vec(self, env: sys::napi_env) -> Result<Vec<sys::napi_value>>;
19}
20
21impl<T> JsValuesTupleIntoVec for T
22where
23 T: ToNapiValue,
24{
25 #[allow(clippy::not_unsafe_ptr_arg_deref)]
26 fn into_vec(self, env: sys::napi_env) -> Result<Vec<sys::napi_value>> {
27 if std::mem::size_of::<T>() == 0 {
29 Ok(vec![])
30 } else {
31 Ok(vec![unsafe {
32 <T as ToNapiValue>::to_napi_value(env, self)?
33 }])
34 }
35 }
36}
37pub trait TupleFromSliceValues {
38 #[allow(clippy::missing_safety_doc)]
39 unsafe fn from_slice_values(env: sys::napi_env, values: &[sys::napi_value]) -> Result<Self>
40 where
41 Self: Sized;
42}
43
44#[repr(C)]
45pub struct FnArgs<T> {
46 pub data: T,
47}
48
49impl<T> From<T> for FnArgs<T> {
50 fn from(value: T) -> Self {
51 FnArgs { data: value }
52 }
53}
54
55macro_rules! impl_tuple_conversion {
56 ($($ident:ident),*) => {
57 impl<$($ident: ToNapiValue),*> JsValuesTupleIntoVec for FnArgs<($($ident,)*)> {
58 #[allow(clippy::not_unsafe_ptr_arg_deref)]
59 fn into_vec(self, env: sys::napi_env) -> Result<Vec<sys::napi_value>> {
60 #[allow(non_snake_case)]
61 let ($($ident,)*) = self.data;
62 Ok(vec![$(unsafe { <$ident as ToNapiValue>::to_napi_value(env, $ident)? }),*])
63 }
64 }
65
66 impl<$($ident: FromNapiValue),*> TupleFromSliceValues for ($($ident,)*) {
67 unsafe fn from_slice_values(env: sys::napi_env, values: &[sys::napi_value]) -> $crate::Result<Self> {
68 #[allow(non_snake_case)]
69 let [$($ident),*] = values.try_into().map_err(|_| crate::Error::new(
70 crate::Status::InvalidArg,
71 "Invalid number of arguments",
72 ))?;
73 Ok(($(
74 unsafe { $ident::from_napi_value(env, $ident)?}
75 ,)*))
76 }
77 }
78 };
79}
80
81impl_tuple_conversion!(A);
82impl_tuple_conversion!(A, B);
83impl_tuple_conversion!(A, B, C);
84impl_tuple_conversion!(A, B, C, D);
85impl_tuple_conversion!(A, B, C, D, E);
86impl_tuple_conversion!(A, B, C, D, E, F);
87impl_tuple_conversion!(A, B, C, D, E, F, G);
88impl_tuple_conversion!(A, B, C, D, E, F, G, H);
89impl_tuple_conversion!(A, B, C, D, E, F, G, H, I);
90impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J);
91impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K);
92impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L);
93impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L, M);
94impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L, M, N);
95impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
96impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
97impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
98impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
99impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
100impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
101impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
102impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V);
103impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W);
104impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X);
105impl_tuple_conversion!(A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y);
106impl_tuple_conversion!(
107 A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z
108);
109
110pub struct Function<'scope, Args: JsValuesTupleIntoVec = Unknown, Return = Unknown> {
115 pub(crate) env: sys::napi_env,
116 pub(crate) value: sys::napi_value,
117 pub(crate) _args: std::marker::PhantomData<Args>,
118 pub(crate) _return: std::marker::PhantomData<Return>,
119 _scope: std::marker::PhantomData<&'scope ()>,
120}
121
122impl<Args: JsValuesTupleIntoVec, Return> TypeName for Function<'_, Args, Return> {
123 fn type_name() -> &'static str {
124 "Function"
125 }
126
127 fn value_type() -> crate::ValueType {
128 ValueType::Function
129 }
130}
131
132impl<Args: JsValuesTupleIntoVec, Return> NapiRaw for Function<'_, Args, Return> {
133 unsafe fn raw(&self) -> sys::napi_value {
134 self.value
135 }
136}
137
138impl<Args: JsValuesTupleIntoVec, Return> FromNapiValue for Function<'_, Args, Return> {
139 unsafe fn from_napi_value(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
140 Ok(Function {
141 env,
142 value,
143 _args: std::marker::PhantomData,
144 _return: std::marker::PhantomData,
145 _scope: std::marker::PhantomData,
146 })
147 }
148}
149
150impl<Args: JsValuesTupleIntoVec, Return> ValidateNapiValue for Function<'_, Args, Return> {}
151
152impl<Args: JsValuesTupleIntoVec, Return> Function<'_, Args, Return> {
153 pub fn name(&self) -> Result<String> {
155 let mut name = ptr::null_mut();
156 check_status!(
157 unsafe {
158 sys::napi_get_named_property(self.env, self.value, c"name".as_ptr().cast(), &mut name)
159 },
160 "Get function name failed"
161 )?;
162 unsafe { String::from_napi_value(self.env, name) }
163 }
164
165 pub fn create_ref(&self) -> Result<FunctionRef<Args, Return>> {
167 let mut reference = ptr::null_mut();
168 check_status!(
169 unsafe { sys::napi_create_reference(self.env, self.value, 1, &mut reference) },
170 "Create reference failed"
171 )?;
172 Ok(FunctionRef {
173 inner: reference,
174 env: self.env,
175 _args: std::marker::PhantomData,
176 _return: std::marker::PhantomData,
177 })
178 }
179
180 pub fn new_instance(&self, args: Args) -> Result<Unknown> {
182 let mut raw_instance = ptr::null_mut();
183 let mut args = args.into_vec(self.env)?;
184 check_status!(
185 unsafe {
186 sys::napi_new_instance(
187 self.env,
188 self.value,
189 args.len(),
190 args.as_mut_ptr().cast(),
191 &mut raw_instance,
192 )
193 },
194 "Create new instance failed"
195 )?;
196 unsafe { Unknown::from_napi_value(self.env, raw_instance) }
197 }
198
199 #[cfg(feature = "napi4")]
200 pub fn build_threadsafe_function<T: 'static>(
202 &self,
203 ) -> ThreadsafeFunctionBuilder<T, Args, Return> {
204 ThreadsafeFunctionBuilder {
205 env: self.env,
206 value: self.value,
207 _args: std::marker::PhantomData,
208 _return: std::marker::PhantomData,
209 }
210 }
211}
212
213impl<Args: JsValuesTupleIntoVec, Return: FromNapiValue> Function<'_, Args, Return> {
214 pub fn call(&self, args: Args) -> Result<Return> {
218 let mut raw_this = ptr::null_mut();
219 check_status!(
220 unsafe { sys::napi_get_undefined(self.env, &mut raw_this) },
221 "Get undefined value failed"
222 )?;
223 let args_ptr = args.into_vec(self.env)?;
224 let mut raw_return = ptr::null_mut();
225 check_pending_exception!(
226 self.env,
227 unsafe {
228 sys::napi_call_function(
229 self.env,
230 raw_this,
231 self.value,
232 args_ptr.len(),
233 args_ptr.as_ptr(),
234 &mut raw_return,
235 )
236 },
237 "Call Function failed"
238 )?;
239 unsafe { Return::from_napi_value(self.env, raw_return) }
240 }
241
242 pub fn apply<Context: ToNapiValue>(&self, this: Context, args: Args) -> Result<Return> {
245 let raw_this = unsafe { Context::to_napi_value(self.env, this) }?;
246 let args_ptr = args.into_vec(self.env)?;
247 let mut raw_return = ptr::null_mut();
248 check_status!(
249 unsafe {
250 sys::napi_call_function(
251 self.env,
252 raw_this,
253 self.value,
254 args_ptr.len(),
255 args_ptr.as_ptr(),
256 &mut raw_return,
257 )
258 },
259 "Call Function failed"
260 )?;
261 unsafe { Return::from_napi_value(self.env, raw_return) }
262 }
263
264 pub fn bind<T: ToNapiValue>(&self, this: T) -> Result<Function<'_, Args, Return>> {
266 let raw_this = unsafe { T::to_napi_value(self.env, this) }?;
267 let mut bind_function = ptr::null_mut();
268 check_status!(
269 unsafe {
270 sys::napi_get_named_property(self.env, self.value, c"bind".as_ptr(), &mut bind_function)
271 },
272 "Get bind function failed"
273 )?;
274 let mut bound_function = ptr::null_mut();
275 check_status!(
276 unsafe {
277 sys::napi_call_function(
278 self.env,
279 self.value,
280 bind_function,
281 1,
282 [raw_this].as_ptr(),
283 &mut bound_function,
284 )
285 },
286 "Bind function failed"
287 )?;
288 Ok(Function {
289 env: self.env,
290 value: bound_function,
291 _args: std::marker::PhantomData,
292 _return: std::marker::PhantomData,
293 _scope: std::marker::PhantomData,
294 })
295 }
296}
297
298#[cfg(feature = "napi4")]
299pub struct ThreadsafeFunctionBuilder<
300 'env,
301 T: 'static,
302 Args: 'static + JsValuesTupleIntoVec,
303 Return,
304 const CalleeHandled: bool = false,
305 const Weak: bool = false,
306 const MaxQueueSize: usize = 0,
307> {
308 pub(crate) env: sys::napi_env,
309 pub(crate) value: sys::napi_value,
310 _args: std::marker::PhantomData<(T, &'env Args)>,
311 _return: std::marker::PhantomData<Return>,
312}
313
314#[cfg(feature = "napi4")]
315impl<
316 'env,
317 T: 'static,
318 Args: 'static + JsValuesTupleIntoVec,
319 Return: FromNapiValue,
320 const CalleeHandled: bool,
321 const Weak: bool,
322 const MaxQueueSize: usize,
323 > ThreadsafeFunctionBuilder<'env, T, Args, Return, CalleeHandled, Weak, MaxQueueSize>
324{
325 pub fn weak<const NewWeak: bool>(
326 self,
327 ) -> ThreadsafeFunctionBuilder<'env, T, Args, Return, CalleeHandled, NewWeak, MaxQueueSize> {
328 ThreadsafeFunctionBuilder {
329 env: self.env,
330 value: self.value,
331 _args: std::marker::PhantomData,
332 _return: std::marker::PhantomData,
333 }
334 }
335
336 pub fn callee_handled<const NewCalleeHandled: bool>(
337 self,
338 ) -> ThreadsafeFunctionBuilder<'env, T, Args, Return, NewCalleeHandled, Weak, MaxQueueSize> {
339 ThreadsafeFunctionBuilder {
340 env: self.env,
341 value: self.value,
342 _args: std::marker::PhantomData,
343 _return: std::marker::PhantomData,
344 }
345 }
346
347 pub fn max_queue_size<const NewMaxQueueSize: usize>(
348 self,
349 ) -> ThreadsafeFunctionBuilder<'env, T, Args, Return, CalleeHandled, Weak, NewMaxQueueSize> {
350 ThreadsafeFunctionBuilder {
351 env: self.env,
352 value: self.value,
353 _args: std::marker::PhantomData,
354 _return: std::marker::PhantomData,
355 }
356 }
357
358 pub fn build_callback<CallJsBackArgs, Callback>(
359 &self,
360 call_js_back: Callback,
361 ) -> Result<ThreadsafeFunction<T, Return, CallJsBackArgs, CalleeHandled, Weak, MaxQueueSize>>
362 where
363 CallJsBackArgs: 'static + JsValuesTupleIntoVec,
364 Callback: 'static + FnMut(ThreadsafeCallContext<T>) -> Result<CallJsBackArgs>,
365 {
366 ThreadsafeFunction::<T, Return, Args, CalleeHandled, Weak, MaxQueueSize>::create(
367 self.env,
368 self.value,
369 call_js_back,
370 )
371 }
372}
373
374#[cfg(feature = "napi4")]
375impl<
376 T: 'static + JsValuesTupleIntoVec,
377 Return: FromNapiValue,
378 const CalleeHandled: bool,
379 const Weak: bool,
380 const MaxQueueSize: usize,
381 > ThreadsafeFunctionBuilder<'_, T, T, Return, CalleeHandled, Weak, MaxQueueSize>
382{
383 pub fn build(
384 &self,
385 ) -> Result<ThreadsafeFunction<T, Return, T, CalleeHandled, Weak, MaxQueueSize>> {
386 unsafe { ThreadsafeFunction::from_napi_value(self.env, self.value) }
387 }
388}
389
390pub struct FunctionRef<Args: JsValuesTupleIntoVec, Return> {
393 pub(crate) inner: sys::napi_ref,
394 pub(crate) env: sys::napi_env,
395 _args: std::marker::PhantomData<Args>,
396 _return: std::marker::PhantomData<Return>,
397}
398
399unsafe impl<Args: JsValuesTupleIntoVec, Return> Sync for FunctionRef<Args, Return> {}
400
401impl<Args: JsValuesTupleIntoVec, Return> FunctionRef<Args, Return> {
402 pub fn borrow_back<'scope>(&self, env: &'scope Env) -> Result<Function<'scope, Args, Return>> {
403 let mut value = ptr::null_mut();
404 check_status!(
405 unsafe { sys::napi_get_reference_value(env.0, self.inner, &mut value) },
406 "Get reference value failed"
407 )?;
408 Ok(Function {
409 env: env.0,
410 value,
411 _args: std::marker::PhantomData,
412 _return: std::marker::PhantomData,
413 _scope: std::marker::PhantomData,
414 })
415 }
416}
417
418impl<Args: JsValuesTupleIntoVec, Return> Drop for FunctionRef<Args, Return> {
419 fn drop(&mut self) {
420 let status = unsafe { sys::napi_delete_reference(self.env, self.inner) };
421 debug_assert_eq!(status, sys::Status::napi_ok, "Drop FunctionRef failed");
422 }
423}
424
425impl<Args: JsValuesTupleIntoVec, Return> TypeName for FunctionRef<Args, Return> {
426 fn type_name() -> &'static str {
427 "Function"
428 }
429
430 fn value_type() -> crate::ValueType {
431 ValueType::Function
432 }
433}
434
435impl<Args: JsValuesTupleIntoVec, Return> FromNapiValue for FunctionRef<Args, Return> {
436 unsafe fn from_napi_value(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
437 let mut reference = ptr::null_mut();
438 check_status!(
439 unsafe { sys::napi_create_reference(env, value, 1, &mut reference) },
440 "Create reference failed"
441 )?;
442 Ok(FunctionRef {
443 inner: reference,
444 env,
445 _args: std::marker::PhantomData,
446 _return: std::marker::PhantomData,
447 })
448 }
449}
450
451impl<Args: JsValuesTupleIntoVec, Return: FromNapiValue> ValidateNapiValue
452 for FunctionRef<Args, Return>
453{
454}
455
456pub struct FunctionCallContext<'scope> {
457 pub(crate) args: &'scope [sys::napi_value],
458 pub(crate) this: sys::napi_value,
459 pub env: &'scope mut Env,
460}
461
462impl FunctionCallContext<'_> {
463 pub fn length(&self) -> usize {
465 self.args.len()
466 }
467
468 pub fn get<ArgType: FromNapiValue>(&self, index: usize) -> Result<ArgType> {
469 if index >= self.length() {
470 Err(crate::Error::new(
471 crate::Status::GenericFailure,
472 "Arguments index out of range".to_owned(),
473 ))
474 } else {
475 unsafe { ArgType::from_napi_value(self.env.0, self.args[index]) }
476 }
477 }
478
479 pub fn try_get<ArgType: NapiValue + TypeName + FromNapiValue>(
480 &self,
481 index: usize,
482 ) -> Result<Either<ArgType, JsUndefined>> {
483 let len = self.length();
484 if index >= len {
485 Err(crate::Error::new(
486 crate::Status::GenericFailure,
487 "Arguments index out of range".to_owned(),
488 ))
489 } else if index < len {
490 unsafe { ArgType::from_raw(self.env.0, self.args[index]) }.map(Either::A)
491 } else {
492 self.env.get_undefined().map(Either::B)
493 }
494 }
495
496 pub fn first_arg<T: FromNapiValue>(&self) -> Result<T> {
498 if self.args.is_empty() {
499 return Err(crate::Error::new(
500 crate::Status::InvalidArg,
501 "There is no arguments",
502 ));
503 }
504 unsafe { T::from_napi_value(self.env.0, self.args[0]) }
505 }
506
507 pub fn args<Args: TupleFromSliceValues>(&self) -> Result<Args> {
515 unsafe { Args::from_slice_values(self.env.0, self.args) }
516 }
517
518 pub fn arguments<T: FromNapiValue>(&self) -> Result<Vec<T>> {
520 self
521 .args
522 .iter()
523 .map(|arg| unsafe { <T as FromNapiValue>::from_napi_value(self.env.0, *arg) })
524 .collect::<Result<Vec<T>>>()
525 }
526
527 pub fn this<This: FromNapiValue>(&self) -> Result<This> {
529 unsafe { This::from_napi_value(self.env.0, self.this) }
530 }
531}
532
533macro_rules! impl_call_apply {
534 ($fn_call_name:ident, $fn_apply_name:ident, $($ident:ident),*) => {
535 #[allow(non_snake_case, clippy::too_many_arguments)]
536 pub fn $fn_call_name<$($ident: ToNapiValue),*, Return: FromNapiValue>(
537 &self,
538 $($ident: $ident),*
539 ) -> Result<Return> {
540 let raw_this = Env::from_raw(self.0.env)
541 .get_undefined()
542 .map(|u| unsafe { u.raw() })?;
543
544 let raw_args = vec![
545 $(
546 unsafe { $ident::to_napi_value(self.0.env, $ident) }?
547 ),*
548 ];
549
550 let mut return_value = ptr::null_mut();
551 check_pending_exception!(self.0.env, unsafe {
552 sys::napi_call_function(
553 self.0.env,
554 raw_this,
555 self.0.value,
556 raw_args.len(),
557 raw_args.as_ptr(),
558 &mut return_value,
559 )
560 })?;
561
562 unsafe { Return::from_napi_value(self.0.env, return_value) }
563 }
564
565 #[allow(non_snake_case, clippy::too_many_arguments)]
566 pub fn $fn_apply_name<$($ident: ToNapiValue),*, Context: ToNapiValue, Return: FromNapiValue>(
567 &self,
568 this: Context,
569 $($ident: $ident),*
570 ) -> Result<Return> {
571 let raw_this = unsafe { Context::to_napi_value(self.0.env, this) }?;
572
573 let raw_args = vec![
574 $(
575 unsafe { $ident::to_napi_value(self.0.env, $ident) }?
576 ),*
577 ];
578
579 let mut return_value = ptr::null_mut();
580 check_pending_exception!(self.0.env, unsafe {
581 sys::napi_call_function(
582 self.0.env,
583 raw_this,
584 self.0.value,
585 raw_args.len(),
586 raw_args.as_ptr(),
587 &mut return_value,
588 )
589 })?;
590
591 unsafe { Return::from_napi_value(self.0.env, return_value) }
592 }
593 };
594}
595
596impl JsFunction {
597 pub fn apply0<Return: FromNapiValue, Context: ToNapiValue>(
598 &self,
599 this: Context,
600 ) -> Result<Return> {
601 let raw_this = unsafe { Context::to_napi_value(self.0.env, this) }?;
602
603 let mut return_value = ptr::null_mut();
604 check_pending_exception!(self.0.env, unsafe {
605 sys::napi_call_function(
606 self.0.env,
607 raw_this,
608 self.0.value,
609 0,
610 ptr::null_mut(),
611 &mut return_value,
612 )
613 })?;
614
615 unsafe { Return::from_napi_value(self.0.env, return_value) }
616 }
617
618 pub fn call0<Return: FromNapiValue>(&self) -> Result<Return> {
619 let raw_this = Env::from_raw(self.0.env)
620 .get_undefined()
621 .map(|u| unsafe { u.raw() })?;
622
623 let mut return_value = ptr::null_mut();
624 check_pending_exception!(self.0.env, unsafe {
625 sys::napi_call_function(
626 self.0.env,
627 raw_this,
628 self.0.value,
629 0,
630 ptr::null_mut(),
631 &mut return_value,
632 )
633 })?;
634
635 unsafe { Return::from_napi_value(self.0.env, return_value) }
636 }
637
638 impl_call_apply!(call1, apply1, Arg1);
639 impl_call_apply!(call2, apply2, Arg1, Arg2);
640 impl_call_apply!(call3, apply3, Arg1, Arg2, Arg3);
641 impl_call_apply!(call4, apply4, Arg1, Arg2, Arg3, Arg4);
642 impl_call_apply!(call5, apply5, Arg1, Arg2, Arg3, Arg4, Arg5);
643 impl_call_apply!(call6, apply6, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6);
644 impl_call_apply!(call7, apply7, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7);
645 impl_call_apply!(call8, apply8, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8);
646 impl_call_apply!(call9, apply9, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9);
647 impl_call_apply!(call10, apply10, Arg1, Arg2, Arg3, Arg4, Arg5, Arg6, Arg7, Arg8, Arg9, Arg10);
648}