2021-11-02 01:34:19 +09:00
|
|
|
use super::{FromNapiValue, ToNapiValue, TypeName};
|
2022-05-12 16:11:47 +09:00
|
|
|
use crate::{
|
|
|
|
bindgen_runtime::{Null, Undefined},
|
|
|
|
sys, type_of, JsUndefined, NapiRaw, Status, ValueType,
|
|
|
|
};
|
2021-11-02 01:34:19 +09:00
|
|
|
|
|
|
|
const ERROR_MSG: &str = "The return value of typeof(T) should not be equal in Either";
|
|
|
|
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
2022-05-12 16:11:47 +09:00
|
|
|
pub enum Either<A, B> {
|
2021-11-02 01:34:19 +09:00
|
|
|
A(A),
|
|
|
|
B(B),
|
|
|
|
}
|
|
|
|
|
2022-05-12 16:11:47 +09:00
|
|
|
impl<A: NapiRaw, B: NapiRaw> Either<A, B> {
|
2021-11-23 15:49:24 +09:00
|
|
|
/// # Safety
|
|
|
|
/// Backward compatible with `Either` in **v1**
|
2022-05-06 22:16:35 +09:00
|
|
|
pub unsafe fn raw(&self) -> sys::napi_value {
|
2021-11-22 17:27:55 +09:00
|
|
|
match &self {
|
2022-01-13 12:15:02 +09:00
|
|
|
Self::A(a) => unsafe { a.raw() },
|
|
|
|
Self::B(b) => unsafe { b.raw() },
|
2021-11-22 17:27:55 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-12 16:11:47 +09:00
|
|
|
impl<A: TypeName, B: TypeName> TypeName for Either<A, B> {
|
2021-11-02 01:34:19 +09:00
|
|
|
fn type_name() -> &'static str {
|
|
|
|
"Either"
|
|
|
|
}
|
|
|
|
|
|
|
|
fn value_type() -> ValueType {
|
|
|
|
ValueType::Unknown
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-22 17:27:55 +09:00
|
|
|
// Backwards compatibility with v1
|
2022-05-12 16:11:47 +09:00
|
|
|
impl<T> From<Either<T, JsUndefined>> for Option<T> {
|
2021-11-22 17:27:55 +09:00
|
|
|
fn from(value: Either<T, JsUndefined>) -> Option<T> {
|
|
|
|
match value {
|
|
|
|
Either::A(v) => Some(v),
|
|
|
|
Either::B(_) => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-12 16:11:47 +09:00
|
|
|
impl<T> From<Option<T>> for Either<T, Undefined> {
|
|
|
|
fn from(value: Option<T>) -> Self {
|
|
|
|
match value {
|
|
|
|
Some(v) => Either::A(v),
|
|
|
|
None => Either::B(()),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<T> From<Either<T, Null>> for Option<T> {
|
|
|
|
fn from(value: Either<T, Null>) -> Option<T> {
|
2021-11-22 17:27:55 +09:00
|
|
|
match value {
|
|
|
|
Either::A(v) => Some(v),
|
|
|
|
Either::B(_) => None,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-12 16:11:47 +09:00
|
|
|
impl<A: TypeName + FromNapiValue, B: TypeName + FromNapiValue> FromNapiValue for Either<A, B> {
|
2022-05-06 22:16:35 +09:00
|
|
|
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> {
|
2021-11-02 01:34:19 +09:00
|
|
|
debug_assert!(A::value_type() != B::value_type(), "{}", ERROR_MSG);
|
|
|
|
let js_type = type_of!(env, napi_val)?;
|
|
|
|
if js_type == A::value_type() {
|
2022-01-13 12:15:02 +09:00
|
|
|
unsafe { A::from_napi_value(env, napi_val).map(Self::A) }
|
2021-11-02 01:34:19 +09:00
|
|
|
} else if js_type == B::value_type() {
|
2022-01-13 12:15:02 +09:00
|
|
|
unsafe { B::from_napi_value(env, napi_val).map(Self::B) }
|
2021-11-02 01:34:19 +09:00
|
|
|
} else {
|
|
|
|
Err(crate::Error::new(
|
|
|
|
Status::InvalidArg,
|
|
|
|
format!(
|
|
|
|
"Expect type {} or {}, but got {}",
|
|
|
|
A::value_type(),
|
|
|
|
B::value_type(),
|
|
|
|
js_type
|
|
|
|
),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-12 16:11:47 +09:00
|
|
|
impl<A: ToNapiValue, B: ToNapiValue> ToNapiValue for Either<A, B> {
|
2021-11-02 01:34:19 +09:00
|
|
|
unsafe fn to_napi_value(
|
2022-05-06 22:16:35 +09:00
|
|
|
env: sys::napi_env,
|
2021-11-02 01:34:19 +09:00
|
|
|
value: Self,
|
|
|
|
) -> crate::Result<crate::sys::napi_value> {
|
|
|
|
match value {
|
2022-01-13 12:15:02 +09:00
|
|
|
Self::A(a) => unsafe { A::to_napi_value(env, a) },
|
|
|
|
Self::B(b) => unsafe { B::to_napi_value(env, b) },
|
2021-11-02 01:34:19 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-02 04:47:23 +09:00
|
|
|
macro_rules! count_idents {
|
|
|
|
( $( $idents:ident ),* $( , )* ) => {
|
|
|
|
{
|
|
|
|
#[allow(dead_code, non_camel_case_types)]
|
|
|
|
enum Idents { $( $idents, )* __LastVariant }
|
|
|
|
const COUNT: usize = Idents::__LastVariant as usize;
|
|
|
|
|
|
|
|
COUNT
|
2021-11-02 01:34:19 +09:00
|
|
|
}
|
2022-06-02 04:47:23 +09:00
|
|
|
};
|
2021-11-02 01:34:19 +09:00
|
|
|
}
|
|
|
|
|
2022-06-02 04:47:23 +09:00
|
|
|
macro_rules! either_n {
|
|
|
|
( $either_name:ident, $( $parameter:ident ),+ $( , )* ) => {
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
|
|
pub enum $either_name< $( $parameter ),+ > {
|
|
|
|
$( $parameter ( $parameter ) ),+
|
2021-11-02 01:34:19 +09:00
|
|
|
}
|
|
|
|
|
2022-06-02 04:47:23 +09:00
|
|
|
impl< $( $parameter ),+ > TypeName for $either_name < $( $parameter ),+ >
|
|
|
|
where $( $parameter: TypeName ),+
|
|
|
|
{
|
|
|
|
fn type_name() -> &'static str {
|
|
|
|
stringify!( $either_name )
|
|
|
|
}
|
2021-11-02 01:34:19 +09:00
|
|
|
|
2022-06-02 04:47:23 +09:00
|
|
|
fn value_type() -> ValueType {
|
|
|
|
ValueType::Unknown
|
|
|
|
}
|
2021-11-02 01:34:19 +09:00
|
|
|
}
|
|
|
|
|
2022-06-02 04:47:23 +09:00
|
|
|
impl< $( $parameter ),+ > FromNapiValue for $either_name < $( $parameter ),+ >
|
|
|
|
where $( $parameter: TypeName + FromNapiValue ),+
|
|
|
|
{
|
|
|
|
unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result<Self> {
|
|
|
|
debug_assert!(
|
|
|
|
{
|
|
|
|
let mut types = vec![ $( $parameter ::value_type() ),+ ];
|
|
|
|
types.dedup();
|
|
|
|
|
|
|
|
types.len() == count_idents!( $( $parameter ),+ )
|
|
|
|
},
|
|
|
|
"{}",
|
|
|
|
ERROR_MSG
|
|
|
|
);
|
|
|
|
|
|
|
|
let js_type = type_of!(env, napi_val)?;
|
|
|
|
|
|
|
|
$(
|
|
|
|
if js_type == $parameter::value_type() {
|
|
|
|
unsafe { $parameter ::from_napi_value(env, napi_val).map(Self:: $parameter ) }
|
|
|
|
} else
|
|
|
|
)+
|
|
|
|
{
|
|
|
|
Err(crate::Error::new(
|
|
|
|
Status::InvalidArg,
|
|
|
|
format!(
|
|
|
|
concat!("Expect type ", $( "`{", stringify!( $parameter ), "}`, " ),+ , "but got {js_type}"),
|
|
|
|
$( $parameter = $parameter::value_type(), )+
|
|
|
|
js_type = js_type,
|
|
|
|
),
|
|
|
|
))
|
|
|
|
}
|
|
|
|
}
|
2021-11-02 01:34:19 +09:00
|
|
|
}
|
|
|
|
|
2022-06-02 04:47:23 +09:00
|
|
|
impl< $( $parameter ),+ > ToNapiValue for $either_name < $( $parameter ),+ >
|
|
|
|
where $( $parameter: ToNapiValue ),+
|
|
|
|
{
|
|
|
|
unsafe fn to_napi_value(
|
|
|
|
env: sys::napi_env,
|
|
|
|
value: Self
|
|
|
|
) -> crate::Result<crate::sys::napi_value> {
|
|
|
|
match value {
|
|
|
|
$( Self:: $parameter (v) => unsafe { $parameter ::to_napi_value(env, v) } ),+
|
|
|
|
}
|
|
|
|
}
|
2021-11-02 01:34:19 +09:00
|
|
|
}
|
2022-06-02 04:47:23 +09:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
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);
|