napi_h/bindgen_runtime/js_values/
either.rs

1use super::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue};
2use crate::{
3  bindgen_runtime::{Null, Undefined, Unknown},
4  check_status, sys, Env, Error, JsUndefined, NapiRaw, NapiValue, Status, ValueType,
5};
6
7impl<A: NapiRaw, B: NapiRaw> Either<A, B> {
8  /// # Safety
9  /// Backward compatible with `Either` in **v1**
10  pub unsafe fn raw(&self) -> sys::napi_value {
11    match &self {
12      Self::A(a) => unsafe { a.raw() },
13      Self::B(b) => unsafe { b.raw() },
14    }
15  }
16}
17
18// Backwards compatibility with v1
19impl<T> From<Either<T, JsUndefined>> for Option<T> {
20  fn from(value: Either<T, JsUndefined>) -> Option<T> {
21    match value {
22      Either::A(v) => Some(v),
23      Either::B(_) => None,
24    }
25  }
26}
27
28impl<T> From<Option<T>> for Either<T, Undefined> {
29  fn from(value: Option<T>) -> Self {
30    match value {
31      Some(v) => Either::A(v),
32      None => Either::B(()),
33    }
34  }
35}
36
37impl<T> From<Either<T, Null>> for Option<T> {
38  fn from(value: Either<T, Null>) -> Option<T> {
39    match value {
40      Either::A(v) => Some(v),
41      Either::B(_) => None,
42    }
43  }
44}
45
46macro_rules! either_n {
47  ( $either_name:ident, $( $parameter:ident ),+ $( , )* ) => {
48    #[derive(Debug, Clone, Copy)]
49    pub enum $either_name< $( $parameter ),+ > {
50      $( $parameter ( $parameter ) ),+
51    }
52
53    impl< $( $parameter ),+ > TypeName for $either_name < $( $parameter ),+ >
54      where $( $parameter: TypeName ),+
55    {
56      fn type_name() -> &'static str {
57        stringify!( $either_name )
58      }
59
60      fn value_type() -> ValueType {
61        ValueType::Unknown
62      }
63    }
64
65    impl< $( $parameter ),+ > FromNapiValue for $either_name < $( $parameter ),+ >
66      where $( $parameter: TypeName + FromNapiValue + ValidateNapiValue ),+
67    {
68      unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> {
69        let mut ret = Err(Error::new(Status::InvalidArg, "Invalid value".to_owned()));
70        $(
71          if unsafe {
72            match $parameter::validate(env, napi_val) {
73              Ok(maybe_rejected_promise) => {
74                if maybe_rejected_promise.is_null() {
75                  true
76                } else {
77                  silence_rejected_promise(env, maybe_rejected_promise)?;
78                  false
79                }
80              },
81              Err(_) => false
82            }
83          } && unsafe { { ret = $parameter ::from_napi_value(env, napi_val).map(Self:: $parameter ); ret.is_ok() } } {
84            ret
85          } else
86        )+
87        {
88          Err(crate::Error::new(
89            Status::InvalidArg,
90            format!(
91              concat!("Value is non of these types ", $( "`{", stringify!( $parameter ), "}`, " ),+ ),
92              $( $parameter = $parameter::type_name(), )+
93            ),
94          ))
95        }
96      }
97    }
98
99    impl< $( $parameter ),+ > ToNapiValue for $either_name < $( $parameter ),+ >
100      where $( $parameter: ToNapiValue ),+
101    {
102      unsafe fn to_napi_value(
103        env: sys::napi_env,
104        value: Self
105      ) -> crate::Result<crate::sys::napi_value> {
106        match value {
107          $( Self:: $parameter (v) => unsafe { $parameter ::to_napi_value(env, v) } ),+
108        }
109      }
110    }
111
112    impl< $( $parameter ),+ > ValidateNapiValue for $either_name < $( $parameter ),+ >
113      where $( $parameter: ValidateNapiValue ),+
114    {
115      unsafe fn validate(
116        env: sys::napi_env,
117        napi_val: sys::napi_value,
118      ) -> crate::Result<sys::napi_value> {
119        let mut ret: crate::Result<sys::napi_value>;
120        $(
121          if unsafe {
122            ret = $parameter::validate(env, napi_val);
123            ret.is_ok()
124          } {
125            ret
126          } else
127        )+
128        {
129          ret
130        }
131      }
132    }
133
134    impl<Data, $( $parameter: AsRef<Data> ),+ > AsRef<Data> for $either_name < $( $parameter ),+ >
135      where Data: ?Sized,
136    {
137      fn as_ref(&self) -> &Data {
138        match &self {
139          $( Self:: $parameter (v) => v.as_ref() ),+
140        }
141      }
142    }
143
144    impl< $( $parameter ),+ > $either_name < $( $parameter ),+ >
145      where $( $parameter: NapiRaw ),+
146    {
147      pub fn as_unknown(&self, env: Env) -> Unknown {
148        match &self {
149          $( Self:: $parameter (v) => unsafe { Unknown::from_raw_unchecked(env.raw(), v.raw()) } ),+
150        }
151      }
152    }
153  };
154}
155
156either_n!(Either, A, B);
157either_n!(Either3, A, B, C);
158either_n!(Either4, A, B, C, D);
159either_n!(Either5, A, B, C, D, E);
160either_n!(Either6, A, B, C, D, E, F);
161either_n!(Either7, A, B, C, D, E, F, G);
162either_n!(Either8, A, B, C, D, E, F, G, H);
163either_n!(Either9, A, B, C, D, E, F, G, H, I);
164either_n!(Either10, A, B, C, D, E, F, G, H, I, J);
165either_n!(Either11, A, B, C, D, E, F, G, H, I, J, K);
166either_n!(Either12, A, B, C, D, E, F, G, H, I, J, K, L);
167either_n!(Either13, A, B, C, D, E, F, G, H, I, J, K, L, M);
168either_n!(Either14, A, B, C, D, E, F, G, H, I, J, K, L, M, N);
169either_n!(Either15, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O);
170either_n!(Either16, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P);
171either_n!(Either17, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q);
172either_n!(Either18, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R);
173either_n!(Either19, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S);
174either_n!(Either20, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T);
175either_n!(Either21, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U);
176either_n!(Either22, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V);
177either_n!(Either23, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W);
178either_n!(Either24, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X);
179either_n!(Either25, 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);
180either_n!(Either26, 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);
181
182fn silence_rejected_promise(env: sys::napi_env, promise: sys::napi_value) -> crate::Result<()> {
183  let mut catch_method = std::ptr::null_mut();
184  check_status!(unsafe {
185    sys::napi_get_named_property(env, promise, "catch\0".as_ptr().cast(), &mut catch_method)
186  })?;
187  let mut catch_noop_callback = std::ptr::null_mut();
188  check_status!(unsafe {
189    sys::napi_create_function(
190      env,
191      "catch\0".as_ptr().cast(),
192      5,
193      Some(noop),
194      std::ptr::null_mut(),
195      &mut catch_noop_callback,
196    )
197  })?;
198  check_status!(unsafe {
199    sys::napi_call_function(
200      env,
201      promise,
202      catch_method,
203      1,
204      vec![catch_noop_callback].as_ptr().cast(),
205      std::ptr::null_mut(),
206    )
207  })?;
208  Ok(())
209}
210
211unsafe extern "C" fn noop(_env: sys::napi_env, _info: sys::napi_callback_info) -> sys::napi_value {
212  std::ptr::null_mut()
213}