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/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.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 aab142b6..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,238 +94,82 @@ impl ToNapiValue for Either { } } -#[derive(Debug, Clone, Copy)] -pub enum Either3 { - A(A), - B(B), - C(C), -} - -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 - ), - )) +macro_rules! either_n { + ( $either_name:ident, $( $parameter:ident ),+ $( , )* ) => { + #[derive(Debug, Clone, Copy)] + pub enum $either_name< $( $parameter ),+ > { + $( $parameter ( $parameter ) ),+ } - } -} -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) }, + impl< $( $parameter ),+ > TypeName for $either_name < $( $parameter ),+ > + where $( $parameter: TypeName ),+ + { + fn type_name() -> &'static str { + stringify!( $either_name ) + } + + fn value_type() -> ValueType { + ValueType::Unknown + } } - } -} -#[derive(Debug, Clone, Copy)] -pub enum Either4 { - A(A), - B(B), - C(C), - D(D), -} - -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 - ), - )) + 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 { + $( + if unsafe { $parameter::validate(env, napi_val).is_ok() } { + unsafe { $parameter ::from_napi_value(env, napi_val).map(Self:: $parameter ) } + } else + )+ + { + Err(crate::Error::new( + Status::InvalidArg, + format!( + concat!("Value is non of these types ", $( "`{", stringify!( $parameter ), "}`, " ),+ ), + $( $parameter = $parameter::value_type(), )+ + ), + )) + } + } } - } -} -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 ),+ > 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) } ),+ + } + } } - } + }; } -#[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 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); 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 a7eaeb36..a5f80b44 100644 Binary files a/examples/napi/__test__/typegen.spec.ts.snap and b/examples/napi/__test__/typegen.spec.ts.snap differ 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 {