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}