diff --git a/napi/Cargo.toml b/napi/Cargo.toml index 40580443..8c62191b 100644 --- a/napi/Cargo.toml +++ b/napi/Cargo.toml @@ -10,6 +10,14 @@ keywords = ["NodeJS", "FFI"] [dependencies] futures = { version = "0.3", features = ["default", "thread-pool"] } +serde = { version = "1", optional = true } +serde_json = { version = "1", optional = true } +rayon = { version = "1", optional = true } + +[features] +serde-json = ["serde", "serde_json", "rayon"] + +default = ["serde-json"] [target.'cfg(windows)'.build-dependencies] flate2 = "1.0" diff --git a/napi/src/lib.rs b/napi/src/lib.rs index baa02ddb..ab870419 100644 --- a/napi/src/lib.rs +++ b/napi/src/lib.rs @@ -1,3 +1,8 @@ +#[cfg(feature = "serde-json")] +extern crate rayon; +#[cfg(feature = "serde-json")] +extern crate serde_json; + pub extern crate futures; use std::any::TypeId; use std::ffi::CString; @@ -9,6 +14,9 @@ use std::ptr; use std::slice; use std::string::String as RustString; +#[cfg(feature = "serde-json")] +use serde_json::value::Value as SerdeValue; + mod executor; pub mod sys; @@ -32,14 +40,18 @@ pub struct Any; #[derive(Clone, Copy, Debug)] pub struct Undefined; +#[derive(Clone, Copy, Debug)] +pub struct Null; + #[derive(Clone, Copy, Debug)] pub struct Boolean { value: bool, } #[derive(Clone, Copy, Debug)] -pub struct Number { - int: i64, +pub enum Number { + Int(i64), + Double(f64), } #[derive(Clone, Copy, Debug)] @@ -188,7 +200,7 @@ macro_rules! callback { match result { Ok(Some(result)) => result.into_raw(), - Ok(None) => env.get_undefined().into_raw(), + Ok(None) => env.get_undefined().unwrap().into_raw(), Err(e) => { if !cfg!(windows) { let _ = writeln!(::std::io::stderr(), "Error calling function: {:?}", e); @@ -197,7 +209,7 @@ macro_rules! callback { unsafe { $crate::sys::napi_throw_error(raw_env, ptr::null(), message.as_ptr() as *const c_char); } - env.get_undefined().into_raw() + env.get_undefined().unwrap().into_raw() } } } @@ -225,11 +237,18 @@ impl Env { Env(env) } - pub fn get_undefined<'a>(&'a self) -> Value<'a, Undefined> { + pub fn get_undefined<'a>(&'a self) -> Result> { let mut raw_value = ptr::null_mut(); let status = unsafe { sys::napi_get_undefined(self.0, &mut raw_value) }; - debug_assert!(Status::from(status) == Status::Ok); - Value::from_raw_value(self, raw_value, Undefined) + check_status(status)?; + Ok(Value::from_raw_value(self, raw_value, Undefined)) + } + + pub fn get_null<'a>(&'a self) -> Result> { + let mut raw_value = ptr::null_mut(); + let status = unsafe { sys::napi_get_null(self.0, &mut raw_value) }; + check_status(status)?; + Ok(Value::from_raw_value(self, raw_value, Null)) } pub fn get_boolean(&self, value: bool) -> Value { @@ -239,15 +258,27 @@ impl Env { Value::from_raw_value(self, raw_value, Boolean { value }) } - pub fn create_int64<'a>(&'a self, int: i64) -> Value<'a, Number> { + pub fn create_int64<'a>(&'a self, int: i64) -> Result> { let mut raw_value = ptr::null_mut(); let status = unsafe { sys::napi_create_int64(self.0, int, (&mut raw_value) as *mut sys::napi_value) }; - debug_assert!(Status::from(status) == Status::Ok); - Value::from_raw_value(self, raw_value, Number { int }) + check_status(status)?; + Ok(Value::from_raw_value(self, raw_value, Number::Int(int))) } - pub fn create_string<'a, 'b>(&'a self, s: &'b str) -> Value<'a, String> { + pub fn create_double<'a>(&'a self, double: f64) -> Result> { + let mut raw_value = ptr::null_mut(); + let status = + unsafe { sys::napi_create_double(self.0, double, (&mut raw_value) as *mut sys::napi_value) }; + check_status(status)?; + Ok(Value::from_raw_value( + self, + raw_value, + Number::Double(double), + )) + } + + pub fn create_string<'a, 'b>(&'a self, s: &'b str) -> Result> { let mut raw_value = ptr::null_mut(); let status = unsafe { sys::napi_create_string_utf8( @@ -257,8 +288,8 @@ impl Env { &mut raw_value, ) }; - debug_assert!(Status::from(status) == Status::Ok); - Value::from_raw_value(self, raw_value, String) + check_status(status)?; + Ok(Value::from_raw_value(self, raw_value, String)) } pub fn create_string_utf16<'a, 'b>(&'a self, chars: &[u16]) -> Value<'a, String> { @@ -277,6 +308,48 @@ impl Env { Value::from_raw_value(self, raw_value, Object) } + #[cfg(feature = "serde-json")] + pub fn from_serde_value<'a>(&'a self, serde_value: &'a SerdeValue) -> Result> { + match serde_value { + SerdeValue::Array(v) => { + let result = self.create_array_with_length(v.len()); + v.iter().enumerate().try_for_each(|(index, value)| unsafe { + let status = sys::napi_set_element( + self.0, + result.into_raw(), + index as u32, + self.from_serde_value(value)?.into_raw(), + ); + check_status(status) + })?; + Ok(result.into_any()) + } + SerdeValue::Bool(v) => Ok(self.get_boolean(*v).into_any()), + SerdeValue::Number(v) => { + if v.is_f64() { + self + .create_double(v.as_f64().unwrap()) + .map(|v| v.into_any()) + } else if v.is_i64() { + self.create_int64(v.as_i64().unwrap()).map(|v| v.into_any()) + } else { + self + .create_int64(v.as_u64().unwrap() as i64) + .map(|v| v.into_any()) + } + } + SerdeValue::Null => self.get_null().map(|v| v.into_any()), + SerdeValue::String(s) => self.create_string(s).map(|v| v.into_any()), + SerdeValue::Object(map) => { + let mut result = self.create_object(); + map.iter().try_for_each(|(key, value)| { + result.set_named_property(key, self.from_serde_value(value)?) + })?; + Ok(result.into_any()) + } + } + } + pub fn create_array_with_length(&self, length: usize) -> Value { let mut raw_value = ptr::null_mut(); let status = @@ -381,12 +454,12 @@ impl Env { name: &'b str, constructor_cb: Callback, properties: Vec, - ) -> Value<'a, Function> { + ) -> Result> { let mut raw_result = ptr::null_mut(); let raw_properties = properties .into_iter() .map(|prop| prop.into_raw(self)) - .collect::>(); + .collect::>>()?; let status = unsafe { sys::napi_define_class( @@ -401,9 +474,9 @@ impl Env { ) }; - debug_assert!(Status::from(status) == Status::Ok); + check_status(status)?; - Value::from_raw_value(self, raw_result, Function) + Ok(Value::from_raw_value(self, raw_result, Function)) } pub fn wrap(&self, js_object: &mut Value, native_object: T) -> Result<()> { @@ -460,46 +533,48 @@ impl Env { } } - pub fn async_init(&self, resource: Option>, name: &str) -> AsyncContext { + pub fn async_init(&self, resource: Option>, name: &str) -> Result { let raw_resource = resource .map(|r| r.into_raw()) .unwrap_or_else(|| self.create_object().into_raw()); - let raw_name = self.create_string(name).into_raw(); + let raw_name = self.create_string(name)?.into_raw(); let mut raw_context = ptr::null_mut(); let mut raw_resource_ref = ptr::null_mut(); unsafe { let status = sys::napi_async_init(self.0, raw_resource, raw_name, &mut raw_context); - debug_assert!(Status::from(status) == Status::Ok); + check_status(status)?; let status = sys::napi_create_reference(self.0, raw_resource, 1, &mut raw_resource_ref); - debug_assert!(Status::from(status) == Status::Ok); + check_status(status)?; } - AsyncContext { + Ok(AsyncContext { raw_env: self.0, raw_resource: raw_resource_ref, raw_context, - } + }) } - pub fn create_promise(&self) -> (Value, Deferred) { + pub fn create_promise(&self) -> Result<(Value, Deferred)> { let mut raw_promise = ptr::null_mut(); let mut raw_deferred = ptr::null_mut(); unsafe { - sys::napi_create_promise(self.0, &mut raw_deferred, &mut raw_promise); + let status = sys::napi_create_promise(self.0, &mut raw_deferred, &mut raw_promise); + check_status(status)?; } - ( + Ok(( Value::from_raw_value(self, raw_promise, Object), Deferred(raw_deferred), - ) + )) } - pub fn resolve_deferred(&self, deferred: Deferred, value: Value) { + pub fn resolve_deferred(&self, deferred: Deferred, value: Value) -> Result<()> { unsafe { - sys::napi_resolve_deferred(self.0, deferred.0, value.into_raw()); + let status = sys::napi_resolve_deferred(self.0, deferred.0, value.into_raw()); + check_status(status) } } @@ -534,6 +609,16 @@ impl ValueType for Undefined { } } +impl ValueType for Null { + fn from_raw(_env: sys::napi_env, _raw: sys::napi_value) -> Self { + Null + } + + fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool { + get_raw_type(env, raw) == sys::napi_valuetype::napi_null + } +} + impl ValueType for Boolean { fn from_raw(env: sys::napi_env, raw: sys::napi_value) -> Self { let mut value = true; @@ -549,10 +634,10 @@ impl ValueType for Boolean { impl ValueType for Number { fn from_raw(env: sys::napi_env, raw: sys::napi_value) -> Self { - let mut int: i64 = 0; - let status = unsafe { sys::napi_get_value_int64(env, raw, &mut int) }; + let mut double: f64 = 0.0; + let status = unsafe { sys::napi_get_value_double(env, raw, &mut double) }; debug_assert!(Status::from(status) == Status::Ok); - Number { int } + Number::Double(double) } fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool { @@ -694,6 +779,15 @@ impl<'env, T: ValueType> Value<'env, T> { value: Object, }) } + + #[inline] + pub fn into_any(self) -> Value<'env, Any> { + Value { + env: self.env, + raw_value: self.raw_value, + value: Any, + } + } } #[inline] @@ -851,7 +945,7 @@ impl<'env> Value<'env, Object> { } pub fn set_index<'a, T>(&mut self, index: usize, value: Value) -> Result<()> { - self.set_property(self.env.create_int64(index as i64), value) + self.set_property(self.env.create_int64(index as i64)?, value) } pub fn get_index(&self, index: u32) -> Result> { @@ -929,7 +1023,8 @@ impl<'env> Value<'env, Function> { ) -> Result> { let raw_this = this .map(|v| v.into_raw()) - .unwrap_or_else(|| self.env.get_undefined().into_raw()); + .or_else(|| self.env.get_undefined().ok().map(|u| u.into_raw())) + .ok_or(Error::new(Status::Unknown))?; let mut raw_args = unsafe { mem::MaybeUninit::<[sys::napi_value; 8]>::uninit().assume_init() }; for (i, arg) in args.into_iter().enumerate() { raw_args[i] = arg.raw_value; @@ -1032,9 +1127,9 @@ impl Property { self } - fn into_raw(mut self, env: &Env) -> sys::napi_property_descriptor { - self.raw_descriptor.name = env.create_string(&self.name).into_raw(); - self.raw_descriptor + fn into_raw(mut self, env: &Env) -> Result { + self.raw_descriptor.name = env.create_string(&self.name)?.into_raw(); + Ok(self.raw_descriptor) } } diff --git a/test_module/src/lib.rs b/test_module/src/lib.rs index 402ead69..42a54c5b 100644 --- a/test_module/src/lib.rs +++ b/test_module/src/lib.rs @@ -28,9 +28,9 @@ fn test_spawn<'a>( use futures::executor::ThreadPool; use futures::StreamExt; - let async_context = env.async_init(None, "test_spawn"); + let async_context = env.async_init(None, "test_spawn")?; let pool = ThreadPool::new().expect("Failed to build pool"); - let (promise, deferred) = env.create_promise(); + let (promise, deferred) = env.create_promise()?; let (tx, rx) = futures::channel::mpsc::unbounded::(); let fut_values = async move { let fut_tx_result = async move { @@ -45,7 +45,9 @@ fn test_spawn<'a>( println!("Collected result lenght {}", results.len()); }; async_context.enter(|env| { - env.resolve_deferred(deferred, env.get_undefined()); + env + .resolve_deferred(deferred, env.get_undefined().unwrap()) + .unwrap(); }); };