use std::convert::{From, TryFrom}; use std::ptr; use crate::error::check_status; use crate::{sys, Error, Result, Status}; #[cfg(feature = "serde-json")] mod de; #[cfg(feature = "serde-json")] mod ser; mod arraybuffer; #[cfg(napi6)] mod bigint; mod boolean; mod buffer; mod either; mod escapable_handle_scope; mod function; mod number; mod object; mod object_property; mod string; mod tagged_object; mod undefined; mod value; mod value_ref; mod value_type; pub use arraybuffer::*; #[cfg(napi6)] pub use bigint::JsBigint; pub use boolean::JsBoolean; pub use buffer::*; #[cfg(feature = "serde-json")] pub(crate) use de::De; pub use either::Either; pub use escapable_handle_scope::EscapableHandleScope; pub use function::JsFunction; pub use number::JsNumber; pub use object::JsObject; pub use object_property::Property; #[cfg(feature = "serde-json")] pub(crate) use ser::Ser; pub use string::*; pub(crate) use tagged_object::TaggedObject; pub use undefined::JsUndefined; pub(crate) use value::Value; pub use value_ref::Ref; pub use value_type::ValueType; // Value types #[repr(transparent)] #[derive(Debug)] pub struct JsUnknown(pub(crate) Value); #[repr(transparent)] #[derive(Debug)] pub struct JsNull(pub(crate) Value); #[repr(transparent)] #[derive(Debug)] pub struct JsSymbol(pub(crate) Value); #[repr(transparent)] #[derive(Debug)] pub struct JsExternal(pub(crate) Value); #[inline] pub(crate) fn type_of(env: sys::napi_env, raw_value: sys::napi_value) -> Result<ValueType> { unsafe { let mut value_type = sys::napi_valuetype::napi_undefined; check_status(sys::napi_typeof(env, raw_value, &mut value_type))?; Ok(ValueType::from(value_type)) } } macro_rules! impl_napi_value_trait { ($js_value:ident, $value_type:ident) => { impl NapiValue for $js_value { fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<$js_value> { let value_type = type_of(env, value)?; if value_type != $value_type { Err(Error::new( Status::InvalidArg, format!("expect {:?}, got: {:?}", $value_type, value_type), )) } else { Ok($js_value(Value { env, value, value_type: $value_type, })) } } fn raw(&self) -> sys::napi_value { self.0.value } fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> $js_value { $js_value(Value { env, value, value_type: $value_type, }) } } impl TryFrom<JsUnknown> for $js_value { type Error = Error; fn try_from(value: JsUnknown) -> Result<$js_value> { $js_value::from_raw(value.0.env, value.0.value) } } }; } macro_rules! impl_js_value_methods { ($js_value:ident) => { impl $js_value { #[inline] pub fn into_unknown(self) -> Result<JsUnknown> { JsUnknown::from_raw(self.0.env, self.0.value) } #[inline] pub fn coerce_to_number(self) -> Result<JsNumber> { let mut new_raw_value = ptr::null_mut(); let status = unsafe { sys::napi_coerce_to_number(self.0.env, self.0.value, &mut new_raw_value) }; check_status(status)?; Ok(JsNumber(Value { env: self.0.env, value: new_raw_value, value_type: ValueType::Number, })) } #[inline] pub fn coerce_to_string(self) -> Result<JsString> { let mut new_raw_value = ptr::null_mut(); let status = unsafe { sys::napi_coerce_to_string(self.0.env, self.0.value, &mut new_raw_value) }; check_status(status)?; Ok(JsString(Value { env: self.0.env, value: new_raw_value, value_type: ValueType::String, })) } #[inline] pub fn coerce_to_object(self) -> Result<JsObject> { let mut new_raw_value = ptr::null_mut(); let status = unsafe { sys::napi_coerce_to_object(self.0.env, self.0.value, &mut new_raw_value) }; check_status(status)?; Ok(JsObject(Value { env: self.0.env, value: new_raw_value, value_type: ValueType::Object, })) } #[inline] #[cfg(napi5)] pub fn is_date(&self) -> Result<bool> { let mut is_date = true; let status = unsafe { sys::napi_is_date(self.0.env, self.0.value, &mut is_date) }; check_status(status)?; Ok(is_date) } #[inline] pub fn is_error(&self) -> Result<bool> { let mut result = false; check_status(unsafe { sys::napi_is_error(self.0.env, self.0.value, &mut result) })?; Ok(result) } #[inline] pub fn is_typedarray(&self) -> Result<bool> { let mut result = false; check_status(unsafe { sys::napi_is_typedarray(self.0.env, self.0.value, &mut result) })?; Ok(result) } #[inline] pub fn is_dataview(&self) -> Result<bool> { let mut result = false; check_status(unsafe { sys::napi_is_dataview(self.0.env, self.0.value, &mut result) })?; Ok(result) } #[inline] pub fn is_array(&self) -> Result<bool> { let mut is_array = false; check_status(unsafe { sys::napi_is_array(self.0.env, self.0.value, &mut is_array) })?; Ok(is_array) } #[inline] pub fn is_buffer(&self) -> Result<bool> { let mut is_buffer = false; check_status(unsafe { sys::napi_is_buffer(self.0.env, self.0.value, &mut is_buffer) })?; Ok(is_buffer) } #[inline] pub fn instanceof<Constructor: NapiValue>(&self, constructor: Constructor) -> Result<bool> { let mut result = false; check_status(unsafe { sys::napi_instanceof(self.0.env, self.0.value, constructor.raw(), &mut result) })?; Ok(result) } } }; } pub trait NapiValue: Sized { fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self>; fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self; fn raw(&self) -> sys::napi_value; } impl_js_value_methods!(JsUnknown); impl_js_value_methods!(JsUndefined); impl_js_value_methods!(JsNull); impl_js_value_methods!(JsBoolean); impl_js_value_methods!(JsArrayBuffer); impl_js_value_methods!(JsBuffer); impl_js_value_methods!(JsNumber); impl_js_value_methods!(JsString); impl_js_value_methods!(JsObject); impl_js_value_methods!(JsFunction); impl_js_value_methods!(JsExternal); impl_js_value_methods!(JsSymbol); use ValueType::*; impl_napi_value_trait!(JsUndefined, Undefined); impl_napi_value_trait!(JsNull, Null); impl_napi_value_trait!(JsBoolean, Boolean); impl_napi_value_trait!(JsBuffer, Object); impl_napi_value_trait!(JsArrayBuffer, Object); impl_napi_value_trait!(JsNumber, Number); impl_napi_value_trait!(JsString, String); impl_napi_value_trait!(JsObject, Object); impl_napi_value_trait!(JsFunction, Function); impl_napi_value_trait!(JsExternal, External); impl_napi_value_trait!(JsSymbol, Symbol); impl NapiValue for JsUnknown { fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> { Ok(JsUnknown(Value { env, value, value_type: Unknown, })) } fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self { JsUnknown(Value { env, value, value_type: Unknown, }) } fn raw(&self) -> sys::napi_value { self.0.value } } impl JsUnknown { #[inline] pub fn get_type(&self) -> Result<ValueType> { type_of(self.0.env, self.0.value) } }