use super::{FromNapiValue, ToNapiValue, TypeName}; use crate::{type_of, JsNull, JsUndefined, NapiRaw, Status, ValueType}; const ERROR_MSG: &str = "The return value of typeof(T) should not be equal in Either"; #[derive(Debug, Clone, Copy)] pub enum Either< A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue, > { A(A), B(B), } impl< A: TypeName + FromNapiValue + ToNapiValue + NapiRaw, B: TypeName + FromNapiValue + ToNapiValue + NapiRaw, > Either { /// # Safety /// Backward compatible with `Either` in **v1** pub unsafe fn raw(&self) -> napi_sys::napi_value { match &self { Self::A(a) => unsafe { a.raw() }, Self::B(b) => unsafe { b.raw() }, } } } 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 Option { fn from(value: Either) -> Option { match value { Either::A(v) => Some(v), Either::B(_) => None, } } } impl FromNapiValue for Either { unsafe fn from_napi_value( env: napi_sys::napi_env, napi_val: napi_sys::napi_value, ) -> crate::Result { debug_assert!(A::value_type() != B::value_type(), "{}", ERROR_MSG); let js_type = type_of!(env, napi_val)?; if js_type == A::value_type() { unsafe { A::from_napi_value(env, napi_val).map(Self::A) } } else if js_type == B::value_type() { unsafe { B::from_napi_value(env, napi_val).map(Self::B) } } else { Err(crate::Error::new( Status::InvalidArg, format!( "Expect type {} or {}, but got {}", A::value_type(), B::value_type(), js_type ), )) } } } impl ToNapiValue for Either { unsafe fn to_napi_value( env: napi_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) }, } } } #[derive(Debug, Clone, Copy)] pub enum Either3< A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue + ToNapiValue, > { A(A), B(B), C(C), } impl< A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue + ToNapiValue, > TypeName for Either3 { fn type_name() -> &'static str { "Either3" } fn value_type() -> ValueType { ValueType::Unknown } } impl< A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue + ToNapiValue, > FromNapiValue for Either3 { unsafe fn from_napi_value( env: napi_sys::napi_env, napi_val: napi_sys::napi_value, ) -> crate::Result { debug_assert!( { let mut types = vec![A::value_type(), B::value_type(), C::value_type()]; types.dedup(); types.len() == 3 }, "{}", ERROR_MSG ); let js_type = type_of!(env, napi_val)?; if js_type == A::value_type() { unsafe { A::from_napi_value(env, napi_val).map(Self::A) } } else if js_type == B::value_type() { unsafe { B::from_napi_value(env, napi_val).map(Self::B) } } else if js_type == C::value_type() { unsafe { C::from_napi_value(env, napi_val).map(Self::C) } } else { Err(crate::Error::new( Status::InvalidArg, format!( "Expect type {} or {} or {}, but got {}", A::value_type(), B::value_type(), C::value_type(), js_type ), )) } } } impl< A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue + ToNapiValue, > ToNapiValue for Either3 { unsafe fn to_napi_value( env: napi_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) }, Self::C(c) => unsafe { C::to_napi_value(env, c) }, } } } #[derive(Debug, Clone, Copy)] pub enum Either4< A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue + ToNapiValue, D: TypeName + FromNapiValue + ToNapiValue, > { A(A), B(B), C(C), D(D), } impl< A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue + ToNapiValue, D: TypeName + FromNapiValue + ToNapiValue, > TypeName for Either4 { fn type_name() -> &'static str { "Either4" } fn value_type() -> ValueType { ValueType::Unknown } } impl< A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue + ToNapiValue, D: TypeName + FromNapiValue + ToNapiValue, > FromNapiValue for Either4 { unsafe fn from_napi_value( env: napi_sys::napi_env, napi_val: napi_sys::napi_value, ) -> crate::Result { debug_assert!( { let mut types = vec![ A::value_type(), B::value_type(), C::value_type(), D::value_type(), ]; types.dedup(); types.len() == 4 }, "{}", ERROR_MSG ); let js_type = type_of!(env, napi_val)?; if js_type == A::value_type() { unsafe { A::from_napi_value(env, napi_val).map(Self::A) } } else if js_type == B::value_type() { unsafe { B::from_napi_value(env, napi_val).map(Self::B) } } else if js_type == C::value_type() { unsafe { C::from_napi_value(env, napi_val).map(Self::C) } } else if js_type == D::value_type() { unsafe { D::from_napi_value(env, napi_val).map(Self::D) } } else { Err(crate::Error::new( Status::InvalidArg, format!( "Expect type {} or {} or {} or {}, but got {}", A::value_type(), B::value_type(), C::value_type(), D::value_type(), js_type ), )) } } } impl< A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue + ToNapiValue, D: TypeName + FromNapiValue + ToNapiValue, > ToNapiValue for Either4 { unsafe fn to_napi_value( env: napi_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) }, Self::C(c) => unsafe { C::to_napi_value(env, c) }, Self::D(d) => unsafe { D::to_napi_value(env, d) }, } } } #[derive(Debug, Clone, Copy)] pub enum Either5< A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue + ToNapiValue, D: TypeName + FromNapiValue + ToNapiValue, E: TypeName + FromNapiValue + ToNapiValue, > { A(A), B(B), C(C), D(D), E(E), } impl< A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue + ToNapiValue, D: TypeName + FromNapiValue + ToNapiValue, E: TypeName + FromNapiValue + ToNapiValue, > TypeName for Either5 { fn type_name() -> &'static str { "Either5" } fn value_type() -> ValueType { ValueType::Unknown } } impl< A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue + ToNapiValue, D: TypeName + FromNapiValue + ToNapiValue, E: TypeName + FromNapiValue + ToNapiValue, > FromNapiValue for Either5 { unsafe fn from_napi_value( env: napi_sys::napi_env, napi_val: napi_sys::napi_value, ) -> crate::Result { debug_assert!( { let mut types = vec![ A::value_type(), B::value_type(), C::value_type(), D::value_type(), E::value_type(), ]; types.dedup(); types.len() == 5 }, "{}", ERROR_MSG ); let js_type = type_of!(env, napi_val)?; if js_type == A::value_type() { unsafe { A::from_napi_value(env, napi_val).map(Self::A) } } else if js_type == B::value_type() { unsafe { B::from_napi_value(env, napi_val).map(Self::B) } } else if js_type == C::value_type() { unsafe { C::from_napi_value(env, napi_val).map(Self::C) } } else if js_type == D::value_type() { unsafe { D::from_napi_value(env, napi_val).map(Self::D) } } else if js_type == E::value_type() { unsafe { E::from_napi_value(env, napi_val).map(Self::E) } } else { Err(crate::Error::new( Status::InvalidArg, format!( "Expect type {} or {} or {} or {} or {}, but got {}", A::value_type(), B::value_type(), C::value_type(), D::value_type(), E::value_type(), js_type ), )) } } } impl< A: TypeName + FromNapiValue + ToNapiValue, B: TypeName + FromNapiValue + ToNapiValue, C: TypeName + FromNapiValue + ToNapiValue, D: TypeName + FromNapiValue + ToNapiValue, E: TypeName + FromNapiValue + ToNapiValue, > ToNapiValue for Either5 { unsafe fn to_napi_value( env: napi_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) }, Self::C(c) => unsafe { C::to_napi_value(env, c) }, Self::D(d) => unsafe { D::to_napi_value(env, d) }, Self::E(e) => unsafe { E::to_napi_value(env, e) }, } } }