nodex_api/
args.rs

1use crate::{api, env::NapiEnv, prelude::*};
2
3/// Js args
4#[derive(Debug, Clone)]
5pub struct JsArgs(pub Vec<JsValue>);
6
7/// Trait for types convertible to any number of Js values.
8pub trait ToJsArgs {
9    fn to_js_args(self, env: NapiEnv) -> NapiResult<JsArgs>;
10    fn len() -> usize;
11}
12
13/// Trait for types that can be created from an arbitrary number of Js values.
14pub trait FromJsArgs: Sized {
15    fn from_js_args(args: JsArgs) -> NapiResult<Self>;
16    fn len() -> usize;
17}
18
19impl FromJsArgs for () {
20    fn from_js_args(args: JsArgs) -> NapiResult<()> {
21        Ok(())
22    }
23
24    fn len() -> usize {
25        0
26    }
27}
28
29impl ToJsArgs for () {
30    fn to_js_args(self, env: NapiEnv) -> NapiResult<JsArgs> {
31        Ok(JsArgs(vec![]))
32    }
33
34    fn len() -> usize {
35        0
36    }
37}
38
39impl<T: NapiValueT> FromJsArgs for T {
40    fn from_js_args(args: JsArgs) -> NapiResult<T> {
41        // It's safe here
42        let arg = unsafe { args.0.get_unchecked(0) };
43        let casted = unsafe { arg.cast::<T>() };
44        match casted.check() {
45            Ok(true) => Ok(casted),
46            Ok(false) => Err(NapiStatus::InvalidArg),
47            Err(e) => Err(e),
48        }
49    }
50
51    fn len() -> usize {
52        1
53    }
54}
55
56impl<T: NapiValueT> ToJsArgs for T {
57    fn to_js_args(self, env: NapiEnv) -> NapiResult<JsArgs> {
58        Ok(JsArgs(vec![self.value()]))
59    }
60
61    fn len() -> usize {
62        1
63    }
64}
65
66macro_rules! count {
67    () => (0_usize);
68    ($x:tt $($xs:tt)*) => (1_usize + count!($($xs)*));
69}
70
71#[macro_export]
72macro_rules! from_js_args_tuple {
73    () => ();
74
75    ($($name:ident),+; $($idx:tt),+) => (
76        #[doc(hidden)]
77        impl<$($name: NapiValueT + NapiValueCheck),*> FromJsArgs for ($($name,)*) {
78            fn from_js_args(args: JsArgs) -> NapiResult<Self> {
79                Ok(($({
80                    // It's safe here
81                    let arg = unsafe { args.0.get_unchecked($idx) };
82                    let casted = unsafe { arg.cast::<$name>() };
83
84                    match casted.check() {
85                        Ok(true) => {
86                            casted
87                        }
88                        Ok(false) => {
89                            return Err(NapiStatus::InvalidArg)
90                        }
91                        Err(e) => {
92                            return Err(e)
93                        }
94                    }
95                },)*))
96            }
97
98            fn len() -> usize {
99                count!($($name)*)
100            }
101        }
102    )
103}
104
105from_js_args_tuple!(T0; 0);
106from_js_args_tuple!(T0, T1; 0, 1);
107from_js_args_tuple!(T0, T1, T2; 0, 1, 2);
108from_js_args_tuple!(T0, T1, T2, T3; 0, 1, 2, 3);
109from_js_args_tuple!(T0, T1, T2, T3, T4; 0, 1, 2, 3, 4);
110from_js_args_tuple!(T0, T1, T2, T3, T4, T5; 0, 1, 2, 3, 4, 5);
111from_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6; 0, 1, 2, 3, 4, 5, 6);
112from_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7; 0, 1, 2, 3, 4, 5, 6, 6);
113from_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8; 0, 1, 2, 3, 4, 5, 6, 7, 8);
114from_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
115from_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
116from_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
117from_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
118from_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
119from_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
120from_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
121
122#[macro_export]
123macro_rules! to_js_args_tuple {
124    () => ();
125
126    ($($name:ident),+; $($idx:tt),+) => (
127        #[doc(hidden)]
128        impl<$($name: NapiValueT + NapiValueCheck),+> ToJsArgs for ($($name,)+) {
129            fn to_js_args(self, env: NapiEnv) -> NapiResult<JsArgs> {
130                let mut args = vec![];
131                let mut idx = 0;
132
133                $({
134                    args.push(self.$idx.value());
135                })+
136
137                Ok(JsArgs(args))
138            }
139
140            fn len() -> usize {
141                count!($($name)*)
142            }
143        }
144    )
145}
146
147to_js_args_tuple!(T0; 0);
148to_js_args_tuple!(T0, T1; 0, 1);
149to_js_args_tuple!(T0, T1, T2; 0, 1, 2);
150to_js_args_tuple!(T0, T1, T2, T3; 0, 1, 2, 3);
151to_js_args_tuple!(T0, T1, T2, T3, T4; 0, 1, 2, 3, 4);
152to_js_args_tuple!(T0, T1, T2, T3, T4, T5; 0, 1, 2, 3, 4, 5);
153to_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6; 0, 1, 2, 3, 4, 5, 6);
154to_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7; 0, 1, 2, 3, 4, 5, 6, 6);
155to_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8; 0, 1, 2, 3, 4, 5, 6, 7, 8);
156to_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
157to_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
158to_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
159to_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
160to_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
161to_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
162to_js_args_tuple!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15; 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);