use super::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue}; use crate::{ bindgen_runtime::{Null, Undefined, Unknown}, sys, Env, Error, JsUndefined, NapiRaw, NapiValue, Status, ValueType, }; #[derive(Debug, Clone, Copy)] pub enum Either { A(A), B(B), } impl Either { /// # Safety /// Backward compatible with `Either` in **v1** pub unsafe fn raw(&self) -> sys::napi_value { match &self { Self::A(a) => unsafe { a.raw() }, Self::B(b) => unsafe { b.raw() }, } } } impl ValidateNapiValue for Either { unsafe fn validate( env: sys::napi_env, napi_val: sys::napi_value, ) -> crate::Result { unsafe { A::validate(env, napi_val).or_else(|_| B::validate(env, napi_val)) } } } impl TypeName for Either { fn type_name() -> &'static str { "Either" } fn value_type() -> ValueType { ValueType::Unknown } } // Backwards compatibility with v1 impl From> for Option { fn from(value: Either) -> Option { match value { Either::A(v) => Some(v), Either::B(_) => None, } } } impl From> for Either { fn from(value: Option) -> Self { match value { Some(v) => Either::A(v), None => Either::B(()), } } } impl From> for Option { fn from(value: Either) -> Option { match value { Either::A(v) => Some(v), Either::B(_) => None, } } } impl< A: TypeName + FromNapiValue + ValidateNapiValue, B: TypeName + FromNapiValue + ValidateNapiValue, > FromNapiValue for Either { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result { if unsafe { A::validate(env, napi_val) }.is_ok() { unsafe { A::from_napi_value(env, napi_val) }.map(Either::A) } else if unsafe { B::validate(env, napi_val) }.is_ok() { unsafe { B::from_napi_value(env, napi_val).map(Either::B) } } else { Err(Error::new( Status::InvalidArg, format!( "Value is not either {} or {}", A::type_name(), B::type_name() ), )) } } } impl ToNapiValue for Either { unsafe fn to_napi_value( env: sys::napi_env, value: Self, ) -> crate::Result { match value { Self::A(a) => unsafe { A::to_napi_value(env, a) }, Self::B(b) => unsafe { B::to_napi_value(env, b) }, } } } macro_rules! either_n { ( $either_name:ident, $( $parameter:ident ),+ $( , )* ) => { #[derive(Debug, Clone, Copy)] pub enum $either_name< $( $parameter ),+ > { $( $parameter ( $parameter ) ),+ } impl< $( $parameter ),+ > TypeName for $either_name < $( $parameter ),+ > where $( $parameter: TypeName ),+ { fn type_name() -> &'static str { stringify!( $either_name ) } fn value_type() -> ValueType { ValueType::Unknown } } impl< $( $parameter ),+ > FromNapiValue for $either_name < $( $parameter ),+ > where $( $parameter: TypeName + FromNapiValue + ValidateNapiValue ),+ { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result { let mut ret = Err(Error::new(Status::InvalidArg, "Invalid value".to_owned())); $( if unsafe { $parameter::validate(env, napi_val).is_ok() && { ret = $parameter ::from_napi_value(env, napi_val).map(Self:: $parameter ); ret.is_ok() } } { ret } else )+ { Err(crate::Error::new( Status::InvalidArg, format!( concat!("Value is non of these types ", $( "`{", stringify!( $parameter ), "}`, " ),+ ), $( $parameter = $parameter::type_name(), )+ ), )) } } } impl< $( $parameter ),+ > ToNapiValue for $either_name < $( $parameter ),+ > where $( $parameter: ToNapiValue ),+ { unsafe fn to_napi_value( env: sys::napi_env, value: Self ) -> crate::Result { match value { $( Self:: $parameter (v) => unsafe { $parameter ::to_napi_value(env, v) } ),+ } } } impl< $( $parameter ),+ > ValidateNapiValue for $either_name < $( $parameter ),+ > where $( $parameter: ValidateNapiValue ),+ { unsafe fn validate( env: sys::napi_env, napi_val: sys::napi_value, ) -> crate::Result { let mut ret: crate::Result; $( if unsafe { ret = $parameter::validate(env, napi_val); ret.is_ok() } { ret } else )+ { ret } } } impl< $( $parameter ),+ > $either_name < $( $parameter ),+ > where $( $parameter: NapiRaw ),+ { pub fn as_unknown(&self, env: Env) -> Unknown { match &self { $( Self:: $parameter (v) => unsafe { Unknown::from_raw_unchecked(env.raw(), v.raw()) } ),+ } } } }; } either_n!(Either3, A, B, C); either_n!(Either4, A, B, C, D); either_n!(Either5, A, B, C, D, E); either_n!(Either6, A, B, C, D, E, F); either_n!(Either7, A, B, C, D, E, F, G); either_n!(Either8, A, B, C, D, E, F, G, H); either_n!(Either9, A, B, C, D, E, F, G, H, I); either_n!(Either10, A, B, C, D, E, F, G, H, I, J); either_n!(Either11, A, B, C, D, E, F, G, H, I, J, K); either_n!(Either12, A, B, C, D, E, F, G, H, I, J, K, L); either_n!(Either13, A, B, C, D, E, F, G, H, I, J, K, L, M); either_n!(Either14, A, B, C, D, E, F, G, H, I, J, K, L, M, N); either_n!(Either15, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O); either_n!(Either16, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P); either_n!(Either17, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q); either_n!(Either18, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R); either_n!(Either19, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S); either_n!(Either20, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T); either_n!(Either21, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U); either_n!(Either22, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V); either_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); either_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); either_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); either_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);