From 81b07ce5a69c8692f7e1bf13be8300df37d121e2 Mon Sep 17 00:00:00 2001 From: Ivan Enderlin Date: Wed, 1 Jun 2022 21:47:23 +0200 Subject: [PATCH 1/2] feat(napi) implement `Either3` to `Either26`. This patch introduces a new macro: `either_n!` that generates the types `Either{n}` where $3 \leq n \leq 26$. Manual implementations for `Either3`, `Either4` and `Either5` are removed by this patch too. The `either_n!` macro is quite classical. There is no particular trick, except `count_idents!` which simply turns, e.g. `A, B, C` into `3`. This macro is used by `either_n!` to implement the `debug_assert!` inside `from_napi_value`. --- crates/backend/src/typegen.rs | 21 ++ .../src/bindgen_runtime/js_values/either.rs | 312 +++++------------- 2 files changed, 112 insertions(+), 221 deletions(-) diff --git a/crates/backend/src/typegen.rs b/crates/backend/src/typegen.rs index 3f835ef1..81bd9108 100644 --- a/crates/backend/src/typegen.rs +++ b/crates/backend/src/typegen.rs @@ -180,6 +180,27 @@ static KNOWN_TYPES: Lazy> = Lazy::new(|| { ("Either3", "{} | {} | {}"), ("Either4", "{} | {} | {} | {}"), ("Either5", "{} | {} | {} | {} | {}"), + ("Either6", "{} | {} | {} | {} | {} | {}"), + ("Either7", "{} | {} | {} | {} | {} | {} | {}"), + ("Either8", "{} | {} | {} | {} | {} | {} | {} | {}"), + ("Either9", "{} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either10", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either11", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either12", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either13", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either14", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either15", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either16", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either17", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either18", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either19", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either20", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either21", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either22", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either23", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either24", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either25", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), + ("Either26", "{} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {} | {}"), ("Null", "null"), ("JsNull", "null"), ("null", "null"), diff --git a/crates/napi/src/bindgen_runtime/js_values/either.rs b/crates/napi/src/bindgen_runtime/js_values/either.rs index aab142b6..28ec5b4c 100644 --- a/crates/napi/src/bindgen_runtime/js_values/either.rs +++ b/crates/napi/src/bindgen_runtime/js_values/either.rs @@ -95,238 +95,108 @@ impl ToNapiValue for Either { } } -#[derive(Debug, Clone, Copy)] -pub enum Either3 { - A(A), - B(B), - C(C), -} +macro_rules! count_idents { + ( $( $idents:ident ),* $( , )* ) => { + { + #[allow(dead_code, non_camel_case_types)] + enum Idents { $( $idents, )* __LastVariant } + const COUNT: usize = Idents::__LastVariant as usize; -impl TypeName for Either3 { - fn type_name() -> &'static str { - "Either3" - } - - fn value_type() -> ValueType { - ValueType::Unknown - } -} - -impl - FromNapiValue for Either3 -{ - unsafe fn from_napi_value(env: sys::napi_env, napi_val: 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 - ), - )) + COUNT } - } + }; } -impl ToNapiValue for Either3 { - 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) }, - Self::C(c) => unsafe { C::to_napi_value(env, c) }, +macro_rules! either_n { + ( $either_name:ident, $( $parameter:ident ),+ $( , )* ) => { + #[derive(Debug, Clone, Copy)] + pub enum $either_name< $( $parameter ),+ > { + $( $parameter ( $parameter ) ),+ } - } -} -#[derive(Debug, Clone, Copy)] -pub enum Either4 { - A(A), - B(B), - C(C), - D(D), -} + impl< $( $parameter ),+ > TypeName for $either_name < $( $parameter ),+ > + where $( $parameter: TypeName ),+ + { + fn type_name() -> &'static str { + stringify!( $either_name ) + } -impl TypeName for Either4 { - fn type_name() -> &'static str { - "Either4" - } - - fn value_type() -> ValueType { - ValueType::Unknown - } -} - -impl< - A: TypeName + FromNapiValue, - B: TypeName + FromNapiValue, - C: TypeName + FromNapiValue, - D: TypeName + FromNapiValue, - > FromNapiValue for Either4 -{ - unsafe fn from_napi_value(env: sys::napi_env, napi_val: 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 - ), - )) + fn value_type() -> ValueType { + ValueType::Unknown + } } - } -} -impl ToNapiValue - for Either4 -{ - 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) }, - Self::C(c) => unsafe { C::to_napi_value(env, c) }, - Self::D(d) => unsafe { D::to_napi_value(env, d) }, + 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 { + 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, + ), + )) + } + } } - } -} -#[derive(Debug, Clone, Copy)] -pub enum Either5 { - A(A), - B(B), - C(C), - D(D), - E(E), -} - -impl TypeName - for Either5 -{ - fn type_name() -> &'static str { - "Either5" - } - - fn value_type() -> ValueType { - ValueType::Unknown - } -} - -impl< - A: TypeName + FromNapiValue, - B: TypeName + FromNapiValue, - C: TypeName + FromNapiValue, - D: TypeName + FromNapiValue, - E: TypeName + FromNapiValue, - > FromNapiValue for Either5 -{ - unsafe fn from_napi_value(env: sys::napi_env, napi_val: 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< $( $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 ToNapiValue - for Either5 -{ - 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) }, - 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) }, - } - } -} +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); From 53cab27bc44bacec5ece8d54c85b5cb5eafd6934 Mon Sep 17 00:00:00 2001 From: LongYinan Date: Tue, 5 Jul 2022 17:00:45 +0800 Subject: [PATCH 2/2] refactor(napi): Either now perform ValidateNapiValue::validate rather than type_of --- crates/backend/src/codegen/struct.rs | 42 ++++++++++++ crates/napi/src/bindgen_runtime/js_values.rs | 29 +++----- .../src/bindgen_runtime/js_values/array.rs | 6 +- .../src/bindgen_runtime/js_values/bigint.rs | 6 +- .../src/bindgen_runtime/js_values/boolean.rs | 6 +- .../src/bindgen_runtime/js_values/either.rs | 63 +++++------------- .../src/bindgen_runtime/js_values/external.rs | 6 +- .../src/bindgen_runtime/js_values/function.rs | 6 +- .../napi/src/bindgen_runtime/js_values/map.rs | 6 +- .../napi/src/bindgen_runtime/js_values/nil.rs | 12 +--- .../src/bindgen_runtime/js_values/number.rs | 7 +- .../src/bindgen_runtime/js_values/object.rs | 6 -- .../src/bindgen_runtime/js_values/promise.rs | 4 -- .../src/bindgen_runtime/js_values/string.rs | 24 ++----- .../src/bindgen_runtime/js_values/symbol.rs | 8 +-- crates/napi/src/js_values/arraybuffer.rs | 20 +++++- crates/napi/src/js_values/bigint.rs | 2 + crates/napi/src/js_values/boolean.rs | 4 +- crates/napi/src/js_values/buffer.rs | 19 +++++- crates/napi/src/js_values/mod.rs | 10 +-- crates/napi/src/js_values/number.rs | 4 +- crates/napi/src/js_values/string/mod.rs | 3 + crates/napi/src/js_values/undefined.rs | 7 +- examples/napi/__test__/typegen.spec.ts.md | 4 ++ examples/napi/__test__/typegen.spec.ts.snap | Bin 3285 -> 3307 bytes examples/napi/__test__/values.spec.ts | 9 +++ examples/napi/index.d.ts | 4 ++ examples/napi/src/either.rs | 19 ++++++ 28 files changed, 179 insertions(+), 157 deletions(-) diff --git a/crates/backend/src/codegen/struct.rs b/crates/backend/src/codegen/struct.rs index 63bcb09e..bde440fd 100644 --- a/crates/backend/src/codegen/struct.rs +++ b/crates/backend/src/codegen/struct.rs @@ -14,6 +14,38 @@ static NAPI_IMPL_ID: AtomicU32 = AtomicU32::new(0); // Generate trait implementations for given Struct. fn gen_napi_value_map_impl(name: &Ident, to_napi_val_impl: TokenStream) -> TokenStream { let name_str = name.to_string(); + let js_name_str = format!("{}\0", name_str); + let validate = quote! { + unsafe fn validate(env: napi::sys::napi_env, napi_val: napi::sys::napi_value) -> napi::Result { + if let Some(ctor_ref) = napi::bindgen_prelude::get_class_constructor(#js_name_str) { + let mut ctor = std::ptr::null_mut(); + napi::check_status!( + napi::sys::napi_get_reference_value(env, ctor_ref, &mut ctor), + "Failed to get constructor reference of class `{}`", + #name_str + )?; + let mut is_instance_of = false; + napi::check_status!( + napi::sys::napi_instanceof(env, napi_val, ctor, &mut is_instance_of), + "Failed to get external value of class `{}`", + #name_str + )?; + if is_instance_of { + Ok(std::ptr::null_mut()) + } else { + Err(napi::Error::new( + napi::Status::InvalidArg, + format!("Value is not instanceof class `{}`", #name_str) + )) + } + } else { + Err(napi::Error::new( + napi::Status::InvalidArg, + format!("Failed to get constructor of class `{}`", #name_str) + )) + } + } + }; quote! { impl napi::bindgen_prelude::TypeName for #name { fn type_name() -> &'static str { @@ -99,6 +131,14 @@ fn gen_napi_value_map_impl(name: &Ident, to_napi_val_impl: TokenStream) -> Token } } + impl napi::bindgen_prelude::ValidateNapiValue for &#name { + #validate + } + + impl napi::bindgen_prelude::ValidateNapiValue for &mut #name { + #validate + } + impl napi::NapiRaw for &#name { unsafe fn raw(&self) -> napi::sys::napi_value { unreachable!() @@ -523,6 +563,8 @@ impl NapiStruct { Ok(val) } } + + impl napi::bindgen_prelude::ValidateNapiValue for #name {} } } diff --git a/crates/napi/src/bindgen_runtime/js_values.rs b/crates/napi/src/bindgen_runtime/js_values.rs index cb1af7f8..50f1e74a 100644 --- a/crates/napi/src/bindgen_runtime/js_values.rs +++ b/crates/napi/src/bindgen_runtime/js_values.rs @@ -38,7 +38,6 @@ pub use buffer::*; pub use class::*; pub use either::*; pub use external::*; -#[cfg(feature = "napi4")] pub use function::*; pub use nil::*; pub use object::*; @@ -116,16 +115,15 @@ pub trait FromNapiMutRef { } pub trait ValidateNapiValue: FromNapiValue + TypeName { - fn type_of() -> Vec { - vec![] - } - /// # Safety /// /// this function called to validate whether napi value passed to rust is valid type + /// The reason why this function return `napi_value` is that if a `Promise` passed in + /// we need to return `Promise.reject(T)`, not the `T`. + /// So we need to create `Promise.reject(T)` in this function. unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result { - let available_types = Self::type_of(); - if available_types.is_empty() { + let value_type = Self::value_type(); + if value_type == ValueType::Unknown { return Ok(ptr::null_mut()); } @@ -136,22 +134,15 @@ pub trait ValidateNapiValue: FromNapiValue + TypeName { )?; let received_type = ValueType::from(result); - if available_types.contains(&received_type) { + if value_type == received_type { Ok(ptr::null_mut()) } else { Err(Error::new( Status::InvalidArg, - if available_types.len() > 1 { - format!( - "Expect value to be one of {:?}, but received {}", - available_types, received_type - ) - } else { - format!( - "Expect value to be {}, but received {}", - available_types[0], received_type - ) - }, + format!( + "Expect value to be {}, but received {}", + value_type, received_type + ), )) } } diff --git a/crates/napi/src/bindgen_runtime/js_values/array.rs b/crates/napi/src/bindgen_runtime/js_values/array.rs index 0f6c6f98..31fdaf63 100644 --- a/crates/napi/src/bindgen_runtime/js_values/array.rs +++ b/crates/napi/src/bindgen_runtime/js_values/array.rs @@ -165,11 +165,7 @@ impl Array { } } -impl ValidateNapiValue for Array { - fn type_of() -> Vec { - vec![ValueType::Object] - } -} +impl ValidateNapiValue for Array {} impl TypeName for Vec { fn type_name() -> &'static str { diff --git a/crates/napi/src/bindgen_runtime/js_values/bigint.rs b/crates/napi/src/bindgen_runtime/js_values/bigint.rs index cf96a6c9..3dc4a5f5 100644 --- a/crates/napi/src/bindgen_runtime/js_values/bigint.rs +++ b/crates/napi/src/bindgen_runtime/js_values/bigint.rs @@ -38,11 +38,7 @@ impl TypeName for BigInt { } } -impl ValidateNapiValue for BigInt { - fn type_of() -> Vec { - vec![crate::ValueType::BigInt] - } -} +impl ValidateNapiValue for BigInt {} impl FromNapiValue for BigInt { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result { diff --git a/crates/napi/src/bindgen_runtime/js_values/boolean.rs b/crates/napi/src/bindgen_runtime/js_values/boolean.rs index cc86d735..5a19b814 100644 --- a/crates/napi/src/bindgen_runtime/js_values/boolean.rs +++ b/crates/napi/src/bindgen_runtime/js_values/boolean.rs @@ -10,11 +10,7 @@ impl TypeName for bool { } } -impl ValidateNapiValue for bool { - fn type_of() -> Vec { - vec![ValueType::Boolean] - } -} +impl ValidateNapiValue for bool {} impl ToNapiValue for bool { unsafe fn to_napi_value(env: sys::napi_env, val: bool) -> Result { diff --git a/crates/napi/src/bindgen_runtime/js_values/either.rs b/crates/napi/src/bindgen_runtime/js_values/either.rs index 28ec5b4c..e84c25fb 100644 --- a/crates/napi/src/bindgen_runtime/js_values/either.rs +++ b/crates/napi/src/bindgen_runtime/js_values/either.rs @@ -1,11 +1,9 @@ -use super::{FromNapiValue, ToNapiValue, TypeName}; +use super::{FromNapiValue, ToNapiValue, TypeName, ValidateNapiValue}; use crate::{ bindgen_runtime::{Null, Undefined}, - sys, type_of, JsUndefined, NapiRaw, Status, ValueType, + sys, Error, 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(A), @@ -61,22 +59,23 @@ impl From> for Option { } } -impl FromNapiValue for Either { +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 { - 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) } + 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(crate::Error::new( + Err(Error::new( Status::InvalidArg, format!( - "Expect type {} or {}, but got {}", - A::value_type(), - B::value_type(), - js_type + "Value is not either {} or {}", + A::type_name(), + B::type_name() ), )) } @@ -95,18 +94,6 @@ impl ToNapiValue for Either { } } -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 - } - }; -} - macro_rules! either_n { ( $either_name:ident, $( $parameter:ident ),+ $( , )* ) => { #[derive(Debug, Clone, Copy)] @@ -127,24 +114,11 @@ macro_rules! either_n { } impl< $( $parameter ),+ > FromNapiValue for $either_name < $( $parameter ),+ > - where $( $parameter: TypeName + FromNapiValue ),+ + where $( $parameter: TypeName + FromNapiValue + ValidateNapiValue ),+ { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> crate::Result { - 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() { + if unsafe { $parameter::validate(env, napi_val).is_ok() } { unsafe { $parameter ::from_napi_value(env, napi_val).map(Self:: $parameter ) } } else )+ @@ -152,9 +126,8 @@ macro_rules! either_n { Err(crate::Error::new( Status::InvalidArg, format!( - concat!("Expect type ", $( "`{", stringify!( $parameter ), "}`, " ),+ , "but got {js_type}"), + concat!("Value is non of these types ", $( "`{", stringify!( $parameter ), "}`, " ),+ ), $( $parameter = $parameter::value_type(), )+ - js_type = js_type, ), )) } diff --git a/crates/napi/src/bindgen_runtime/js_values/external.rs b/crates/napi/src/bindgen_runtime/js_values/external.rs index 5ed77a4c..3ce29a13 100644 --- a/crates/napi/src/bindgen_runtime/js_values/external.rs +++ b/crates/napi/src/bindgen_runtime/js_values/external.rs @@ -23,11 +23,7 @@ impl TypeName for External { } } -impl ValidateNapiValue for External { - fn type_of() -> Vec { - vec![crate::ValueType::External] - } -} +impl ValidateNapiValue for External {} impl External { pub fn new(value: T) -> Self { diff --git a/crates/napi/src/bindgen_runtime/js_values/function.rs b/crates/napi/src/bindgen_runtime/js_values/function.rs index 208251d5..d7df6aea 100644 --- a/crates/napi/src/bindgen_runtime/js_values/function.rs +++ b/crates/napi/src/bindgen_runtime/js_values/function.rs @@ -2,8 +2,4 @@ use super::ValidateNapiValue; pub use crate::JsFunction; -impl ValidateNapiValue for JsFunction { - fn type_of() -> Vec { - vec![crate::ValueType::Function] - } -} +impl ValidateNapiValue for JsFunction {} diff --git a/crates/napi/src/bindgen_runtime/js_values/map.rs b/crates/napi/src/bindgen_runtime/js_values/map.rs index 91f6e8ea..6e0c4748 100644 --- a/crates/napi/src/bindgen_runtime/js_values/map.rs +++ b/crates/napi/src/bindgen_runtime/js_values/map.rs @@ -13,11 +13,7 @@ impl TypeName for HashMap { } } -impl + Eq + Hash, V: FromNapiValue> ValidateNapiValue for HashMap { - fn type_of() -> Vec { - vec![crate::ValueType::Object] - } -} +impl + Eq + Hash, V: FromNapiValue> ValidateNapiValue for HashMap {} impl ToNapiValue for HashMap where diff --git a/crates/napi/src/bindgen_runtime/js_values/nil.rs b/crates/napi/src/bindgen_runtime/js_values/nil.rs index 24a6d408..91b5a736 100644 --- a/crates/napi/src/bindgen_runtime/js_values/nil.rs +++ b/crates/napi/src/bindgen_runtime/js_values/nil.rs @@ -15,11 +15,7 @@ impl TypeName for Null { } } -impl ValidateNapiValue for Null { - fn type_of() -> Vec { - vec![ValueType::Null] - } -} +impl ValidateNapiValue for Null {} impl FromNapiValue for Null { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result { @@ -56,11 +52,7 @@ impl TypeName for Undefined { } } -impl ValidateNapiValue for Undefined { - fn type_of() -> Vec { - vec![ValueType::Undefined] - } -} +impl ValidateNapiValue for Undefined {} impl FromNapiValue for Undefined { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result { diff --git a/crates/napi/src/bindgen_runtime/js_values/number.rs b/crates/napi/src/bindgen_runtime/js_values/number.rs index 0c20b619..97296809 100644 --- a/crates/napi/src/bindgen_runtime/js_values/number.rs +++ b/crates/napi/src/bindgen_runtime/js_values/number.rs @@ -15,12 +15,7 @@ macro_rules! impl_number_conversions { } } - impl $crate::bindgen_prelude::ValidateNapiValue for $t { - #[inline(always)] - fn type_of() -> Vec<$crate::ValueType> { - vec![$crate::ValueType::Number] - } - } + impl $crate::bindgen_prelude::ValidateNapiValue for $t { } impl $crate::bindgen_prelude::ToNapiValue for $t { #[inline(always)] diff --git a/crates/napi/src/bindgen_runtime/js_values/object.rs b/crates/napi/src/bindgen_runtime/js_values/object.rs index 512ff5ae..04870e59 100644 --- a/crates/napi/src/bindgen_runtime/js_values/object.rs +++ b/crates/napi/src/bindgen_runtime/js_values/object.rs @@ -88,9 +88,3 @@ impl TypeName for Object { ValueType::Object } } - -impl ValidateNapiValue for Object { - fn type_of() -> Vec { - vec![ValueType::Object] - } -} diff --git a/crates/napi/src/bindgen_runtime/js_values/promise.rs b/crates/napi/src/bindgen_runtime/js_values/promise.rs index a9fa23c9..b2b710b0 100644 --- a/crates/napi/src/bindgen_runtime/js_values/promise.rs +++ b/crates/napi/src/bindgen_runtime/js_values/promise.rs @@ -25,10 +25,6 @@ impl TypeName for Promise { } impl ValidateNapiValue for Promise { - fn type_of() -> Vec { - vec![crate::ValueType::Object] - } - unsafe fn validate( env: crate::sys::napi_env, napi_val: crate::sys::napi_value, diff --git a/crates/napi/src/bindgen_runtime/js_values/string.rs b/crates/napi/src/bindgen_runtime/js_values/string.rs index 4ab329ac..9fb4635a 100644 --- a/crates/napi/src/bindgen_runtime/js_values/string.rs +++ b/crates/napi/src/bindgen_runtime/js_values/string.rs @@ -16,11 +16,7 @@ impl TypeName for String { } } -impl ValidateNapiValue for String { - fn type_of() -> Vec { - vec![ValueType::String] - } -} +impl ValidateNapiValue for String {} impl ToNapiValue for String { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { @@ -81,11 +77,7 @@ impl TypeName for &str { } } -impl ValidateNapiValue for &str { - fn type_of() -> Vec { - vec![ValueType::String] - } -} +impl ValidateNapiValue for &str {} impl FromNapiValue for &str { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result { @@ -146,11 +138,7 @@ impl ToNapiValue for &str { #[derive(Debug)] pub struct Utf16String(String); -impl ValidateNapiValue for Utf16String { - fn type_of() -> Vec { - vec![ValueType::String] - } -} +impl ValidateNapiValue for Utf16String {} impl From for Utf16String { fn from(s: String) -> Self { @@ -245,11 +233,7 @@ pub mod latin1_string { #[derive(Debug)] pub struct Latin1String(String); - impl ValidateNapiValue for Latin1String { - fn type_of() -> Vec { - vec![ValueType::String] - } - } + impl ValidateNapiValue for Latin1String {} impl From for Latin1String { fn from(s: String) -> Self { diff --git a/crates/napi/src/bindgen_runtime/js_values/symbol.rs b/crates/napi/src/bindgen_runtime/js_values/symbol.rs index 745b884b..fef0edb5 100644 --- a/crates/napi/src/bindgen_runtime/js_values/symbol.rs +++ b/crates/napi/src/bindgen_runtime/js_values/symbol.rs @@ -14,15 +14,11 @@ impl TypeName for Symbol { } fn value_type() -> crate::ValueType { - crate::ValueType::Object + crate::ValueType::Symbol } } -impl ValidateNapiValue for Symbol { - fn type_of() -> Vec { - vec![crate::ValueType::Symbol] - } -} +impl ValidateNapiValue for Symbol {} impl Symbol { pub fn new(desc: String) -> Self { diff --git a/crates/napi/src/js_values/arraybuffer.rs b/crates/napi/src/js_values/arraybuffer.rs index d61b4963..deb12b2d 100644 --- a/crates/napi/src/js_values/arraybuffer.rs +++ b/crates/napi/src/js_values/arraybuffer.rs @@ -3,8 +3,10 @@ use std::os::raw::c_void; use std::ptr; use std::slice; -use crate::bindgen_runtime::TypeName; -use crate::{check_status, sys, JsUnknown, NapiValue, Ref, Result, Value, ValueType}; +use crate::bindgen_runtime::{TypeName, ValidateNapiValue}; +use crate::{ + check_status, sys, Error, JsUnknown, NapiValue, Ref, Result, Status, Value, ValueType, +}; pub struct JsArrayBuffer(pub(crate) Value); @@ -18,6 +20,20 @@ impl TypeName for JsArrayBuffer { } } +impl ValidateNapiValue for JsArrayBuffer { + unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result { + let mut is_array_buffer = false; + check_status!(unsafe { sys::napi_is_arraybuffer(env, napi_val, &mut is_array_buffer) })?; + if !is_array_buffer { + return Err(Error::new( + Status::InvalidArg, + "Value is not an array buffer".to_owned(), + )); + } + Ok(ptr::null_mut()) + } +} + pub struct JsArrayBufferValue { pub(crate) value: JsArrayBuffer, len: usize, diff --git a/crates/napi/src/js_values/bigint.rs b/crates/napi/src/js_values/bigint.rs index b63fd6e8..245cddb1 100644 --- a/crates/napi/src/js_values/bigint.rs +++ b/crates/napi/src/js_values/bigint.rs @@ -20,6 +20,8 @@ impl TypeName for JsBigInt { } } +impl ValidateNapiValue for JsBigInt {} + impl JsBigInt { pub(crate) fn from_raw_unchecked( env: sys::napi_env, diff --git a/crates/napi/src/js_values/boolean.rs b/crates/napi/src/js_values/boolean.rs index 277d3dd5..c5d5d69f 100644 --- a/crates/napi/src/js_values/boolean.rs +++ b/crates/napi/src/js_values/boolean.rs @@ -1,7 +1,7 @@ use std::convert::TryFrom; use super::Value; -use crate::bindgen_runtime::TypeName; +use crate::bindgen_runtime::{TypeName, ValidateNapiValue}; use crate::{check_status, ValueType}; use crate::{sys, Error, Result}; @@ -18,6 +18,8 @@ impl TypeName for JsBoolean { } } +impl ValidateNapiValue for JsBoolean {} + impl JsBoolean { pub fn get_value(&self) -> Result { let mut result = false; diff --git a/crates/napi/src/js_values/buffer.rs b/crates/napi/src/js_values/buffer.rs index 1ce009de..ab21b83d 100644 --- a/crates/napi/src/js_values/buffer.rs +++ b/crates/napi/src/js_values/buffer.rs @@ -3,7 +3,10 @@ use std::ops::{Deref, DerefMut}; use std::ptr; use super::{Value, ValueType}; -use crate::{bindgen_runtime::TypeName, check_status, sys, JsUnknown, NapiValue, Ref, Result}; +use crate::bindgen_runtime::ValidateNapiValue; +use crate::{ + bindgen_runtime::TypeName, check_status, sys, Error, JsUnknown, NapiValue, Ref, Result, Status, +}; pub struct JsBuffer(pub(crate) Value); @@ -17,6 +20,20 @@ impl TypeName for JsBuffer { } } +impl ValidateNapiValue for JsBuffer { + unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result { + let mut is_buffer = false; + check_status!(unsafe { sys::napi_is_buffer(env, napi_val, &mut is_buffer) })?; + if !is_buffer { + return Err(Error::new( + Status::InvalidArg, + "Value is not a buffer".to_owned(), + )); + } + Ok(ptr::null_mut()) + } +} + pub struct JsBufferValue { pub(crate) value: JsBuffer, data: mem::ManuallyDrop>, diff --git a/crates/napi/src/js_values/mod.rs b/crates/napi/src/js_values/mod.rs index 0787e541..0c56a7b2 100644 --- a/crates/napi/src/js_values/mod.rs +++ b/crates/napi/src/js_values/mod.rs @@ -73,6 +73,8 @@ impl TypeName for JsNull { } } +impl ValidateNapiValue for JsNull {} + #[derive(Clone, Copy)] pub struct JsSymbol(pub(crate) Value); @@ -86,11 +88,7 @@ impl TypeName for JsSymbol { } } -impl ValidateNapiValue for JsSymbol { - fn type_of() -> Vec { - vec![ValueType::Symbol] - } -} +impl ValidateNapiValue for JsSymbol {} pub struct JsExternal(pub(crate) Value); @@ -104,6 +102,8 @@ impl TypeName for JsExternal { } } +impl ValidateNapiValue for JsExternal {} + macro_rules! impl_napi_value_trait { ($js_value:ident, $value_type:ident) => { impl NapiValue for $js_value { diff --git a/crates/napi/src/js_values/number.rs b/crates/napi/src/js_values/number.rs index e85fab73..9dc0965d 100644 --- a/crates/napi/src/js_values/number.rs +++ b/crates/napi/src/js_values/number.rs @@ -1,7 +1,7 @@ use std::convert::TryFrom; use super::Value; -use crate::bindgen_runtime::TypeName; +use crate::bindgen_runtime::{TypeName, ValidateNapiValue}; use crate::{check_status, ValueType}; use crate::{sys, Error, Result}; @@ -18,6 +18,8 @@ impl TypeName for JsNumber { } } +impl ValidateNapiValue for JsNumber {} + impl JsNumber { pub fn get_uint32(&self) -> Result { let mut result = 0; diff --git a/crates/napi/src/js_values/string/mod.rs b/crates/napi/src/js_values/string/mod.rs index 8aa26538..0e5eeff8 100644 --- a/crates/napi/src/js_values/string/mod.rs +++ b/crates/napi/src/js_values/string/mod.rs @@ -2,6 +2,7 @@ use std::mem; use std::ptr; use crate::bindgen_runtime::TypeName; +use crate::bindgen_runtime::ValidateNapiValue; use crate::ValueType; use crate::{check_status, sys, Result, Value}; @@ -26,6 +27,8 @@ impl TypeName for JsString { } } +impl ValidateNapiValue for JsString {} + impl JsString { pub fn utf8_len(&self) -> Result { let mut length = 0; diff --git a/crates/napi/src/js_values/undefined.rs b/crates/napi/src/js_values/undefined.rs index ede22046..bd5f5e0b 100644 --- a/crates/napi/src/js_values/undefined.rs +++ b/crates/napi/src/js_values/undefined.rs @@ -1,4 +1,7 @@ -use crate::{bindgen_runtime::TypeName, ValueType}; +use crate::{ + bindgen_runtime::{TypeName, ValidateNapiValue}, + ValueType, +}; use super::Value; @@ -14,3 +17,5 @@ impl TypeName for JsUndefined { ValueType::Undefined } } + +impl ValidateNapiValue for JsUndefined {} diff --git a/examples/napi/__test__/typegen.spec.ts.md b/examples/napi/__test__/typegen.spec.ts.md index cfc7453c..4271220a 100644 --- a/examples/napi/__test__/typegen.spec.ts.md +++ b/examples/napi/__test__/typegen.spec.ts.md @@ -62,6 +62,7 @@ Generated by [AVA](https://avajs.dev). export function either4(input: string | number | boolean | Obj): number␊ export function receiveClassOrNumber(either: number | JsClassForEither): number␊ export function receiveMutClassOrNumber(either: number | JsClassForEither): number␊ + export function receiveDifferentClass(either: JsClassForEither | AnotherClassForEither): number␊ export function returnEitherClass(input: number): number | JsClassForEither␊ export function eitherFromOption(): JsClassForEither | undefined␊ /** default enum values are continuos i32s start from 0 */␊ @@ -276,6 +277,9 @@ Generated by [AVA](https://avajs.dev). export class JsClassForEither {␊ constructor()␊ }␊ + export class AnotherClassForEither {␊ + constructor()␊ + }␊ export class Fib {␊ [Symbol.iterator](): Iterator␊ constructor()␊ diff --git a/examples/napi/__test__/typegen.spec.ts.snap b/examples/napi/__test__/typegen.spec.ts.snap index a7eaeb365f12c122dc3abcea82e16c073fc52729..a5f80b44c22a0d0bc928eb1a8efe7c2f59c1e203 100644 GIT binary patch literal 3307 zcmV

5Q0RzV&Pi+smeR|? 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 literal 3285 zcmV;`3@YXuyFs?R|01&aPIP!xAh*hlCLx!mP`N%CESBwBK3hBL$YB=@KBD3;-c z`tfI`xsKWOU({5laYQCeu!L$xLYX8i)I=}lj6`fq#yng0PK1$6HUUHDn<6LHA@7Ik4GPYujj*;m%wQAl^c>Dz`nsZxd7k!0Tdm_Yp!vsX`o}w#m7jbJcaS zmn1UrdHDpJoiN}{yjJ_!1loM?@Zm!s3=xBh#o4)`0Z(;z$rwB_G@S1aUj`21K+IDO z^bCa|uvEZwi6zzAU?dX)|8DrcY` zme|mFoRsCu?K#g3Ei7B}-7};da*k7>(!#-Z%cAfwk}_sg)Rr$(8kJ)_2inf#Crv?*UB27OsslV(mPD`CnQ$4G`TPp z86mrJ0s;MTH+%C2{7jh`lf55M4evMI`yo|&kzuCc1!jiALcHbnW^;hU^|G4t8=1m; zEWAe$qb>+Y3tY1~MC6E!A!35P2zHeVmMSam!)9>?snQaQ!aW?}I>&-JMxh`xDGMK` z3B&nq9PG<9f#)aqe9Euk@hLv;@yQg0e1?M~Zs`2gATvyTn~$4(0G1ufgYB(=^~%gF zDM%qMU77R{w52f{zg+_mDE@cm*;=JBXsa&EM6#j|^~!|y3fu}cSG_k>dO1HVduU^& zUG`b3eZf`{>Y^?D4d3U&H|h&agkxecEdi7l$=cn4!?fjn0L8a`T8%M;J~6TjX2IY+ z1kz__W{vesVeK$i75q7tji>=u=6NvBo?4MGVFl5uZ0SP}`RooD#ctl+9vqFlUJFOA zz*?0n9qN}8|UVLU#mHe#@femB#`K zyRuJdWY6QSWgM{6TLw}%U0Wic_AJG&XU`dbP_T<%#BxN967UdGj>*JKG=Z*Gg*jELtF$Qg`*CbH(1mMLKb1@y z#&p8+&21=vvSPbN3)KU7^)(vp!xzA-?)q;J`lp7gzAH|5uo5fy@TCEdVG+c+G?N7E zz!1P@d5HvLabjhNG7=c_O4Pc9Wuz*s7OP`;4RuA0xfWa1=A#A58}v#PmuxYBnO4G* zXytFHuv{5TshBWZ|D%OvVTt87S)O(~_bPwC^%rb1;(3&&clk>oPkS-kTdnF7Kf==yfi?UyQ|@v42?z}*QiTx z*ra&x^%3Uuc`+{Gw&z#Pls?6S!4nC-4lwfouTISQTc_82_6BVU5K?r9b!r?7{9cbYpRN!7mO@9mxek2dfTpU{~OoGS&SN%nm@$iHu|Lzm_z)s-Q$_>yYXa#V4kW4i{LO>JKJ%^V?A=tF_^fn zHywLbW(x)$0N`oPO48sh5ajgx?X6mOoK3B~=qn#xc%62qM5pC=q28JA$C7%BH)<_n z2^$wJJQ{T|GKOu2gP6`7`S!##GOBq;l|pMvC)0|K*Sb|aVNn{g#yx6CYxl?l^1&2O zShL9FLv|HpGTR3``vLO7_bJEQ8}KKneOVkSq9qwYmP$u454%W4;u+)>(1-9lA$&Fm zP~?etCnV0KGsxltZUT;5P0ni+ItqVBemd-`qa>ws-%2E`sg#j*GK)yr_|rhBu~D zH;1kR&l23t6KQMo56#90LMAf|E=92+^EMr4Z}KATwo|=nvzCpA<_%?_Z84x zc5S<`8C{In5o367=L*NNdOKxdc7eZ)$-HRG2qHOaIGuW9=SMoU%3XV3~xhBORuRj#*n%GBEj+Eb!t(AUM$m{!b7*{`GSy76^8ALg!Ny(j#mQ z?~tmCfsCz>o2}u$+BwXg_5FoZa*dTvxra9eyrk1Ed6?z6PX7U#9ANpJlM+L@wkogFB~d@n=V4eM=Nfm2A} zLVICLKyYk{Vin+S3AXbKxvy=@37gB>W<)&k(`Ev-l4ka<{lq*s(ZTuLu37`y;Pmt) zjoDkSFxU)~a-)jD7B37<2sAiu_)^jap*cleo$5u*PN$5S3=c~c6O9#Ub1W?3StdO? zRW?1)sv66AC_(-!+`AZ>IN5xK5GWE&H&I%}XrN)fB7_5}$kK>e$-{LBw*}37<_n{| zYK~`p*Vj{P@uhR={@a5ujt=*ZhMvVY+~90~_w-5I^^Hx*0JORFtUxk3xPcM?EhqFf z@@eJvY1o;soe=fBXR&QvW-;?Bt-78m)9`)7Cr~p6J`1-ky4&(~=L@uj=d~*?X_|HV T^~#&E+k5{92EUjt=q&&M%ppk> diff --git a/examples/napi/__test__/values.spec.ts b/examples/napi/__test__/values.spec.ts index 412e053e..e04a1d76 100644 --- a/examples/napi/__test__/values.spec.ts +++ b/examples/napi/__test__/values.spec.ts @@ -99,6 +99,8 @@ import { overrideIndividualArgOnFunctionWithCbArg, createObjectWithClassField, receiveObjectWithClassField, + AnotherClassForEither, + receiveDifferentClass, } from '../' test('export const', (t) => { @@ -500,6 +502,13 @@ test('receive class reference in either', (t) => { t.is(receiveMutClassOrNumber(c), 100) }) +test('receive different class', (t) => { + const a = new JsClassForEither() + const b = new AnotherClassForEither() + t.is(receiveDifferentClass(a), 42) + t.is(receiveDifferentClass(b), 100) +}) + test('return either class', (t) => { t.is(returnEitherClass(1), 1) t.true(returnEitherClass(-1) instanceof JsClassForEither) diff --git a/examples/napi/index.d.ts b/examples/napi/index.d.ts index 0531adfe..5d537f7f 100644 --- a/examples/napi/index.d.ts +++ b/examples/napi/index.d.ts @@ -52,6 +52,7 @@ export interface Obj { export function either4(input: string | number | boolean | Obj): number export function receiveClassOrNumber(either: number | JsClassForEither): number export function receiveMutClassOrNumber(either: number | JsClassForEither): number +export function receiveDifferentClass(either: JsClassForEither | AnotherClassForEither): number export function returnEitherClass(input: number): number | JsClassForEither export function eitherFromOption(): JsClassForEither | undefined /** default enum values are continuos i32s start from 0 */ @@ -266,6 +267,9 @@ export class ClassWithFactory { export class JsClassForEither { constructor() } +export class AnotherClassForEither { + constructor() +} export class Fib { [Symbol.iterator](): Iterator constructor() diff --git a/examples/napi/src/either.rs b/examples/napi/src/either.rs index 0f5fa8cd..d5c3498d 100644 --- a/examples/napi/src/either.rs +++ b/examples/napi/src/either.rs @@ -67,6 +67,17 @@ impl JsClassForEither { } } +#[napi] +struct AnotherClassForEither {} + +#[napi] +impl AnotherClassForEither { + #[napi(constructor)] + pub fn new() -> Self { + Self {} + } +} + #[napi] fn receive_class_or_number(either: Either) -> u32 { match either { @@ -83,6 +94,14 @@ fn receive_mut_class_or_number(either: Either) -> u3 } } +#[napi] +fn receive_different_class(either: Either<&JsClassForEither, &AnotherClassForEither>) -> u32 { + match either { + Either::A(_) => 42, + Either::B(_) => 100, + } +} + #[napi] fn return_either_class(input: i32) -> Either { if input > 0 {