Skip to main content

edon/napi/bindgen_runtime/js_values/
array.rs

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