use std::ptr; use crate::{check_status, sys, Error, JsUnknown, NapiRaw, NapiValue, Result, Status, ValueType}; mod array; #[cfg(feature = "napi6")] mod bigint; mod boolean; mod buffer; mod either; mod external; mod function; mod map; mod nil; mod number; mod object; #[cfg(all(feature = "tokio_rt", feature = "napi4"))] mod promise; #[cfg(feature = "serde-json")] mod serde; mod string; mod symbol; mod task; pub use array::*; #[cfg(feature = "napi6")] pub use bigint::*; pub use buffer::*; pub use either::*; pub use external::*; #[cfg(feature = "napi4")] pub use function::*; pub use nil::*; pub use object::*; #[cfg(all(feature = "tokio_rt", feature = "napi4"))] pub use promise::*; pub use string::*; pub use symbol::*; pub use task::*; #[cfg(feature = "latin1")] pub use string::latin1_string::*; pub trait TypeName { fn type_name() -> &'static str; fn value_type() -> ValueType; } pub trait ToNapiValue { /// # Safety /// /// this function called to convert rust values to napi values unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result; } impl TypeName for JsUnknown { fn type_name() -> &'static str { "unknown" } fn value_type() -> ValueType { ValueType::Unknown } } impl ToNapiValue for T { unsafe fn to_napi_value(_env: sys::napi_env, val: Self) -> Result { Ok(NapiRaw::raw(&val)) } } impl FromNapiValue for T { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result { Ok(T::from_raw_unchecked(env, napi_val)) } } pub trait FromNapiValue: Sized { /// # Safety /// /// this function called to convert napi values to native rust values unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result; } pub trait FromNapiRef { /// # Safety /// /// this function called to convert napi values to native rust values unsafe fn from_napi_ref(env: sys::napi_env, napi_val: sys::napi_value) -> Result<&'static Self>; } pub trait FromNapiMutRef { /// # Safety /// /// this function called to convert napi values to native rust values unsafe fn from_napi_mut_ref( env: sys::napi_env, napi_val: sys::napi_value, ) -> Result<&'static mut Self>; } 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 unsafe fn validate(env: sys::napi_env, napi_val: sys::napi_value) -> Result<()> { let available_types = Self::type_of(); if available_types.is_empty() { return Ok(()); } let mut result = -1; check_status!( sys::napi_typeof(env, napi_val, &mut result), "Failed to detect napi value type", )?; let received_type = ValueType::from(result); if available_types.contains(&received_type) { Ok(()) } 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 ) }, )) } } } impl TypeName for Option { fn type_name() -> &'static str { "Option" } fn value_type() -> ValueType { T::value_type() } } impl FromNapiValue for Option where T: FromNapiValue, { unsafe fn from_napi_value(env: sys::napi_env, napi_val: sys::napi_value) -> Result { let mut val_type = 0; check_status!( sys::napi_typeof(env, napi_val, &mut val_type), "Failed to convert napi value into rust type `Option`", )?; match val_type { sys::ValueType::napi_undefined | sys::ValueType::napi_null => Ok(None), _ => Ok(Some(T::from_napi_value(env, napi_val)?)), } } } impl ToNapiValue for Option where T: ToNapiValue, { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { match val { Some(val) => T::to_napi_value(env, val), None => { let mut ptr = ptr::null_mut(); check_status!( sys::napi_get_null(env, &mut ptr), "Failed to convert rust type `Option` into napi value", )?; Ok(ptr) } } } } impl ToNapiValue for Result where T: ToNapiValue, { unsafe fn to_napi_value(env: sys::napi_env, val: Self) -> Result { match val { Ok(v) => T::to_napi_value(env, v), Err(e) => { let error_code = String::to_napi_value(env, format!("{:?}", e.status))?; let reason = String::to_napi_value(env, e.reason)?; let mut error = ptr::null_mut(); check_status!( sys::napi_create_error(env, error_code, reason, &mut error), "Failed to create napi error" )?; Ok(error) } } } }