1use std::{marker::PhantomData, ptr};
2
3use crate::{bindgen_prelude::*, check_status, Value};
4
5#[derive(Clone, Copy)]
6pub struct Array<'env> {
7 pub(crate) env: sys::napi_env,
8 pub(crate) inner: sys::napi_value,
9 pub(crate) len: u32,
10 _marker: std::marker::PhantomData<&'env ()>,
11}
12
13impl<'env> Array<'env> {
14 pub(crate) fn new(env: sys::napi_env, len: u32) -> Result<Self> {
15 let mut ptr = ptr::null_mut();
16 unsafe {
17 check_status!(
18 sys::napi_create_array_with_length(env, len as usize, &mut ptr),
19 "Failed to create napi Array"
20 )?;
21 }
22
23 Ok(Array {
24 env,
25 inner: ptr,
26 len,
27 _marker: std::marker::PhantomData,
28 })
29 }
30
31 pub fn get<T: FromNapiValue>(&self, index: u32) -> Result<Option<T>> {
32 if index >= self.len() {
33 return Ok(None);
34 }
35
36 let mut ret = ptr::null_mut();
37 unsafe {
38 check_status!(
39 sys::napi_get_element(self.env, self.inner, index, &mut ret),
40 "Failed to get element with index `{}`",
41 index,
42 )?;
43
44 Ok(Some(T::from_napi_value(self.env, ret)?))
45 }
46 }
47
48 pub fn get_ref<T: 'static + FromNapiRef>(&self, index: u32) -> Result<Option<&'env T>> {
49 if index >= self.len() {
50 return Ok(None);
51 }
52
53 let mut ret = ptr::null_mut();
54 unsafe {
55 check_status!(
56 sys::napi_get_element(self.env, self.inner, index, &mut ret),
57 "Failed to get element with index `{}`",
58 index,
59 )?;
60
61 Ok(Some(T::from_napi_ref(self.env, ret)?))
62 }
63 }
64
65 pub fn set<T: ToNapiValue>(&mut self, index: u32, val: T) -> Result<()> {
66 unsafe {
67 let napi_val = T::to_napi_value(self.env, val)?;
68
69 check_status!(
70 sys::napi_set_element(self.env, self.inner, index, napi_val),
71 "Failed to set element with index `{}`",
72 index,
73 )?;
74
75 if index >= self.len() {
76 self.len = index + 1;
77 }
78
79 Ok(())
80 }
81 }
82
83 pub fn insert<T: ToNapiValue>(&mut self, val: T) -> Result<()> {
84 self.set(self.len(), val)?;
85 Ok(())
86 }
87
88 #[allow(clippy::len_without_is_empty)]
89 pub fn len(&self) -> u32 {
90 self.len
91 }
92
93 pub fn coerce_to_object(self) -> Result<Object<'env>> {
94 let mut new_raw_value = ptr::null_mut();
95 check_status!(unsafe { sys::napi_coerce_to_object(self.env, self.inner, &mut new_raw_value) })?;
96 Ok(Object(
97 Value {
98 env: self.env,
99 value: new_raw_value,
100 value_type: ValueType::Object,
101 },
102 PhantomData,
103 ))
104 }
105}
106
107impl TypeName for Array<'_> {
108 fn type_name() -> &'static str {
109 "Array"
110 }
111
112 fn value_type() -> ValueType {
113 ValueType::Object
114 }
115}
116
117impl<'env> JsValue<'env> for Array<'env> {
118 fn value(&self) -> Value {
119 Value {
120 env: self.env,
121 value: self.inner,
122 value_type: ValueType::Object,
123 }
124 }
125}
126
127impl<'env> JsObjectValue<'env> for Array<'env> {}
128
129impl FromNapiValue for Array<'_> {
130 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
131 let mut is_arr = false;
132 check_status!(
133 unsafe { sys::napi_is_array(env, napi_val, &mut is_arr) },
134 "Failed to check given napi value is array"
135 )?;
136
137 if is_arr {
138 let mut len = 0;
139
140 check_status!(
141 unsafe { sys::napi_get_array_length(env, napi_val, &mut len) },
142 "Failed to get Array length",
143 )?;
144
145 Ok(Array {
146 inner: napi_val,
147 env,
148 len,
149 _marker: std::marker::PhantomData,
150 })
151 } else {
152 Err(Error::new(
153 Status::InvalidArg,
154 "Given napi value is not an array".to_owned(),
155 ))
156 }
157 }
158}
159
160impl Array<'_> {
161 pub fn from_vec<T>(env: &Env, value: Vec<T>) -> Result<Self>
163 where
164 T: ToNapiValue,
165 {
166 let mut arr = Array::new(env.0, value.len() as u32)?;
167 value.into_iter().enumerate().try_for_each(|(index, val)| {
168 arr.set(index as u32, val)?;
169 Ok::<(), Error>(())
170 })?;
171 Ok(arr)
172 }
173
174 pub fn from_ref_vec_string(env: &Env, value: &[String]) -> Result<Self> {
176 let mut arr = Array::new(env.0, value.len() as u32)?;
177 value.iter().enumerate().try_for_each(|(index, val)| {
178 arr.set(index as u32, val.as_str())?;
179 Ok::<(), Error>(())
180 })?;
181 Ok(arr)
182 }
183
184 pub fn from_ref_vec<T>(env: &Env, value: &[T]) -> Result<Self>
186 where
187 T: ToNapiValue + Copy,
188 {
189 let mut arr = Array::new(env.0, value.len() as u32)?;
190 value.iter().enumerate().try_for_each(|(index, val)| {
191 arr.set(index as u32, *val)?;
192 Ok::<(), Error>(())
193 })?;
194 Ok(arr)
195 }
196}
197
198impl ValidateNapiValue for Array<'_> {}
199
200impl<T> TypeName for Vec<T> {
201 fn type_name() -> &'static str {
202 "Array<T>"
203 }
204
205 fn value_type() -> ValueType {
206 ValueType::Object
207 }
208}
209
210impl<T, const N: usize> ToNapiValue for [T; N]
211where
212 T: ToNapiValue + Copy,
213{
214 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
215 let mut arr = Array::new(env, val.len() as u32)?;
216
217 for (i, v) in val.into_iter().enumerate() {
218 arr.set(i as u32, v)?;
219 }
220
221 unsafe { Array::to_napi_value(env, arr) }
222 }
223}
224
225impl<T, const N: usize> ToNapiValue for &[T; N]
226where
227 for<'a> &'a T: ToNapiValue,
228{
229 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
230 let mut arr = Array::new(env, val.len() as u32)?;
231
232 for (i, v) in val.iter().enumerate() {
233 arr.set(i as u32, v)?;
234 }
235
236 unsafe { Array::to_napi_value(env, arr) }
237 }
238}
239
240impl<T> ToNapiValue for Vec<T>
241where
242 T: ToNapiValue,
243{
244 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
245 let mut arr = Array::new(env, val.len() as u32)?;
246
247 for (i, v) in val.into_iter().enumerate() {
248 arr.set(i as u32, v)?;
249 }
250
251 unsafe { Array::to_napi_value(env, arr) }
252 }
253}
254
255impl<T> ToNapiValue for &Vec<T>
256where
257 for<'a> &'a T: ToNapiValue,
258{
259 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
260 let mut arr = Array::new(env, val.len() as u32)?;
261
262 for (i, v) in val.iter().enumerate() {
263 arr.set(i as u32, v)?;
264 }
265
266 unsafe { Array::to_napi_value(env, arr) }
267 }
268}
269
270impl<T> ToNapiValue for &mut Vec<T>
271where
272 for<'a> &'a T: ToNapiValue,
273{
274 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
275 ToNapiValue::to_napi_value(env, &*val)
276 }
277}
278
279impl<T> FromNapiValue for Vec<T>
280where
281 T: FromNapiValue,
282{
283 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
284 let arr = unsafe { Array::from_napi_value(env, napi_val)? };
285 let mut vec = Vec::with_capacity(arr.len() as usize);
286
287 for i in 0..arr.len() {
288 if let Some(val) = arr.get::<T>(i)? {
289 vec.push(val);
290 } else {
291 return Err(Error::new(
292 Status::InvalidArg,
293 "Found inconsistent data type in Array<T> when converting to Rust Vec<T>".to_owned(),
294 ));
295 }
296 }
297
298 Ok(vec)
299 }
300}
301
302impl<T> ValidateNapiValue for Vec<T>
303where
304 T: FromNapiValue,
305{
306 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
307 let mut is_array = false;
308 check_status!(
309 unsafe { sys::napi_is_array(env, napi_val, &mut is_array) },
310 "Failed to check given napi value is array"
311 )?;
312 if !is_array {
313 return Err(Error::new(
314 Status::InvalidArg,
315 "Expected an array".to_owned(),
316 ));
317 }
318 Ok(ptr::null_mut())
319 }
320}
321
322macro_rules! arr_get {
323 ($arr:expr, $n:expr, $err:expr) => {
324 if let Some(e) = $arr.get($n)? {
325 e
326 } else {
327 return $err($n);
328 }
329 };
330}
331
332macro_rules! tuple_from_napi_value {
333 ($total:expr, $($n:expr),+,) => {
334 unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
335 let arr = unsafe { Array::from_napi_value(env, napi_val)? };
336 let err = |v| Err(Error::new(
337 Status::InvalidArg,
338 format!(
339 "Found inconsistent data type in Array[{}] when converting to Rust T",
340 v
341 )
342 .to_owned(),
343 ));
344 if arr.len() < $total {
345 return Err(Error::new(
346 Status::InvalidArg,
347 format!("Array length < {}",$total).to_owned(),
348 ));
349 }
350 Ok(($(arr_get!(arr,$n,err)),+))
351 }
352 }
353}
354
355macro_rules! impl_tuple_validate_napi_value {
356 ($($ident:ident),+) => {
357 impl<$($ident: FromNapiValue),*> ValidateNapiValue for ($($ident,)*) {}
358 impl<$($ident: FromNapiValue),*> TypeName for ($($ident,)*) {
359 fn type_name() -> &'static str {
360 concat!("Tuple", "(", $(stringify!($ident), ","),*, ")")
361 }
362 fn value_type() -> ValueType {
363 ValueType::Object
364 }
365 }
366 };
367}
368
369macro_rules! impl_from_tuple {
370 (
371 $($typs:ident),*;
372 $($tidents:expr),+;
373 $length:expr
374 ) => {
375 impl<$($typs),*> FromNapiValue for ($($typs,)*)
376 where $($typs: FromNapiValue,)* {
377 tuple_from_napi_value!($length, $($tidents,)*);
378 }
379 };
380}
381
382macro_rules! impl_to_tuple {
383 (
384 $($typs:ident),*;
385 $($tidents:expr),+;
386 $length:expr
387 ) => {
388 impl<$($typs),*> ToNapiValue for ($($typs,)*)
389 where $($typs: ToNapiValue,)* {
390 unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
391 let mut arr = Array::new(env, $length as u32)?;
392
393 #[allow(non_snake_case)]
394 let ($($typs,)*) = val;
395 let mut i = 0;
396
397 $(i+=1; unsafe {arr.set(i-1, <$typs as ToNapiValue>::to_napi_value(env, $typs)? )?}; )*
398
399 unsafe { Array::to_napi_value(env, arr) }
400 }
401 }
402 };
403}
404
405macro_rules! impl_tuples {
406 (
407 ;;$length:expr,
408 $shift:expr
409 ) => {};
410 (
411 $typ:ident$(, $($typs:ident),*)?;
412 $tident:expr$(, $($tidents:expr),*)?;
413 $length:expr,
414 $shift:expr
415 ) => {
416 impl_tuples!(
417 $($($typs),*)?;
418 $($($tidents),*)?;
419 $length - 1,
420 $shift + 1
421 );
422 impl_from_tuple!(
423 $typ$(, $($typs),*)?;
424 $tident - $shift$(, $($tidents - $shift),*)?;
425 $length
426 );
427 impl_to_tuple!(
428 $typ$(, $($typs),*)?;
429 $tident - $shift$(, $($tidents - $shift),*)?;
430 $length
431 );
432 impl_tuple_validate_napi_value!($typ$(, $($typs),*)?);
433 };
434}
435
436impl_tuples!(
437 T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15;
438 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15;
439 16, 0
440);