napi_h/bindgen_runtime/js_values/
array.rs

1use std::ptr;
2
3use crate::{bindgen_prelude::*, check_status, sys, JsObject, Value, ValueType};
4
5pub struct Array {
6  env: sys::napi_env,
7  inner: sys::napi_value,
8  len: u32,
9}
10
11impl Array {
12  pub(crate) fn new(env: sys::napi_env, len: u32) -> Result<Self> {
13    let mut ptr = ptr::null_mut();
14    unsafe {
15      check_status!(
16        sys::napi_create_array_with_length(env, len as usize, &mut ptr),
17        "Failed to create napi Array"
18      )?;
19    }
20
21    Ok(Array {
22      env,
23      inner: ptr,
24      len,
25    })
26  }
27
28  pub fn get<T: FromNapiValue>(&self, index: u32) -> Result<Option<T>> {
29    if index >= self.len() {
30      return Ok(None);
31    }
32
33    let mut ret = ptr::null_mut();
34    unsafe {
35      check_status!(
36        sys::napi_get_element(self.env, self.inner, index, &mut ret),
37        "Failed to get element with index `{}`",
38        index,
39      )?;
40
41      Ok(Some(T::from_napi_value(self.env, ret)?))
42    }
43  }
44
45  pub fn set<T: ToNapiValue>(&mut self, index: u32, val: T) -> Result<()> {
46    unsafe {
47      let napi_val = T::to_napi_value(self.env, val)?;
48
49      check_status!(
50        sys::napi_set_element(self.env, self.inner, index, napi_val),
51        "Failed to set element with index `{}`",
52        index,
53      )?;
54
55      if index >= self.len() {
56        self.len = index + 1;
57      }
58
59      Ok(())
60    }
61  }
62
63  pub fn insert<T: ToNapiValue>(&mut self, val: T) -> Result<()> {
64    self.set(self.len(), val)?;
65    Ok(())
66  }
67
68  #[allow(clippy::len_without_is_empty)]
69  pub fn len(&self) -> u32 {
70    self.len
71  }
72
73  pub fn coerce_to_object(self) -> Result<JsObject> {
74    let mut new_raw_value = ptr::null_mut();
75    check_status!(unsafe { sys::napi_coerce_to_object(self.env, self.inner, &mut new_raw_value) })?;
76    Ok(JsObject(Value {
77      env: self.env,
78      value: new_raw_value,
79      value_type: ValueType::Object,
80    }))
81  }
82}
83
84impl TypeName for Array {
85  fn type_name() -> &'static str {
86    "Array"
87  }
88
89  fn value_type() -> ValueType {
90    ValueType::Object
91  }
92}
93
94impl ToNapiValue for Array {
95  unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
96    Ok(val.inner)
97  }
98}
99
100impl FromNapiValue for Array {
101  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
102    let mut is_arr = false;
103    check_status!(
104      unsafe { sys::napi_is_array(env, napi_val, &mut is_arr) },
105      "Failed to check given napi value is array"
106    )?;
107
108    if is_arr {
109      let mut len = 0;
110
111      check_status!(
112        unsafe { sys::napi_get_array_length(env, napi_val, &mut len) },
113        "Failed to get Array length",
114      )?;
115
116      Ok(Array {
117        inner: napi_val,
118        env,
119        len,
120      })
121    } else {
122      Err(Error::new(
123        Status::InvalidArg,
124        "Given napi value is not an array".to_owned(),
125      ))
126    }
127  }
128}
129
130impl Array {
131  /// Create `Array` from `Vec<T>`
132  pub fn from_vec<T>(env: &Env, value: Vec<T>) -> Result<Self>
133  where
134    T: ToNapiValue,
135  {
136    let mut arr = Array::new(env.0, value.len() as u32)?;
137    value.into_iter().enumerate().try_for_each(|(index, val)| {
138      arr.set(index as u32, val)?;
139      Ok::<(), Error>(())
140    })?;
141    Ok(arr)
142  }
143
144  /// Create `Array` from `&Vec<String>`
145  pub fn from_ref_vec_string(env: &Env, value: &[String]) -> Result<Self> {
146    let mut arr = Array::new(env.0, value.len() as u32)?;
147    value.iter().enumerate().try_for_each(|(index, val)| {
148      arr.set(index as u32, val.as_str())?;
149      Ok::<(), Error>(())
150    })?;
151    Ok(arr)
152  }
153
154  /// Create `Array` from `&Vec<T: Copy + ToNapiValue>`
155  pub fn from_ref_vec<T>(env: &Env, value: &[T]) -> Result<Self>
156  where
157    T: ToNapiValue + Copy,
158  {
159    let mut arr = Array::new(env.0, value.len() as u32)?;
160    value.iter().enumerate().try_for_each(|(index, val)| {
161      arr.set(index as u32, *val)?;
162      Ok::<(), Error>(())
163    })?;
164    Ok(arr)
165  }
166}
167
168impl ValidateNapiValue for Array {}
169
170impl<T> TypeName for Vec<T> {
171  fn type_name() -> &'static str {
172    "Array<T>"
173  }
174
175  fn value_type() -> ValueType {
176    ValueType::Object
177  }
178}
179
180impl<T, const N: usize> ToNapiValue for [T; N]
181where
182  T: ToNapiValue + Copy,
183{
184  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
185    let mut arr = Array::new(env, val.len() as u32)?;
186
187    for (i, v) in val.into_iter().enumerate() {
188      arr.set(i as u32, v)?;
189    }
190
191    unsafe { Array::to_napi_value(env, arr) }
192  }
193}
194
195impl<T> ToNapiValue for &[T]
196where
197  T: ToNapiValue + Copy,
198{
199  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
200    let mut arr = Array::new(env, val.len() as u32)?;
201
202    for (i, v) in val.iter().enumerate() {
203      arr.set(i as u32, *v)?;
204    }
205
206    unsafe { Array::to_napi_value(env, arr) }
207  }
208}
209
210impl<T> ToNapiValue for Vec<T>
211where
212  T: ToNapiValue,
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
225macro_rules! impl_for_primitive_type {
226  ($primitive_type:ident) => {
227    impl ToNapiValue for &Vec<$primitive_type> {
228      unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
229        let mut arr = Array::new(env, val.len() as u32)?;
230
231        for (i, v) in val.iter().enumerate() {
232          arr.set(i as u32, *v)?;
233        }
234
235        unsafe { Array::to_napi_value(env, arr) }
236      }
237    }
238  };
239}
240
241impl_for_primitive_type!(u8);
242impl_for_primitive_type!(i8);
243impl_for_primitive_type!(u16);
244impl_for_primitive_type!(i16);
245impl_for_primitive_type!(u32);
246impl_for_primitive_type!(i32);
247impl_for_primitive_type!(i64);
248impl_for_primitive_type!(f64);
249impl_for_primitive_type!(bool);
250
251impl ToNapiValue for &Vec<String> {
252  unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result<sys::napi_value> {
253    let mut arr = Array::new(env, val.len() as u32)?;
254
255    for (i, v) in val.iter().enumerate() {
256      arr.set(i as u32, v.as_str())?;
257    }
258
259    unsafe { Array::to_napi_value(env, arr) }
260  }
261}
262
263impl<T> FromNapiValue for Vec<T>
264where
265  T: FromNapiValue,
266{
267  unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
268    let arr = unsafe { Array::from_napi_value(env, napi_val)? };
269    let mut vec = vec![];
270
271    for i in 0..arr.len() {
272      if let Some(val) = arr.get::<T>(i)? {
273        vec.push(val);
274      } else {
275        return Err(Error::new(
276          Status::InvalidArg,
277          "Found inconsistent data type in Array<T> when converting to Rust Vec<T>".to_owned(),
278        ));
279      }
280    }
281
282    Ok(vec)
283  }
284}
285
286impl<T> ValidateNapiValue for Vec<T>
287where
288  T: FromNapiValue,
289{
290  unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<sys::napi_value> {
291    let mut is_array = false;
292    check_status!(
293      unsafe { sys::napi_is_array(env, napi_val, &mut is_array) },
294      "Failed to check given napi value is array"
295    )?;
296    if !is_array {
297      return Err(Error::new(
298        Status::InvalidArg,
299        "Expected an array".to_owned(),
300      ));
301    }
302    Ok(ptr::null_mut())
303  }
304}
305
306macro_rules! arr_get {
307  ($arr:expr, $n:expr) => {
308    if let Some(e) = $arr.get($n)? {
309      e
310    } else {
311      return Err(Error::new(
312        Status::InvalidArg,
313        format!(
314          "Found inconsistent data type in Array[{}] when converting to Rust T",
315          $n
316        )
317        .to_owned(),
318      ));
319    }
320  };
321}
322
323macro_rules! tuple_from_napi_value {
324  ($total:expr, $($n:expr),+) => {
325    unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result<Self> {
326      let arr = unsafe { Array::from_napi_value(env, napi_val)? };
327      if arr.len() < $total {
328        return Err(Error::new(
329            Status::InvalidArg,
330            format!("Array length < {}",$total).to_owned(),
331        ));
332      }
333      Ok(($(arr_get!(arr,$n)),+))
334    }
335  }
336}
337
338macro_rules! impl_tuple_validate_napi_value {
339  ($($ident:ident),+) => {
340    impl<$($ident: FromNapiValue),*> ValidateNapiValue for ($($ident,)*) {}
341    impl<$($ident: FromNapiValue),*> TypeName for ($($ident,)*) {
342      fn type_name() -> &'static str {
343        concat!("Tuple", "(", $(stringify!($ident), ","),*, ")")
344      }
345      fn value_type() -> ValueType {
346        ValueType::Object
347      }
348    }
349  };
350}
351
352impl<T0, T1> FromNapiValue for (T0, T1)
353where
354  T0: FromNapiValue,
355  T1: FromNapiValue,
356{
357  tuple_from_napi_value!(2, 0, 1);
358}
359
360impl<T0, T1, T2> FromNapiValue for (T0, T1, T2)
361where
362  T0: FromNapiValue,
363  T1: FromNapiValue,
364  T2: FromNapiValue,
365{
366  tuple_from_napi_value!(3, 0, 1, 2);
367}
368
369impl<T0, T1, T2, T3> FromNapiValue for (T0, T1, T2, T3)
370where
371  T0: FromNapiValue,
372  T1: FromNapiValue,
373  T2: FromNapiValue,
374  T3: FromNapiValue,
375{
376  tuple_from_napi_value!(4, 0, 1, 2, 3);
377}
378
379impl<T0, T1, T2, T3, T4> FromNapiValue for (T0, T1, T2, T3, T4)
380where
381  T0: FromNapiValue,
382  T1: FromNapiValue,
383  T2: FromNapiValue,
384  T3: FromNapiValue,
385  T4: FromNapiValue,
386{
387  tuple_from_napi_value!(5, 0, 1, 2, 3, 4);
388}
389
390impl<T0, T1, T2, T3, T4, T5> FromNapiValue for (T0, T1, T2, T3, T4, T5)
391where
392  T0: FromNapiValue,
393  T1: FromNapiValue,
394  T2: FromNapiValue,
395  T3: FromNapiValue,
396  T4: FromNapiValue,
397  T5: FromNapiValue,
398{
399  tuple_from_napi_value!(6, 0, 1, 2, 3, 4, 5);
400}
401
402impl<T0, T1, T2, T3, T4, T5, T6> FromNapiValue for (T0, T1, T2, T3, T4, T5, T6)
403where
404  T0: FromNapiValue,
405  T1: FromNapiValue,
406  T2: FromNapiValue,
407  T3: FromNapiValue,
408  T4: FromNapiValue,
409  T5: FromNapiValue,
410  T6: FromNapiValue,
411{
412  tuple_from_napi_value!(7, 0, 1, 2, 3, 4, 5, 6);
413}
414
415impl<T0, T1, T2, T3, T4, T5, T6, T7> FromNapiValue for (T0, T1, T2, T3, T4, T5, T6, T7)
416where
417  T0: FromNapiValue,
418  T1: FromNapiValue,
419  T2: FromNapiValue,
420  T3: FromNapiValue,
421  T4: FromNapiValue,
422  T5: FromNapiValue,
423  T6: FromNapiValue,
424  T7: FromNapiValue,
425{
426  tuple_from_napi_value!(8, 0, 1, 2, 3, 4, 5, 6, 7);
427}
428
429impl<T0, T1, T2, T3, T4, T5, T6, T7, T8> FromNapiValue for (T0, T1, T2, T3, T4, T5, T6, T7, T8)
430where
431  T0: FromNapiValue,
432  T1: FromNapiValue,
433  T2: FromNapiValue,
434  T3: FromNapiValue,
435  T4: FromNapiValue,
436  T5: FromNapiValue,
437  T6: FromNapiValue,
438  T7: FromNapiValue,
439  T8: FromNapiValue,
440{
441  tuple_from_napi_value!(9, 0, 1, 2, 3, 4, 5, 6, 7, 8);
442}
443
444impl<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9> FromNapiValue
445  for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9)
446where
447  T0: FromNapiValue,
448  T1: FromNapiValue,
449  T2: FromNapiValue,
450  T3: FromNapiValue,
451  T4: FromNapiValue,
452  T5: FromNapiValue,
453  T6: FromNapiValue,
454  T7: FromNapiValue,
455  T8: FromNapiValue,
456  T9: FromNapiValue,
457{
458  tuple_from_napi_value!(10, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
459}
460
461impl<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10> FromNapiValue
462  for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10)
463where
464  T0: FromNapiValue,
465  T1: FromNapiValue,
466  T2: FromNapiValue,
467  T3: FromNapiValue,
468  T4: FromNapiValue,
469  T5: FromNapiValue,
470  T6: FromNapiValue,
471  T7: FromNapiValue,
472  T8: FromNapiValue,
473  T9: FromNapiValue,
474  T10: FromNapiValue,
475{
476  tuple_from_napi_value!(11, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
477}
478
479impl<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11> FromNapiValue
480  for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11)
481where
482  T0: FromNapiValue,
483  T1: FromNapiValue,
484  T2: FromNapiValue,
485  T3: FromNapiValue,
486  T4: FromNapiValue,
487  T5: FromNapiValue,
488  T6: FromNapiValue,
489  T7: FromNapiValue,
490  T8: FromNapiValue,
491  T9: FromNapiValue,
492  T10: FromNapiValue,
493  T11: FromNapiValue,
494{
495  tuple_from_napi_value!(12, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11);
496}
497
498impl<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12> FromNapiValue
499  for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12)
500where
501  T0: FromNapiValue,
502  T1: FromNapiValue,
503  T2: FromNapiValue,
504  T3: FromNapiValue,
505  T4: FromNapiValue,
506  T5: FromNapiValue,
507  T6: FromNapiValue,
508  T7: FromNapiValue,
509  T8: FromNapiValue,
510  T9: FromNapiValue,
511  T10: FromNapiValue,
512  T11: FromNapiValue,
513  T12: FromNapiValue,
514{
515  tuple_from_napi_value!(13, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12);
516}
517
518impl<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13> FromNapiValue
519  for (T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13)
520where
521  T0: FromNapiValue,
522  T1: FromNapiValue,
523  T2: FromNapiValue,
524  T3: FromNapiValue,
525  T4: FromNapiValue,
526  T5: FromNapiValue,
527  T6: FromNapiValue,
528  T7: FromNapiValue,
529  T8: FromNapiValue,
530  T9: FromNapiValue,
531  T10: FromNapiValue,
532  T11: FromNapiValue,
533  T12: FromNapiValue,
534  T13: FromNapiValue,
535{
536  tuple_from_napi_value!(14, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13);
537}
538
539impl<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14> FromNapiValue
540  for (
541    T0,
542    T1,
543    T2,
544    T3,
545    T4,
546    T5,
547    T6,
548    T7,
549    T8,
550    T9,
551    T10,
552    T11,
553    T12,
554    T13,
555    T14,
556  )
557where
558  T0: FromNapiValue,
559  T1: FromNapiValue,
560  T2: FromNapiValue,
561  T3: FromNapiValue,
562  T4: FromNapiValue,
563  T5: FromNapiValue,
564  T6: FromNapiValue,
565  T7: FromNapiValue,
566  T8: FromNapiValue,
567  T9: FromNapiValue,
568  T10: FromNapiValue,
569  T11: FromNapiValue,
570  T12: FromNapiValue,
571  T13: FromNapiValue,
572  T14: FromNapiValue,
573{
574  tuple_from_napi_value!(15, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
575}
576
577impl<T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15> FromNapiValue
578  for (
579    T0,
580    T1,
581    T2,
582    T3,
583    T4,
584    T5,
585    T6,
586    T7,
587    T8,
588    T9,
589    T10,
590    T11,
591    T12,
592    T13,
593    T14,
594    T15,
595  )
596where
597  T0: FromNapiValue,
598  T1: FromNapiValue,
599  T2: FromNapiValue,
600  T3: FromNapiValue,
601  T4: FromNapiValue,
602  T5: FromNapiValue,
603  T6: FromNapiValue,
604  T7: FromNapiValue,
605  T8: FromNapiValue,
606  T9: FromNapiValue,
607  T10: FromNapiValue,
608  T11: FromNapiValue,
609  T12: FromNapiValue,
610  T13: FromNapiValue,
611  T14: FromNapiValue,
612  T15: FromNapiValue,
613{
614  tuple_from_napi_value!(16, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
615}
616
617impl_tuple_validate_napi_value!(T0, T1);
618impl_tuple_validate_napi_value!(T0, T1, T2);
619impl_tuple_validate_napi_value!(T0, T1, T2, T3);
620impl_tuple_validate_napi_value!(T0, T1, T2, T3, T4);
621impl_tuple_validate_napi_value!(T0, T1, T2, T3, T4, T5);
622impl_tuple_validate_napi_value!(T0, T1, T2, T3, T4, T5, T6);
623impl_tuple_validate_napi_value!(T0, T1, T2, T3, T4, T5, T6, T7);
624impl_tuple_validate_napi_value!(T0, T1, T2, T3, T4, T5, T6, T7, T8);
625impl_tuple_validate_napi_value!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9);
626impl_tuple_validate_napi_value!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10);
627impl_tuple_validate_napi_value!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11);
628impl_tuple_validate_napi_value!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
629impl_tuple_validate_napi_value!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13);
630impl_tuple_validate_napi_value!(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14);
631impl_tuple_validate_napi_value!(
632  T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15
633);