napi/bindgen_runtime/js_values/
either.rs

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