Merge pull request #28 from Brooooooklyn/result

Make  API call more safety
This commit is contained in:
LongYinan 2020-04-19 19:07:08 +08:00 committed by GitHub
commit 6b032caca8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 178 additions and 179 deletions

View file

@ -115,12 +115,12 @@ npm test
| [Enum types](https://nodejs.org/api/n-api.html#n_api_enum_types) | 6 | v13.7.0 | ⛔️ | | [Enum types](https://nodejs.org/api/n-api.html#n_api_enum_types) | 6 | v13.7.0 | ⛔️ |
| [napi_create_array](https://nodejs.org/api/n-api.html#n_api_napi_create_array) | 1 | v8.0.0 | ✅ | | [napi_create_array](https://nodejs.org/api/n-api.html#n_api_napi_create_array) | 1 | v8.0.0 | ✅ |
| [napi_create_array_with_length](https://nodejs.org/api/n-api.html#n_api_napi_create_array_with_length) | 1 | v8.0.0 | ✅ | | [napi_create_array_with_length](https://nodejs.org/api/n-api.html#n_api_napi_create_array_with_length) | 1 | v8.0.0 | ✅ |
| [napi_create_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_create_arraybuffer) | 1 | v8.0.0 | ⛔️ | | [napi_create_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_create_arraybuffer) | 1 | v8.0.0 | |
| [napi_create_buffer](https://nodejs.org/api/n-api.html#n_api_napi_create_buffer) | 1 | v8.0.0 | ✅ | | [napi_create_buffer](https://nodejs.org/api/n-api.html#n_api_napi_create_buffer) | 1 | v8.0.0 | ✅ |
| [napi_create_buffer_copy](https://nodejs.org/api/n-api.html#n_api_napi_create_buffer_copy) | 1 | v8.0.0 | ⛔️ | | [napi_create_buffer_copy](https://nodejs.org/api/n-api.html#n_api_napi_create_buffer_copy) | 1 | v8.0.0 | ⛔️ |
| [napi_create_date](https://nodejs.org/api/n-api.html#n_api_napi_create_date) | 5 | v11.11.0 | ⛔️ | | [napi_create_date](https://nodejs.org/api/n-api.html#n_api_napi_create_date) | 5 | v11.11.0 | ⛔️ |
| [napi_create_external](https://nodejs.org/api/n-api.html#n_api_napi_create_external) | 1 | v8.0.0 | ⛔️ | | [napi_create_external](https://nodejs.org/api/n-api.html#n_api_napi_create_external) | 1 | v8.0.0 | ⛔️ |
| [napi_create_external_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_create_external_arraybuffer) | 1 | v8.0.0 | ⛔️ | | [napi_create_external_arraybuffer](https://nodejs.org/api/n-api.html#n_api_napi_create_external_arraybuffer) | 1 | v8.0.0 | |
| [napi_create_external_buffer](https://nodejs.org/api/n-api.html#n_api_napi_create_external_buffer) | 1 | v8.0.0 | ✅ | | [napi_create_external_buffer](https://nodejs.org/api/n-api.html#n_api_napi_create_external_buffer) | 1 | v8.0.0 | ✅ |
| [napi_create_object](https://nodejs.org/api/n-api.html#n_api_napi_create_object) | 1 | v8.0.0 | ✅ | | [napi_create_object](https://nodejs.org/api/n-api.html#n_api_napi_create_object) | 1 | v8.0.0 | ✅ |
| [napi_create_symbol](https://nodejs.org/api/n-api.html#n_api_napi_create_symbol) | 1 | v8.0.0 | ⛔️ | | [napi_create_symbol](https://nodejs.org/api/n-api.html#n_api_napi_create_symbol) | 1 | v8.0.0 | ⛔️ |
@ -142,7 +142,7 @@ npm test
| NAPI | NAPI Version | Minimal Node Version | Status | | NAPI | NAPI Version | Minimal Node Version | Status |
| ---- | ------------ | -------------------- | ------ | | ---- | ------------ | -------------------- | ------ |
|[napi_get_array_length](https://nodejs.org/api/n-api.html#n_api_napi_get_array_length)| 1 | v8.0.0 | ✅ | |[napi_get_array_length](https://nodejs.org/api/n-api.html#n_api_napi_get_array_length)| 1 | v8.0.0 | ✅ |
|[napi_get_arraybuffer_info](https://nodejs.org/api/n-api.html#n_api_napi_get_arraybuffer_info)| 1 | v8.0.0 | ⛔️ | |[napi_get_arraybuffer_info](https://nodejs.org/api/n-api.html#n_api_napi_get_arraybuffer_info)| 1 | v8.0.0 | |
|[napi_get_buffer_info](https://nodejs.org/api/n-api.html#n_api_napi_get_buffer_info)| 1 | v8.0.0 | ✅ | |[napi_get_buffer_info](https://nodejs.org/api/n-api.html#n_api_napi_get_buffer_info)| 1 | v8.0.0 | ✅ |
|[napi_get_prototype](https://nodejs.org/api/n-api.html#n_api_napi_get_prototype)| 1 | v8.0.0 | ⛔️ | |[napi_get_prototype](https://nodejs.org/api/n-api.html#n_api_napi_get_prototype)| 1 | v8.0.0 | ⛔️ |
|[napi_get_typedarray_info](https://nodejs.org/api/n-api.html#n_api_napi_get_typedarray_info)| 1 | v8.0.0 | ⛔️ | |[napi_get_typedarray_info](https://nodejs.org/api/n-api.html#n_api_napi_get_typedarray_info)| 1 | v8.0.0 | ⛔️ |

View file

@ -12,10 +12,9 @@ keywords = ["NodeJS", "FFI"]
futures = { version = "0.3", features = ["default", "thread-pool"] } futures = { version = "0.3", features = ["default", "thread-pool"] }
serde = { version = "1", optional = true } serde = { version = "1", optional = true }
serde_json = { version = "1", optional = true } serde_json = { version = "1", optional = true }
rayon = { version = "1", optional = true }
[features] [features]
serde-json = ["serde", "serde_json", "rayon"] serde-json = ["serde", "serde_json"]
default = ["serde-json"] default = ["serde-json"]

View file

@ -1,10 +1,7 @@
#[cfg(feature = "serde-json")] extern crate futures;
extern crate rayon;
#[cfg(feature = "serde-json")]
extern crate serde_json;
pub extern crate futures;
use std::any::TypeId; use std::any::TypeId;
use std::convert::TryInto;
use std::ffi::CString; use std::ffi::CString;
use std::marker::PhantomData; use std::marker::PhantomData;
use std::mem; use std::mem;
@ -14,9 +11,6 @@ use std::ptr;
use std::slice; use std::slice;
use std::string::String as RustString; use std::string::String as RustString;
#[cfg(feature = "serde-json")]
use serde_json::value::Value as SerdeValue;
mod executor; mod executor;
pub mod sys; pub mod sys;
@ -142,7 +136,7 @@ macro_rules! register_module {
raw_exports: sys::napi_value, raw_exports: sys::napi_value,
) -> sys::napi_value { ) -> sys::napi_value {
let env = Env::from_raw(raw_env); let env = Env::from_raw(raw_env);
let mut exports: Value<Object> = Value::from_raw(&env, raw_exports); let mut exports: Value<Object> = Value::from_raw(&env, raw_exports).unwrap();
let result = $init(&env, &mut exports); let result = $init(&env, &mut exports);
@ -195,10 +189,10 @@ macro_rules! callback {
} }
let env = Env::from_raw(raw_env); let env = Env::from_raw(raw_env);
let this = Value::from_raw(&env, raw_this); let this = Value::from_raw(&env, raw_this).unwrap();
let mut args = unsafe { mem::MaybeUninit::<[Value<Any>; 8]>::uninit().assume_init() }; let mut args = unsafe { mem::MaybeUninit::<[Value<Any>; 8]>::uninit().assume_init() };
for (i, raw_arg) in raw_args.iter().enumerate() { for (i, raw_arg) in raw_args.iter().enumerate() {
args[i] = Value::from_raw(&env, *raw_arg) args[i] = Value::from_raw(&env, *raw_arg).unwrap()
} }
let callback = $callback_expr; let callback = $callback_expr;
@ -257,11 +251,11 @@ impl Env {
Ok(Value::from_raw_value(self, raw_value, Null)) Ok(Value::from_raw_value(self, raw_value, Null))
} }
pub fn get_boolean(&self, value: bool) -> Value<Boolean> { pub fn get_boolean(&self, value: bool) -> Result<Value<Boolean>> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
let status = unsafe { sys::napi_get_boolean(self.0, value, &mut raw_value) }; let status = unsafe { sys::napi_get_boolean(self.0, value, &mut raw_value) };
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
Value::from_raw_value(self, raw_value, Boolean { value }) Ok(Value::from_raw_value(self, raw_value, Boolean { value }))
} }
pub fn create_int64<'a>(&'a self, int: i64) -> Result<Value<'a, Number>> { pub fn create_int64<'a>(&'a self, int: i64) -> Result<Value<'a, Number>> {
@ -298,88 +292,46 @@ impl Env {
Ok(Value::from_raw_value(self, raw_value, String)) Ok(Value::from_raw_value(self, raw_value, String))
} }
pub fn create_string_utf16<'a, 'b>(&'a self, chars: &[u16]) -> Value<'a, String> { pub fn create_string_utf16<'a, 'b>(&'a self, chars: &[u16]) -> Result<Value<'a, String>> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
let status = unsafe { let status = unsafe {
sys::napi_create_string_utf16(self.0, chars.as_ptr(), chars.len() as u64, &mut raw_value) sys::napi_create_string_utf16(self.0, chars.as_ptr(), chars.len() as u64, &mut raw_value)
}; };
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
Value::from_raw_value(self, raw_value, String) Ok(Value::from_raw_value(self, raw_value, String))
} }
pub fn create_object<'a>(&'a self) -> Value<'a, Object> { pub fn create_object<'a>(&'a self) -> Result<Value<'a, Object>> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
let status = unsafe { sys::napi_create_object(self.0, &mut raw_value) }; let status = unsafe { sys::napi_create_object(self.0, &mut raw_value) };
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
Value::from_raw_value(self, raw_value, Object) Ok(Value::from_raw_value(self, raw_value, Object))
} }
#[cfg(feature = "serde-json")] pub fn create_array_with_length(&self, length: usize) -> Result<Value<Object>> {
pub fn from_serde_value<'a>(&'a self, serde_value: &'a SerdeValue) -> Result<Value<'a, Any>> {
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<Object> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
let status = let status =
unsafe { sys::napi_create_array_with_length(self.0, length as u64, &mut raw_value) }; unsafe { sys::napi_create_array_with_length(self.0, length as u64, &mut raw_value) };
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
Value::from_raw_value(self, raw_value, Object) Ok(Value::from_raw_value(self, raw_value, Object))
} }
pub fn create_buffer(&self, length: u64) -> Value<Buffer> { pub fn create_buffer(&self, length: u64) -> Result<Value<Buffer>> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
let mut data = ptr::null_mut(); let mut data = ptr::null_mut();
let status = unsafe { sys::napi_create_buffer(self.0, length, &mut data, &mut raw_value) }; let status = unsafe { sys::napi_create_buffer(self.0, length, &mut data, &mut raw_value) };
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
Value::from_raw_value( Ok(Value::from_raw_value(
self, self,
raw_value, raw_value,
Buffer { Buffer {
data: data as *const u8, data: data as *const u8,
size: length, size: length,
}, },
) ))
} }
pub fn create_buffer_with_data(&self, data: Vec<u8>) -> Value<Buffer> { pub fn create_buffer_with_data(&self, data: Vec<u8>) -> Result<Value<Buffer>> {
let length = data.len() as u64; let length = data.len() as u64;
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
let data_ptr = data.as_ptr(); let data_ptr = data.as_ptr();
@ -393,27 +345,72 @@ impl Env {
&mut raw_value, &mut raw_value,
) )
}; };
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
let mut changed = 0; let mut changed = 0;
let ajust_external_memory_status = let ajust_external_memory_status =
unsafe { sys::napi_adjust_external_memory(self.0, length as i64, &mut changed) }; unsafe { sys::napi_adjust_external_memory(self.0, length as i64, &mut changed) };
debug_assert!(Status::from(ajust_external_memory_status) == Status::Ok); check_status(ajust_external_memory_status)?;
mem::forget(data); mem::forget(data);
Value::from_raw_value( Ok(Value::from_raw_value(
self, self,
raw_value, raw_value,
Buffer { Buffer {
data: data_ptr, data: data_ptr,
size: length, size: length,
}, },
))
}
pub fn create_arraybuffer(&self, length: u64) -> Result<Value<ArrayBuffer>> {
let mut raw_value = ptr::null_mut();
let mut data = ptr::null_mut();
let status = unsafe { sys::napi_create_arraybuffer(self.0, length, &mut data, &mut raw_value) };
check_status(status)?;
Ok(Value::from_raw_value(
self,
raw_value,
ArrayBuffer {
data: data as *const u8,
size: length,
},
))
}
pub fn create_arraybuffer_with_data(&self, data: Vec<u8>) -> Result<Value<ArrayBuffer>> {
let length = data.len() as u64;
let mut raw_value = ptr::null_mut();
let data_ptr = data.as_ptr();
let status = unsafe {
sys::napi_create_external_arraybuffer(
self.0,
data_ptr as *mut c_void,
length,
Some(drop_buffer),
Box::into_raw(Box::from(length)) as *mut c_void,
&mut raw_value,
) )
};
check_status(status)?;
let mut changed = 0;
let ajust_external_memory_status =
unsafe { sys::napi_adjust_external_memory(self.0, length as i64, &mut changed) };
check_status(ajust_external_memory_status)?;
mem::forget(data);
Ok(Value::from_raw_value(
self,
raw_value,
ArrayBuffer {
data: data_ptr,
size: length,
},
))
} }
pub fn create_function<'a, 'b>( pub fn create_function<'a, 'b>(
&'a self, &'a self,
name: &'b str, name: &'b str,
callback: Callback, callback: Callback,
) -> Value<'a, Function> { ) -> Result<Value<'a, Function>> {
let mut raw_result = ptr::null_mut(); let mut raw_result = ptr::null_mut();
let status = unsafe { let status = unsafe {
sys::napi_create_function( sys::napi_create_function(
@ -426,30 +423,30 @@ 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 create_reference<T>(&self, value: &Value<T>) -> Ref<T> { pub fn create_reference<T>(&self, value: &Value<T>) -> Result<Ref<T>> {
let mut raw_ref = ptr::null_mut(); let mut raw_ref = ptr::null_mut();
unsafe { unsafe {
let status = sys::napi_create_reference(self.0, value.raw_value, 1, &mut raw_ref); let status = sys::napi_create_reference(self.0, value.raw_value, 1, &mut raw_ref);
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
}; };
Ref { Ok(Ref {
raw_env: self.0, raw_env: self.0,
raw_ref, raw_ref,
_marker: PhantomData, _marker: PhantomData,
} })
} }
pub fn get_reference_value<T: ValueType>(&self, reference: &Ref<T>) -> Value<T> { pub fn get_reference_value<T: ValueType>(&self, reference: &Ref<T>) -> Result<Value<T>> {
let mut raw_value = ptr::null_mut(); let mut raw_value = ptr::null_mut();
unsafe { unsafe {
let status = sys::napi_get_reference_value(self.0, reference.raw_ref, &mut raw_value); let status = sys::napi_get_reference_value(self.0, reference.raw_ref, &mut raw_value);
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
}; };
Value::from_raw(self, raw_value) Value::from_raw(self, raw_value)
@ -541,8 +538,8 @@ impl Env {
pub fn async_init(&self, resource: Option<Value<Object>>, name: &str) -> Result<AsyncContext> { pub fn async_init(&self, resource: Option<Value<Object>>, name: &str) -> Result<AsyncContext> {
let raw_resource = resource let raw_resource = resource
.map(|r| r.into_raw()) .map(|r| Ok(r.into_raw()))
.unwrap_or_else(|| self.create_object().into_raw()); .unwrap_or_else(|| self.create_object().map(|o| o.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_context = ptr::null_mut();
@ -591,13 +588,13 @@ impl Env {
} }
pub trait ValueType: Copy { pub trait ValueType: Copy {
fn from_raw(env: sys::napi_env, raw: sys::napi_value) -> Self; fn from_raw(env: sys::napi_env, raw: sys::napi_value) -> Result<Self>;
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool; fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool;
} }
impl ValueType for Any { impl ValueType for Any {
fn from_raw(_env: sys::napi_env, _raw: sys::napi_value) -> Self { fn from_raw(_env: sys::napi_env, _raw: sys::napi_value) -> Result<Self> {
Any Ok(Any)
} }
fn matches_raw_type(_env: sys::napi_env, _raw: sys::napi_value) -> bool { fn matches_raw_type(_env: sys::napi_env, _raw: sys::napi_value) -> bool {
@ -606,8 +603,8 @@ impl ValueType for Any {
} }
impl ValueType for Undefined { impl ValueType for Undefined {
fn from_raw(_env: sys::napi_env, _raw: sys::napi_value) -> Self { fn from_raw(_env: sys::napi_env, _raw: sys::napi_value) -> Result<Self> {
Undefined Ok(Undefined)
} }
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool { fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
@ -616,8 +613,8 @@ impl ValueType for Undefined {
} }
impl ValueType for Null { impl ValueType for Null {
fn from_raw(_env: sys::napi_env, _raw: sys::napi_value) -> Self { fn from_raw(_env: sys::napi_env, _raw: sys::napi_value) -> Result<Self> {
Null Ok(Null)
} }
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool { fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
@ -626,11 +623,11 @@ impl ValueType for Null {
} }
impl ValueType for Boolean { impl ValueType for Boolean {
fn from_raw(env: sys::napi_env, raw: sys::napi_value) -> Self { fn from_raw(env: sys::napi_env, raw: sys::napi_value) -> Result<Self> {
let mut value = true; let mut value = true;
let status = unsafe { sys::napi_get_value_bool(env, raw, &mut value) }; let status = unsafe { sys::napi_get_value_bool(env, raw, &mut value) };
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
Boolean { value } Ok(Boolean { value })
} }
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool { fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
@ -639,11 +636,11 @@ impl ValueType for Boolean {
} }
impl ValueType for Number { impl ValueType for Number {
fn from_raw(env: sys::napi_env, raw: sys::napi_value) -> Self { fn from_raw(env: sys::napi_env, raw: sys::napi_value) -> Result<Self> {
let mut double: f64 = 0.0; let mut double: f64 = 0.0;
let status = unsafe { sys::napi_get_value_double(env, raw, &mut double) }; let status = unsafe { sys::napi_get_value_double(env, raw, &mut double) };
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
Number::Double(double) Ok(Number::Double(double))
} }
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool { fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
@ -652,8 +649,8 @@ impl ValueType for Number {
} }
impl ValueType for String { impl ValueType for String {
fn from_raw(_env: sys::napi_env, _raw: sys::napi_value) -> Self { fn from_raw(_env: sys::napi_env, _raw: sys::napi_value) -> Result<Self> {
String {} Ok(String {})
} }
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool { fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
@ -662,8 +659,8 @@ impl ValueType for String {
} }
impl ValueType for Object { impl ValueType for Object {
fn from_raw(_env: sys::napi_env, _raw: sys::napi_value) -> Self { fn from_raw(_env: sys::napi_env, _raw: sys::napi_value) -> Result<Self> {
Object {} Ok(Object {})
} }
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool { fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
@ -672,15 +669,15 @@ impl ValueType for Object {
} }
impl ValueType for Buffer { impl ValueType for Buffer {
fn from_raw(env: sys::napi_env, raw: sys::napi_value) -> Self { fn from_raw(env: sys::napi_env, raw: sys::napi_value) -> Result<Self> {
let mut data = ptr::null_mut(); let mut data = ptr::null_mut();
let mut size: u64 = 0; let mut size: u64 = 0;
let status = unsafe { sys::napi_get_buffer_info(env, raw, &mut data, &mut size) }; let status = unsafe { sys::napi_get_buffer_info(env, raw, &mut data, &mut size) };
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
Buffer { Ok(Buffer {
data: data as *const u8, data: data as *const u8,
size, size,
} })
} }
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool { fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
@ -694,15 +691,15 @@ impl ValueType for Buffer {
} }
impl ValueType for ArrayBuffer { impl ValueType for ArrayBuffer {
fn from_raw(env: sys::napi_env, raw: sys::napi_value) -> Self { fn from_raw(env: sys::napi_env, raw: sys::napi_value) -> Result<Self> {
let mut data = ptr::null_mut(); let mut data = ptr::null_mut();
let mut size: u64 = 0; let mut size: u64 = 0;
let status = unsafe { sys::napi_get_arraybuffer_info(env, raw, &mut data, &mut size) }; let status = unsafe { sys::napi_get_arraybuffer_info(env, raw, &mut data, &mut size) };
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
ArrayBuffer { Ok(ArrayBuffer {
data: data as *const u8, data: data as *const u8,
size, size,
} })
} }
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool { fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
@ -717,18 +714,18 @@ impl ValueType for ArrayBuffer {
impl<'env> Value<'env, Buffer> { impl<'env> Value<'env, Buffer> {
#[inline] #[inline]
pub fn from_value(env: &'env Env, value: &Value<'env, Any>) -> Value<'env, Buffer> { pub fn from_value(env: &'env Env, value: &Value<'env, Any>) -> Result<Value<'env, Buffer>> {
Value { Ok(Value {
env, env,
raw_value: value.raw_value, raw_value: value.raw_value,
value: Buffer::from_raw(env.0, value.into_raw()), value: Buffer::from_raw(env.0, value.into_raw())?,
} })
} }
} }
impl ValueType for Function { impl ValueType for Function {
fn from_raw(_env: sys::napi_env, _raw: sys::napi_value) -> Self { fn from_raw(_env: sys::napi_env, _raw: sys::napi_value) -> Result<Self> {
Function {} Ok(Function {})
} }
fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool { fn matches_raw_type(env: sys::napi_env, raw: sys::napi_value) -> bool {
@ -745,28 +742,18 @@ impl<'env, T: ValueType> Value<'env, T> {
} }
} }
pub fn from_raw(env: &'env Env, raw_value: sys::napi_value) -> Self { pub fn from_raw(env: &'env Env, raw_value: sys::napi_value) -> Result<Self> {
Self { Ok(Self {
env, env,
raw_value, raw_value,
value: T::from_raw(env.0, raw_value), value: T::from_raw(env.0, raw_value)?,
} })
} }
pub fn into_raw(self) -> sys::napi_value { pub fn into_raw(self) -> sys::napi_value {
self.raw_value self.raw_value
} }
pub fn try_into<S: ValueType>(self) -> Result<Value<'env, S>> {
if S::matches_raw_type(self.env.0, self.raw_value) {
Ok(Value::from_raw(self.env, self.raw_value))
} else {
Err(Error {
status: Status::GenericFailure,
})
}
}
pub fn coerce_to_number(self) -> Result<Value<'env, Number>> { pub fn coerce_to_number(self) -> Result<Value<'env, Number>> {
let mut new_raw_value = ptr::null_mut(); let mut new_raw_value = ptr::null_mut();
let status = let status =
@ -775,7 +762,7 @@ impl<'env, T: ValueType> Value<'env, T> {
Ok(Value { Ok(Value {
env: self.env, env: self.env,
raw_value: self.raw_value, raw_value: self.raw_value,
value: Number::from_raw(self.env.0, self.raw_value), value: Number::from_raw(self.env.0, self.raw_value)?,
}) })
} }
@ -829,7 +816,7 @@ fn get_raw_type(env: sys::napi_env, raw_value: sys::napi_value) -> sys::napi_val
} }
impl<'env> Value<'env, String> { impl<'env> Value<'env, String> {
pub fn len(&self) -> usize { pub fn len(&self) -> Result<usize> {
let mut raw_length = ptr::null_mut(); let mut raw_length = ptr::null_mut();
unsafe { unsafe {
let status = sys::napi_get_named_property( let status = sys::napi_get_named_property(
@ -838,19 +825,17 @@ impl<'env> Value<'env, String> {
"length\0".as_ptr() as *const c_char, "length\0".as_ptr() as *const c_char,
&mut raw_length, &mut raw_length,
); );
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
} }
let length: Value<Number> = Value::from_raw(self.env, raw_length); let length: Value<Number> = Value::from_raw(self.env, raw_length)?;
length.into() length.try_into()
} }
} }
impl<'env> Deref for Value<'env, String> { impl<'env> Value<'env, String> {
type Target = [u8]; pub fn get_ref(&self) -> Result<&[u8]> {
fn deref(&self) -> &[u8] {
let mut written_char_count: u64 = 0; let mut written_char_count: u64 = 0;
let len = self.len() + 1; let len = self.len()? + 1;
let mut result = Vec::with_capacity(len); let mut result = Vec::with_capacity(len);
unsafe { unsafe {
let status = sys::napi_get_value_string_utf8( let status = sys::napi_get_value_string_utf8(
@ -861,18 +846,19 @@ impl<'env> Deref for Value<'env, String> {
&mut written_char_count, &mut written_char_count,
); );
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
let ptr = result.as_ptr(); let ptr = result.as_ptr();
mem::forget(result); mem::forget(result);
slice::from_raw_parts(ptr as *const u8, written_char_count as usize) Ok(slice::from_raw_parts(
ptr as *const u8,
written_char_count as usize,
))
} }
} }
}
impl<'env> DerefMut for Value<'env, String> { pub fn get_ref_mut(&mut self) -> Result<&mut [u8]> {
fn deref_mut(&mut self) -> &mut [u8] {
let mut written_char_count: u64 = 0; let mut written_char_count: u64 = 0;
let len = self.len() + 1; let len = self.len()? + 1;
let mut result = Vec::with_capacity(len); let mut result = Vec::with_capacity(len);
unsafe { unsafe {
let status = sys::napi_get_value_string_utf8( let status = sys::napi_get_value_string_utf8(
@ -883,17 +869,22 @@ impl<'env> DerefMut for Value<'env, String> {
&mut written_char_count, &mut written_char_count,
); );
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
let ptr = result.as_ptr(); let ptr = result.as_ptr();
mem::forget(result); mem::forget(result);
slice::from_raw_parts_mut(ptr as *mut _, written_char_count as usize) Ok(slice::from_raw_parts_mut(
ptr as *mut _,
written_char_count as usize,
))
} }
} }
} }
impl<'env> Into<Vec<u16>> for Value<'env, String> { impl<'env> TryInto<Vec<u16>> for Value<'env, String> {
fn into(self) -> Vec<u16> { type Error = Error;
let mut result = Vec::with_capacity(self.len() + 1); // Leave room for trailing null byte
fn try_into(self) -> Result<Vec<u16>> {
let mut result = Vec::with_capacity(self.len()? + 1); // Leave room for trailing null byte
unsafe { unsafe {
let mut written_char_count = 0; let mut written_char_count = 0;
@ -904,38 +895,44 @@ impl<'env> Into<Vec<u16>> for Value<'env, String> {
result.capacity() as u64, result.capacity() as u64,
&mut written_char_count, &mut written_char_count,
); );
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
result.set_len(written_char_count as usize); result.set_len(written_char_count as usize);
} }
result Ok(result)
} }
} }
impl<'env> Into<usize> for Value<'env, Number> { impl<'env> TryInto<usize> for Value<'env, Number> {
fn into(self) -> usize { type Error = Error;
fn try_into(self) -> Result<usize> {
let mut result = 0; let mut result = 0;
let status = unsafe { sys::napi_get_value_int64(self.env.0, self.raw_value, &mut result) }; let status = unsafe { sys::napi_get_value_int64(self.env.0, self.raw_value, &mut result) };
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
result as usize Ok(result as usize)
} }
} }
impl<'env> Into<i64> for Value<'env, Number> { impl<'env> TryInto<i64> for Value<'env, Number> {
fn into(self) -> i64 { type Error = Error;
fn try_into(self) -> Result<i64> {
let mut result = 0; let mut result = 0;
let status = unsafe { sys::napi_get_value_int64(self.env.0, self.raw_value, &mut result) }; let status = unsafe { sys::napi_get_value_int64(self.env.0, self.raw_value, &mut result) };
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
result Ok(result)
} }
} }
impl<'env> Into<f64> for Value<'env, Number> { impl<'env> TryInto<f64> for Value<'env, Number> {
fn into(self) -> f64 { type Error = Error;
fn try_into(self) -> Result<f64> {
let mut result = 0_f64; let mut result = 0_f64;
let status = unsafe { sys::napi_get_value_double(self.env.0, self.raw_value, &mut result) }; let status = unsafe { sys::napi_get_value_double(self.env.0, self.raw_value, &mut result) };
debug_assert!(Status::from(status) == Status::Ok); check_status(status)?;
result Ok(result)
} }
} }
@ -983,7 +980,7 @@ impl<'env> Value<'env, Object> {
) )
}; };
check_status(status)?; check_status(status)?;
Value::<Any>::from_raw(self.env, raw_value).try_into() Value::<T>::from_raw(self.env, raw_value)
} }
pub fn get_property_names<T: ValueType>(&self) -> Result<Value<T>> { pub fn get_property_names<T: ValueType>(&self) -> Result<Value<T>> {
@ -991,7 +988,7 @@ impl<'env> Value<'env, Object> {
let status = let status =
unsafe { sys::napi_get_property_names(self.raw_env(), self.raw_value(), &mut raw_value) }; unsafe { sys::napi_get_property_names(self.raw_env(), self.raw_value(), &mut raw_value) };
check_status(status)?; check_status(status)?;
Value::<Any>::from_raw(self.env, raw_value).try_into() Value::<T>::from_raw(self.env, raw_value)
} }
pub fn set_index<'a, T>(&mut self, index: usize, value: Value<T>) -> Result<()> { pub fn set_index<'a, T>(&mut self, index: usize, value: Value<T>) -> Result<()> {
@ -1003,7 +1000,7 @@ impl<'env> Value<'env, Object> {
let status = let status =
unsafe { sys::napi_get_element(self.raw_env(), self.raw_value(), index, &mut raw_value) }; unsafe { sys::napi_get_element(self.raw_env(), self.raw_value(), index, &mut raw_value) };
check_status(status)?; check_status(status)?;
Value::<Any>::from_raw(self.env, raw_value).try_into() Value::<T>::from_raw(self.env, raw_value)
} }
pub fn is_array(&self) -> Result<bool> { pub fn is_array(&self) -> Result<bool> {
@ -1020,7 +1017,7 @@ impl<'env> Value<'env, Object> {
Ok(is_buffer) Ok(is_buffer)
} }
pub fn to_buffer(&self) -> Value<'env, Buffer> { pub fn to_buffer(&self) -> Result<Value<'env, Buffer>> {
Value::from_raw(self.env, self.raw_value) Value::from_raw(self.env, self.raw_value)
} }
@ -1101,7 +1098,7 @@ impl<'env> Value<'env, Function> {
}; };
check_status(status)?; check_status(status)?;
Ok(Value::from_raw(self.env, return_value)) Value::from_raw(self.env, return_value)
} }
} }

View file

@ -8,6 +8,7 @@ edition = "2018"
crate-type = ["cdylib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
futures = "0.3"
napi-rs = {path = "../napi"} napi-rs = {path = "../napi"}
[build-dependencies] [build-dependencies]

View file

@ -1,7 +1,9 @@
#[macro_use] #[macro_use]
extern crate napi_rs as napi; extern crate napi_rs as napi;
use napi::{futures, Any, Env, Error, Object, Result, Status, Value}; extern crate futures;
use napi::{Any, Env, Error, Object, Result, Status, Value};
register_module!(test_module, init); register_module!(test_module, init);
@ -11,11 +13,11 @@ fn init<'env>(
) -> Result<Option<Value<'env, Object>>> { ) -> Result<Option<Value<'env, Object>>> {
exports.set_named_property( exports.set_named_property(
"testSpawn", "testSpawn",
env.create_function("testSpawn", callback!(test_spawn)), env.create_function("testSpawn", callback!(test_spawn))?,
)?; )?;
exports.set_named_property( exports.set_named_property(
"testThrow", "testThrow",
env.create_function("testThrow", callback!(test_throw)), env.create_function("testThrow", callback!(test_throw))?,
)?; )?;
Ok(None) Ok(None)
} }
@ -53,7 +55,7 @@ fn test_spawn<'a>(
env.create_executor().execute(fut_values); env.create_executor().execute(fut_values);
Ok(Some(promise.try_into().unwrap())) Ok(Some(promise.into_any()))
} }
fn test_throw<'a>( fn test_throw<'a>(