feat(napi): major upgrades for napi@1

1. inline everything
2. change `check_status` and `type_of` to macro
3. provide #[module_exports] macro
4. remove debug and repr[transparent] for ffi struct
This commit is contained in:
LongYinan 2020-11-25 17:42:14 +08:00
parent 9c8a4dee99
commit 1a3621b727
No known key found for this signature in database
GPG key ID: A3FFE134A3E20881
59 changed files with 903 additions and 1014 deletions

View file

@ -1,8 +1,6 @@
use napi::{
CallContext, Env, JsBuffer, JsBufferValue, JsNumber, JsObject, Module, Ref, Result, Task,
};
use napi::{CallContext, Env, JsBuffer, JsBufferValue, JsNumber, JsObject, Ref, Result, Task};
#[repr(transparent)]
struct BufferLength(Ref<JsBufferValue>);
impl Task for BufferLength {
@ -27,7 +25,7 @@ fn bench_async_task(ctx: CallContext) -> Result<JsObject> {
Ok(async_promise.promise_object())
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("benchAsyncTask", bench_async_task)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("benchAsyncTask", bench_async_task)?;
Ok(())
}

View file

@ -1,21 +1,18 @@
#[macro_use]
extern crate napi;
#[macro_use]
extern crate napi_derive;
use napi::{Module, Result};
use napi::{JsObject, Result};
mod async_compute;
mod noop;
mod plus;
register_module!(bench, init);
#[module_exports]
fn init(mut exports: JsObject) -> Result<()> {
exports.create_named_method("noop", noop::noop)?;
fn init(module: &mut Module) -> Result<()> {
module.create_named_method("noop", noop::noop)?;
async_compute::register_js(module)?;
plus::register_js(module)?;
async_compute::register_js(&mut exports)?;
plus::register_js(&mut exports)?;
Ok(())
}

View file

@ -1,6 +1,6 @@
use std::convert::TryInto;
use napi::{CallContext, JsNumber, Module, Result};
use napi::{CallContext, JsNumber, JsObject, Result};
#[js_function(2)]
fn bench_plus(ctx: CallContext) -> Result<JsNumber> {
@ -9,7 +9,7 @@ fn bench_plus(ctx: CallContext) -> Result<JsNumber> {
ctx.env.create_uint32(a + b)
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("plus", bench_plus)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("plus", bench_plus)?;
Ok(())
}

View file

@ -1,4 +1,5 @@
use std::collections::hash_map::DefaultHasher;
use std::env;
use std::fs::{metadata, write};
use std::hash::{Hash, Hasher};
use std::io::Read;
@ -35,14 +36,14 @@ fn download_node_lib(dist_url: &str, version: &str, arch: &str) -> Vec<u8> {
}
pub fn setup() {
let out_dir = std::env::var("OUT_DIR").expect("OUT_DIR is not set");
let out_dir = env::var("OUT_DIR").expect("OUT_DIR is not set");
// Assume nodejs if not specified.
let dist_url =
std::env::var("NPM_CONFIG_DISTURL").unwrap_or_else(|_| "https://nodejs.org/dist".to_string());
env::var("NPM_CONFIG_DISTURL").unwrap_or_else(|_| "https://nodejs.org/dist".to_string());
// Try to get local nodejs version if not specified.
let node_version = std::env::var("NPM_CONFIG_TARGET")
let node_version = env::var("NPM_CONFIG_TARGET")
.or_else(|_| get_node_version())
.expect("Failed to determine nodejs version");
@ -53,7 +54,7 @@ pub fn setup() {
// See https://nodejs.org/docs/latest/api/process.html#process_process_arch for npm env values.
// For windows, we only support `['ia32', 'x64', 'arm64']`
// https://github.com/nodejs/node-gyp/blob/master/lib/install.js#L301
let arch = std::env::var("CARGO_CFG_TARGET_ARCH")
let arch = env::var("CARGO_CFG_TARGET_ARCH")
.map(|arch| match arch.as_str() {
"x86" => "x86",
"x86_64" => "x64",

View file

@ -1,17 +1,14 @@
#[macro_use]
extern crate napi;
#[macro_use]
extern crate napi_derive;
use napi::{CallContext, Error, JsNumber, JsUnknown, Module, Result, Status};
use napi::{CallContext, Error, JsNumber, JsObject, JsUnknown, Result, Status};
use std::convert::TryInto;
register_module!(napi_derive_example, init);
#[module_exports]
fn init(mut exports: JsObject) -> Result<()> {
exports.create_named_method("testThrow", test_throw)?;
fn init(module: &mut Module) -> Result<()> {
module.create_named_method("testThrow", test_throw)?;
module.create_named_method("fibonacci", fibonacci)?;
exports.create_named_method("fibonacci", fibonacci)?;
Ok(())
}

View file

@ -1,7 +1,5 @@
extern crate proc_macro;
use std::mem;
use proc_macro::TokenStream;
use proc_macro2::{Ident, Literal};
use quote::{format_ident, quote};
@ -28,8 +26,9 @@ impl Parse for ArgLength {
struct JsFunction {
args: Vec<FnArg>,
name: mem::MaybeUninit<Ident>,
signature: mem::MaybeUninit<Signature>,
name: Option<Ident>,
signature: Option<Signature>,
signature_raw: Option<Signature>,
block: Vec<Block>,
visibility: Visibility,
}
@ -38,8 +37,9 @@ impl JsFunction {
pub fn new() -> Self {
JsFunction {
args: vec![],
name: mem::MaybeUninit::uninit(),
signature: mem::MaybeUninit::uninit(),
name: None,
signature: None,
signature_raw: None,
visibility: Visibility::Inherited,
block: vec![],
}
@ -53,10 +53,11 @@ impl Fold for JsFunction {
}
fn fold_signature(&mut self, signature: Signature) -> Signature {
self.name = mem::MaybeUninit::new(format_ident!("{}", signature.ident));
self.name = Some(format_ident!("{}", signature.ident));
let mut new_signature = signature.clone();
new_signature.ident = format_ident!("_{}", signature.ident);
self.signature = mem::MaybeUninit::new(new_signature);
new_signature.ident = format_ident!("_generated_{}_generated_", signature.ident);
self.signature = Some(new_signature);
self.signature_raw = Some(signature.clone());
fold_signature(self, signature)
}
@ -78,39 +79,32 @@ pub fn js_function(attr: TokenStream, input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemFn);
let mut js_fn = JsFunction::new();
js_fn.fold_item_fn(input);
let fn_name = unsafe { js_fn.name.assume_init() };
let fn_name = js_fn.name.unwrap();
let fn_block = js_fn.block;
let signature = unsafe { js_fn.signature.assume_init() };
let signature = js_fn.signature.unwrap();
let visibility = js_fn.visibility;
let new_fn_name = signature.ident.clone();
let execute_js_function = get_execute_js_code(new_fn_name, FunctionKind::JsFunction);
let expanded = quote! {
#[inline(always)]
#signature #(#fn_block)*
#[inline(always)]
#visibility extern "C" fn #fn_name(
raw_env: napi::sys::napi_env,
cb_info: napi::sys::napi_callback_info,
) -> napi::sys::napi_value {
use std::io::Write;
use std::mem;
use std::os::raw::c_char;
use std::ptr;
use std::panic::{self, AssertUnwindSafe};
use std::ffi::CString;
use napi::{JsUnknown, Env, Error, Status, NapiValue, CallContext};
use napi::{Env, Error, Status, NapiValue, CallContext};
let mut argc = #arg_len_span as usize;
let mut raw_args: [napi::sys::napi_value; #arg_len_span] = [ptr::null_mut(); #arg_len_span];
let mut raw_this = ptr::null_mut();
let mut has_error = false;
unsafe {
let status = napi::sys::napi_get_cb_info(
raw_env,
cb_info,
&mut argc as *mut usize as *mut _,
&mut argc,
raw_args.as_mut_ptr(),
&mut raw_this,
ptr::null_mut(),
@ -119,7 +113,7 @@ pub fn js_function(attr: TokenStream, input: TokenStream) -> TokenStream {
}
let mut env = unsafe { Env::from_raw(raw_env) };
let ctx = CallContext::new(&mut env, cb_info, raw_this, &raw_args, #arg_len_span, argc as usize);
let ctx = CallContext::new(&mut env, cb_info, raw_this, &raw_args, #arg_len_span, argc);
#execute_js_function
}
};
@ -132,29 +126,24 @@ pub fn contextless_function(_attr: TokenStream, input: TokenStream) -> TokenStre
let input = parse_macro_input!(input as ItemFn);
let mut js_fn = JsFunction::new();
js_fn.fold_item_fn(input);
let fn_name = unsafe { js_fn.name.assume_init() };
let fn_name = js_fn.name.unwrap();
let fn_block = js_fn.block;
let signature = unsafe { js_fn.signature.assume_init() };
let signature = js_fn.signature.unwrap();
let visibility = js_fn.visibility;
let new_fn_name = signature.ident.clone();
let execute_js_function = get_execute_js_code(new_fn_name, FunctionKind::Contextless);
let expanded = quote! {
#[inline]
#signature #(#fn_block)*
#visibility extern "C" fn #fn_name(
raw_env: napi::sys::napi_env,
cb_info: napi::sys::napi_callback_info,
) -> napi::sys::napi_value {
use std::io::Write;
use std::mem;
use std::os::raw::c_char;
use std::ptr;
use std::panic::{self, AssertUnwindSafe};
use std::ffi::CString;
use napi::{Env, NapiValue, Error, Status};
let mut has_error = false;
let ctx = unsafe { Env::from_raw(raw_env) };
#execute_js_function
@ -211,3 +200,63 @@ fn get_execute_js_code(
}
}
}
#[proc_macro_attribute]
pub fn module_exports(_attr: TokenStream, input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as ItemFn);
let mut js_fn = JsFunction::new();
js_fn.fold_item_fn(input);
let fn_block = js_fn.block;
let fn_name = js_fn.name.unwrap();
let signature = js_fn.signature_raw.unwrap();
let args_len = js_fn.args.len();
let call_expr = if args_len == 1 {
quote! { #fn_name(exports) }
} else if args_len == 2 {
quote! { #fn_name(exports, env) }
} else {
panic!("Arguments length of #[module_exports] function must be 1 or 2");
};
let expanded = quote! {
#[inline]
#signature #(#fn_block)*
#[no_mangle]
unsafe extern "C" fn napi_register_module_v1(
raw_env: napi::sys::napi_env,
raw_exports: napi::sys::napi_value,
) -> napi::sys::napi_value {
use std::ffi::CString;
use std::ptr;
use napi::{Env, JsObject, NapiValue};
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
use napi::shutdown_tokio_rt;
let env = Env::from_raw(raw_env);
let exports = JsObject::from_raw_unchecked(raw_env, raw_exports);
let result: napi::Result<()> = #call_expr;
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
let hook_result = napi::check_status!(unsafe {
napi::sys::napi_add_env_cleanup_hook(raw_env, Some(shutdown_tokio_rt), ptr::null_mut())
});
#[cfg(not(all(feature = "tokio_rt", feature = "napi4")))]
let hook_result = Ok(());
match hook_result.and_then(move |_| result) {
Ok(_) => raw_exports,
Err(e) => {
unsafe {
napi::sys::napi_throw_error(
raw_env,
ptr::null(),
CString::from_vec_unchecked(format!("Error initializing module: {}", e).into())
.as_ptr(),
)
};
ptr::null_mut()
}
}
}
};
// Hand the output tokens back to the compiler
TokenStream::from(expanded)
}

View file

@ -2,7 +2,7 @@ use std::mem;
use std::os::raw::{c_char, c_void};
use std::ptr;
use crate::error::check_status;
use crate::check_status;
use crate::js_values::NapiValue;
use crate::{sys, Env, JsObject, Result, Task};
@ -13,7 +13,6 @@ struct AsyncWork<T: Task> {
napi_async_work: sys::napi_async_work,
}
#[derive(Debug)]
pub struct AsyncWorkPromise<'env> {
napi_async_work: sys::napi_async_work,
raw_promise: sys::napi_value,
@ -21,26 +20,27 @@ pub struct AsyncWorkPromise<'env> {
}
impl<'env> AsyncWorkPromise<'env> {
#[inline(always)]
#[inline]
pub fn promise_object(&self) -> JsObject {
unsafe { JsObject::from_raw_unchecked(self.env.0, self.raw_promise) }
}
#[inline]
pub fn cancel(self) -> Result<()> {
check_status(unsafe { sys::napi_cancel_async_work(self.env.0, self.napi_async_work) })
check_status!(unsafe { sys::napi_cancel_async_work(self.env.0, self.napi_async_work) })
}
}
#[inline(always)]
#[inline]
pub fn run<'env, T: Task>(env: &'env Env, task: T) -> Result<AsyncWorkPromise<'env>> {
let mut raw_resource = ptr::null_mut();
check_status(unsafe { sys::napi_create_object(env.0, &mut raw_resource) })?;
check_status!(unsafe { sys::napi_create_object(env.0, &mut raw_resource) })?;
let mut raw_promise = ptr::null_mut();
let mut deferred = ptr::null_mut();
check_status(unsafe { sys::napi_create_promise(env.0, &mut deferred, &mut raw_promise) })?;
check_status!(unsafe { sys::napi_create_promise(env.0, &mut deferred, &mut raw_promise) })?;
let mut raw_name = ptr::null_mut();
let s = "napi_rs_async_work";
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_string_utf8(
env.0,
s.as_ptr() as *const c_char,
@ -54,7 +54,7 @@ pub fn run<'env, T: Task>(env: &'env Env, task: T) -> Result<AsyncWorkPromise<'e
value: Ok(mem::MaybeUninit::zeroed()),
napi_async_work: ptr::null_mut(),
}));
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_async_work(
env.0,
raw_resource,
@ -68,7 +68,7 @@ pub fn run<'env, T: Task>(env: &'env Env, task: T) -> Result<AsyncWorkPromise<'e
&mut result.napi_async_work,
)
})?;
check_status(unsafe { sys::napi_queue_async_work(env.0, result.napi_async_work) })?;
check_status!(unsafe { sys::napi_queue_async_work(env.0, result.napi_async_work) })?;
Ok(AsyncWorkPromise {
napi_async_work: result.napi_async_work,
raw_promise,
@ -104,7 +104,7 @@ unsafe extern "C" fn complete<T: Task>(
let output = v.assume_init();
work.inner_task.resolve(Env::from_raw(env), output)
});
match check_status(status).and_then(move |_| value) {
match check_status!(status).and_then(move |_| value) {
Ok(v) => {
let status = sys::napi_resolve_deferred(env, deferred, v.raw());
debug_assert!(status == sys::Status::napi_ok, "Reject promise failed");

View file

@ -1,6 +1,6 @@
use std::ptr;
use crate::error::check_status;
use crate::check_status;
use crate::{sys, Either, Env, Error, JsUndefined, NapiValue, Result, Status};
/// Function call context
@ -15,6 +15,7 @@ pub struct CallContext<'env> {
}
impl<'env> CallContext<'env> {
#[inline]
pub fn new(
env: &'env mut Env,
callback_info: sys::napi_callback_info,
@ -33,6 +34,7 @@ impl<'env> CallContext<'env> {
}
}
#[inline]
pub fn get<ArgType: NapiValue>(&self, index: usize) -> Result<ArgType> {
if index + 1 > self.arg_len {
Err(Error {
@ -44,6 +46,7 @@ impl<'env> CallContext<'env> {
}
}
#[inline]
pub fn try_get<ArgType: NapiValue>(&self, index: usize) -> Result<Either<ArgType, JsUndefined>> {
if index + 1 > self.arg_len {
Err(Error {
@ -59,21 +62,22 @@ impl<'env> CallContext<'env> {
}
}
#[inline]
pub fn get_new_target<V>(&self) -> Result<V>
where
V: NapiValue,
{
let mut value = ptr::null_mut();
check_status(unsafe { sys::napi_get_new_target(self.env.0, self.callback_info, &mut value) })?;
check_status!(unsafe { sys::napi_get_new_target(self.env.0, self.callback_info, &mut value) })?;
unsafe { V::from_raw(self.env.0, value) }
}
#[inline(always)]
#[inline]
pub fn this<T: NapiValue>(&self) -> Result<T> {
unsafe { T::from_raw(self.env.0, self.raw_this) }
}
#[inline(always)]
#[inline]
pub fn this_unchecked<T: NapiValue>(&self) -> T {
unsafe { T::from_raw_unchecked(self.env.0, self.raw_this) }
}

View file

@ -3,6 +3,5 @@ pub(crate) struct CleanupEnvHookData<T: 'static> {
pub(crate) hook: Box<dyn FnOnce(T) -> ()>,
}
#[repr(transparent)]
#[derive(Debug, Clone, Copy)]
#[derive(Clone, Copy)]
pub struct CleanupEnvHook<T: 'static>(pub(crate) *mut CleanupEnvHookData<T>);

View file

@ -6,7 +6,7 @@ use std::os::raw::{c_char, c_void};
use std::ptr;
use crate::async_work::{self, AsyncWorkPromise};
use crate::error::check_status;
use crate::check_status;
use crate::js_values::*;
use crate::task::Task;
use crate::{sys, Error, NodeVersion, Result, Status};
@ -32,104 +32,116 @@ use tokio::sync::mpsc::error::TrySendError;
pub type Callback = extern "C" fn(sys::napi_env, sys::napi_callback_info) -> sys::napi_value;
#[repr(transparent)]
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy)]
pub struct Env(pub(crate) sys::napi_env);
impl Env {
#[inline]
pub unsafe fn from_raw(env: sys::napi_env) -> Self {
Env(env)
}
#[inline]
pub fn get_undefined(&self) -> Result<JsUndefined> {
let mut raw_value = ptr::null_mut();
check_status(unsafe { sys::napi_get_undefined(self.0, &mut raw_value) })?;
check_status!(unsafe { sys::napi_get_undefined(self.0, &mut raw_value) })?;
Ok(unsafe { JsUndefined::from_raw_unchecked(self.0, raw_value) })
}
#[inline]
pub fn get_null(&self) -> Result<JsNull> {
let mut raw_value = ptr::null_mut();
check_status(unsafe { sys::napi_get_null(self.0, &mut raw_value) })?;
check_status!(unsafe { sys::napi_get_null(self.0, &mut raw_value) })?;
Ok(unsafe { JsNull::from_raw_unchecked(self.0, raw_value) })
}
#[inline]
pub fn get_boolean(&self, value: bool) -> Result<JsBoolean> {
let mut raw_value = ptr::null_mut();
check_status(unsafe { sys::napi_get_boolean(self.0, value, &mut raw_value) })?;
check_status!(unsafe { sys::napi_get_boolean(self.0, value, &mut raw_value) })?;
Ok(unsafe { JsBoolean::from_raw_unchecked(self.0, raw_value) })
}
#[inline]
pub fn create_int32(&self, int: i32) -> Result<JsNumber> {
let mut raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_int32(self.0, int, (&mut raw_value) as *mut sys::napi_value)
})?;
Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
}
#[inline]
pub fn create_int64(&self, int: i64) -> Result<JsNumber> {
let mut raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_int64(self.0, int, (&mut raw_value) as *mut sys::napi_value)
})?;
Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
}
#[inline]
pub fn create_uint32(&self, number: u32) -> Result<JsNumber> {
let mut raw_value = ptr::null_mut();
check_status(unsafe { sys::napi_create_uint32(self.0, number, &mut raw_value) })?;
check_status!(unsafe { sys::napi_create_uint32(self.0, number, &mut raw_value) })?;
Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
}
#[inline]
pub fn create_double(&self, double: f64) -> Result<JsNumber> {
let mut raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_double(self.0, double, (&mut raw_value) as *mut sys::napi_value)
})?;
Ok(unsafe { JsNumber::from_raw_unchecked(self.0, raw_value) })
}
#[cfg(feature = "napi6")]
/// [n_api_napi_create_bigint_int64](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_int64)
#[cfg(feature = "napi6")]
#[inline]
pub fn create_bigint_from_i64(&self, value: i64) -> Result<JsBigint> {
let mut raw_value = ptr::null_mut();
check_status(unsafe { sys::napi_create_bigint_int64(self.0, value, &mut raw_value) })?;
check_status!(unsafe { sys::napi_create_bigint_int64(self.0, value, &mut raw_value) })?;
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
}
#[cfg(feature = "napi6")]
#[inline]
pub fn create_bigint_from_u64(&self, value: u64) -> Result<JsBigint> {
let mut raw_value = ptr::null_mut();
check_status(unsafe { sys::napi_create_bigint_uint64(self.0, value, &mut raw_value) })?;
check_status!(unsafe { sys::napi_create_bigint_uint64(self.0, value, &mut raw_value) })?;
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
}
#[cfg(feature = "napi6")]
#[inline]
pub fn create_bigint_from_i128(&self, value: i128) -> Result<JsBigint> {
let mut raw_value = ptr::null_mut();
let sign_bit = if value > 0 { 0 } else { 1 };
let words = &value as *const i128 as *const u64;
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_bigint_words(self.0, sign_bit, 2, words, &mut raw_value)
})?;
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
}
#[cfg(feature = "napi6")]
#[inline]
pub fn create_bigint_from_u128(&self, value: u128) -> Result<JsBigint> {
let mut raw_value = ptr::null_mut();
let words = &value as *const u128 as *const u64;
check_status(unsafe { sys::napi_create_bigint_words(self.0, 0, 2, words, &mut raw_value) })?;
check_status!(unsafe { sys::napi_create_bigint_words(self.0, 0, 2, words, &mut raw_value) })?;
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, 1))
}
#[cfg(feature = "napi6")]
/// [n_api_napi_create_bigint_words](https://nodejs.org/api/n-api.html#n_api_napi_create_bigint_words)
/// The resulting BigInt will be negative when sign_bit is true.
#[cfg(feature = "napi6")]
#[inline]
pub fn create_bigint_from_words(&self, sign_bit: bool, words: Vec<u64>) -> Result<JsBigint> {
let mut raw_value = ptr::null_mut();
let len = words.len();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_bigint_words(
self.0,
match sign_bit {
@ -144,41 +156,48 @@ impl Env {
Ok(JsBigint::from_raw_unchecked(self.0, raw_value, len as _))
}
#[inline]
pub fn create_string(&self, s: &str) -> Result<JsString> {
self.create_string_from_chars(s.as_ptr() as *const c_char, s.len())
}
#[inline]
pub fn create_string_from_std(&self, s: String) -> Result<JsString> {
self.create_string_from_chars(s.as_ptr() as *const c_char, s.len())
}
#[inline]
pub fn create_string_from_vec_u8(&self, bytes: Vec<u8>) -> Result<JsString> {
self.create_string_from_chars(bytes.as_ptr() as *const c_char, bytes.len())
}
#[inline]
pub fn create_string_from_vec_i8(&self, bytes: Vec<i8>) -> Result<JsString> {
self.create_string_from_chars(bytes.as_ptr() as *const c_char, bytes.len())
}
#[inline]
fn create_string_from_chars(&self, data_ptr: *const c_char, len: usize) -> Result<JsString> {
let mut raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_string_utf8(self.0, data_ptr, len as _, &mut raw_value)
})?;
Ok(unsafe { JsString::from_raw_unchecked(self.0, raw_value) })
}
#[inline]
pub fn create_string_utf16(&self, chars: &[u16]) -> Result<JsString> {
let mut raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_string_utf16(self.0, chars.as_ptr(), chars.len() as _, &mut raw_value)
})?;
Ok(unsafe { JsString::from_raw_unchecked(self.0, raw_value) })
}
#[inline]
pub fn create_string_latin1(&self, chars: &[u8]) -> Result<JsString> {
let mut raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_string_latin1(
self.0,
chars.as_ptr() as *const _,
@ -189,15 +208,17 @@ impl Env {
Ok(unsafe { JsString::from_raw_unchecked(self.0, raw_value) })
}
#[inline]
pub fn create_symbol_from_js_string(&self, description: JsString) -> Result<JsSymbol> {
let mut result = ptr::null_mut();
check_status(unsafe { sys::napi_create_symbol(self.0, description.0.value, &mut result) })?;
check_status!(unsafe { sys::napi_create_symbol(self.0, description.0.value, &mut result) })?;
Ok(unsafe { JsSymbol::from_raw_unchecked(self.0, result) })
}
#[inline]
pub fn create_symbol(&self, description: Option<&str>) -> Result<JsSymbol> {
let mut result = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_symbol(
self.0,
description
@ -210,31 +231,35 @@ impl Env {
Ok(unsafe { JsSymbol::from_raw_unchecked(self.0, result) })
}
#[inline]
pub fn create_object(&self) -> Result<JsObject> {
let mut raw_value = ptr::null_mut();
check_status(unsafe { sys::napi_create_object(self.0, &mut raw_value) })?;
check_status!(unsafe { sys::napi_create_object(self.0, &mut raw_value) })?;
Ok(unsafe { JsObject::from_raw_unchecked(self.0, raw_value) })
}
#[inline]
pub fn create_array(&self) -> Result<JsObject> {
let mut raw_value = ptr::null_mut();
check_status(unsafe { sys::napi_create_array(self.0, &mut raw_value) })?;
check_status!(unsafe { sys::napi_create_array(self.0, &mut raw_value) })?;
Ok(unsafe { JsObject::from_raw_unchecked(self.0, raw_value) })
}
#[inline]
pub fn create_array_with_length(&self, length: usize) -> Result<JsObject> {
let mut raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_array_with_length(self.0, length as _, &mut raw_value)
})?;
Ok(unsafe { JsObject::from_raw_unchecked(self.0, raw_value) })
}
#[inline]
pub fn create_buffer(&self, length: usize) -> Result<JsBufferValue> {
let mut raw_value = ptr::null_mut();
let mut data: Vec<u8> = Vec::with_capacity(length);
let mut data_ptr = data.as_mut_ptr() as *mut c_void;
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_buffer(self.0, length as _, &mut data_ptr, &mut raw_value)
})?;
@ -248,11 +273,12 @@ impl Env {
))
}
#[inline]
pub fn create_buffer_with_data(&self, mut data: Vec<u8>) -> Result<JsBufferValue> {
let mut length = data.len();
let mut raw_value = ptr::null_mut();
let data_ptr = data.as_mut_ptr();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_external_buffer(
self.0,
length as _,
@ -263,7 +289,9 @@ impl Env {
)
})?;
let mut changed = 0;
check_status(unsafe { sys::napi_adjust_external_memory(self.0, length as i64, &mut changed) })?;
check_status!(unsafe {
sys::napi_adjust_external_memory(self.0, length as i64, &mut changed)
})?;
Ok(JsBufferValue::new(
JsBuffer(Value {
env: self.0,
@ -274,6 +302,7 @@ impl Env {
))
}
#[inline]
pub fn create_buffer_copy<D>(&self, data_to_copy: D) -> Result<JsBufferValue>
where
D: AsRef<[u8]>,
@ -282,7 +311,7 @@ impl Env {
let data_ptr = data_to_copy.as_ref().as_ptr();
let mut copy_data = ptr::null_mut();
let mut raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_buffer_copy(
self.0,
length as _,
@ -301,11 +330,12 @@ impl Env {
))
}
#[inline]
pub fn create_arraybuffer(&self, length: usize) -> Result<JsArrayBufferValue> {
let mut raw_value = ptr::null_mut();
let mut data: Vec<u8> = Vec::with_capacity(length as usize);
let mut data_ptr = data.as_mut_ptr() as *mut c_void;
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_arraybuffer(self.0, length as _, &mut data_ptr, &mut raw_value)
})?;
@ -315,11 +345,12 @@ impl Env {
))
}
#[inline]
pub fn create_arraybuffer_with_data(&self, data: Vec<u8>) -> Result<JsArrayBufferValue> {
let mut length = data.len();
let mut raw_value = ptr::null_mut();
let data_ptr = data.as_ptr();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_external_arraybuffer(
self.0,
data_ptr as *mut c_void,
@ -330,7 +361,9 @@ impl Env {
)
})?;
let mut changed = 0;
check_status(unsafe { sys::napi_adjust_external_memory(self.0, length as i64, &mut changed) })?;
check_status!(unsafe {
sys::napi_adjust_external_memory(self.0, length as i64, &mut changed)
})?;
Ok(JsArrayBufferValue::new(
JsArrayBuffer(Value {
@ -342,11 +375,12 @@ impl Env {
))
}
#[inline]
pub fn create_function(&self, name: &str, callback: Callback) -> Result<JsFunction> {
let mut raw_result = ptr::null_mut();
let len = name.len();
let name = CString::new(name)?;
let len = name.as_bytes().len();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_function(
self.0,
name.as_ptr(),
@ -360,16 +394,21 @@ impl Env {
Ok(unsafe { JsFunction::from_raw_unchecked(self.0, raw_result) })
}
#[inline]
pub fn throw(&self, error: Error) -> Result<()> {
let err_value = self.create_error(error)?.0.value;
check_status(unsafe { sys::napi_throw(self.0, err_value) })?;
check_status!(unsafe { sys::napi_throw(self.0, err_value) })?;
Ok(())
}
#[inline]
pub fn throw_error(&self, msg: &str) -> Result<()> {
check_status(unsafe { sys::napi_throw_error(self.0, ptr::null(), CString::new(msg)?.as_ptr()) })
check_status!(unsafe {
sys::napi_throw_error(self.0, ptr::null(), CString::new(msg)?.as_ptr())
})
}
#[inline]
pub fn define_class(
&self,
name: &str,
@ -382,7 +421,7 @@ impl Env {
.map(|prop| prop.raw())
.collect::<Vec<sys::napi_property_descriptor>>();
check_status(unsafe {
check_status!(unsafe {
sys::napi_define_class(
self.0,
name.as_ptr() as *const c_char,
@ -398,8 +437,9 @@ impl Env {
Ok(unsafe { JsFunction::from_raw_unchecked(self.0, raw_result) })
}
#[inline]
pub fn wrap<T: 'static>(&self, js_object: &mut JsObject, native_object: T) -> Result<()> {
check_status(unsafe {
check_status!(unsafe {
sys::napi_wrap(
self.0,
js_object.0.value,
@ -411,10 +451,11 @@ impl Env {
})
}
#[inline]
pub fn unwrap<T: 'static>(&self, js_object: &JsObject) -> Result<&mut T> {
unsafe {
let mut unknown_tagged_object: *mut c_void = ptr::null_mut();
check_status(sys::napi_unwrap(
check_status!(sys::napi_unwrap(
self.0,
js_object.0.value,
&mut unknown_tagged_object,
@ -436,10 +477,11 @@ impl Env {
}
}
#[inline]
pub fn drop_wrapped<T: 'static>(&self, js_object: JsObject) -> Result<()> {
unsafe {
let mut unknown_tagged_object: *mut c_void = ptr::null_mut();
check_status(sys::napi_unwrap(
check_status!(sys::napi_unwrap(
self.0,
js_object.0.value,
&mut unknown_tagged_object,
@ -460,9 +502,10 @@ impl Env {
}
}
#[inline]
pub fn create_external<T: 'static>(&self, native_object: T) -> Result<JsExternal> {
let mut object_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_external(
self.0,
Box::into_raw(Box::new(TaggedObject::new(native_object))) as *mut c_void,
@ -474,10 +517,11 @@ impl Env {
Ok(unsafe { JsExternal::from_raw_unchecked(self.0, object_value) })
}
#[inline]
pub fn get_value_external<T: 'static>(&self, js_external: &JsExternal) -> Result<&mut T> {
unsafe {
let mut unknown_tagged_object = ptr::null_mut();
check_status(sys::napi_get_value_external(
check_status!(sys::napi_get_value_external(
self.0,
js_external.0.value,
&mut unknown_tagged_object,
@ -499,39 +543,44 @@ impl Env {
}
}
#[inline]
pub fn create_error(&self, e: Error) -> Result<JsObject> {
let reason = e.reason;
let reason_string = self.create_string(reason.as_str())?;
let mut result = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_error(self.0, ptr::null_mut(), reason_string.0.value, &mut result)
})?;
Ok(unsafe { JsObject::from_raw_unchecked(self.0, result) })
}
#[inline]
pub fn spawn<T: 'static + Task>(&self, task: T) -> Result<AsyncWorkPromise> {
async_work::run(self, task)
}
#[inline]
pub fn run_in_scope<T, F>(&self, executor: F) -> Result<T>
where
F: FnOnce() -> Result<T>,
{
let mut handle_scope = ptr::null_mut();
check_status(unsafe { sys::napi_open_handle_scope(self.0, &mut handle_scope) })?;
check_status!(unsafe { sys::napi_open_handle_scope(self.0, &mut handle_scope) })?;
let result = executor();
check_status(unsafe { sys::napi_close_handle_scope(self.0, handle_scope) })?;
check_status!(unsafe { sys::napi_close_handle_scope(self.0, handle_scope) })?;
result
}
#[inline]
pub fn get_global(&self) -> Result<JsGlobal> {
let mut raw_global = ptr::null_mut();
check_status(unsafe { sys::napi_get_global(self.0, &mut raw_global) })?;
check_status!(unsafe { sys::napi_get_global(self.0, &mut raw_global) })?;
Ok(unsafe { JsGlobal::from_raw_unchecked(self.0, raw_global) })
}
#[inline]
pub fn get_napi_version(&self) -> Result<u32> {
let global = self.get_global()?;
let process: JsObject = global.get_named_property("process")?;
@ -545,13 +594,15 @@ impl Env {
}
#[cfg(feature = "napi2")]
#[inline]
pub fn get_uv_event_loop(&self) -> Result<*mut sys::uv_loop_s> {
let mut uv_loop: *mut sys::uv_loop_s = ptr::null_mut();
check_status(unsafe { sys::napi_get_uv_event_loop(self.0, &mut uv_loop) })?;
check_status!(unsafe { sys::napi_get_uv_event_loop(self.0, &mut uv_loop) })?;
Ok(uv_loop)
}
#[cfg(feature = "napi3")]
#[inline]
pub fn add_env_cleanup_hook<T, F>(
&mut self,
cleanup_data: T,
@ -566,7 +617,7 @@ impl Env {
hook: Box::new(cleanup_fn),
};
let hook_ref = Box::leak(Box::new(hook));
check_status(unsafe {
check_status!(unsafe {
sys::napi_add_env_cleanup_hook(
self.0,
Some(cleanup_env::<T>),
@ -577,16 +628,18 @@ impl Env {
}
#[cfg(feature = "napi3")]
#[inline]
pub fn remove_env_cleanup_hook<T>(&mut self, hook: CleanupEnvHook<T>) -> Result<()>
where
T: 'static,
{
check_status(unsafe {
check_status!(unsafe {
sys::napi_remove_env_cleanup_hook(self.0, Some(cleanup_env::<T>), hook.0 as *mut _)
})
}
#[cfg(feature = "napi4")]
#[inline]
pub fn create_threadsafe_function<
T: Send,
V: NapiValue,
@ -601,6 +654,7 @@ impl Env {
}
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
#[inline]
pub fn execute_tokio_future<
T: 'static + Send,
V: 'static + NapiValue,
@ -613,7 +667,9 @@ impl Env {
) -> Result<JsObject> {
let mut raw_promise = ptr::null_mut();
let mut raw_deferred = ptr::null_mut();
check_status(unsafe { sys::napi_create_promise(self.0, &mut raw_deferred, &mut raw_promise) })?;
check_status!(unsafe {
sys::napi_create_promise(self.0, &mut raw_deferred, &mut raw_promise)
})?;
let raw_env = self.0;
let future_promise =
@ -636,9 +692,10 @@ impl Env {
}
#[cfg(feature = "napi5")]
#[inline]
pub fn create_date(&self, time: f64) -> Result<JsDate> {
let mut js_value = ptr::null_mut();
check_status(unsafe { sys::napi_create_date(self.0, time, &mut js_value) })?;
check_status!(unsafe { sys::napi_create_date(self.0, time, &mut js_value) })?;
Ok(unsafe { JsDate::from_raw_unchecked(self.0, js_value) })
}
@ -658,6 +715,7 @@ impl Env {
/// }
/// ```
#[cfg(feature = "serde-json")]
#[inline]
pub fn to_js_value<T>(&self, node: &T) -> Result<JsUnknown>
where
T: Serialize,
@ -683,6 +741,7 @@ impl Env {
/// }
///
#[cfg(feature = "serde-json")]
#[inline]
pub fn from_js_value<T, V>(&self, value: V) -> Result<T>
where
T: DeserializeOwned + ?Sized,
@ -697,20 +756,23 @@ impl Env {
T::deserialize(&mut de)
}
#[inline]
pub fn strict_equals<A: NapiValue, B: NapiValue>(&self, a: A, b: B) -> Result<bool> {
let mut result = false;
check_status(unsafe { sys::napi_strict_equals(self.0, a.raw(), b.raw(), &mut result) })?;
check_status!(unsafe { sys::napi_strict_equals(self.0, a.raw(), b.raw(), &mut result) })?;
Ok(result)
}
#[inline]
pub fn get_node_version(&self) -> Result<NodeVersion> {
let mut result = ptr::null();
check_status(unsafe { sys::napi_get_node_version(self.0, &mut result) })?;
check_status!(unsafe { sys::napi_get_node_version(self.0, &mut result) })?;
let version = unsafe { *result };
version.try_into()
}
/// get raw env ptr
#[inline]
pub fn raw(&self) -> sys::napi_env {
self.0
}

View file

@ -1,5 +1,5 @@
use std::convert::From;
use std::error::Error as StdError;
use std::error;
use std::fmt;
#[cfg(feature = "serde-json")]
use std::fmt::Display;
@ -19,7 +19,7 @@ pub struct Error {
pub reason: String,
}
impl StdError for Error {}
impl error::Error for Error {}
#[cfg(feature = "serde-json")]
impl ser::Error for Error {
@ -42,10 +42,12 @@ impl fmt::Display for Error {
}
impl Error {
#[inline]
pub fn new(status: Status, reason: String) -> Self {
Error { status, reason }
}
#[inline]
pub fn from_status(status: Status) -> Self {
Error {
status,
@ -53,6 +55,7 @@ impl Error {
}
}
#[inline]
pub fn from_reason(reason: String) -> Self {
Error {
status: Status::GenericFailure,
@ -60,6 +63,7 @@ impl Error {
}
}
#[inline]
pub(crate) fn into_raw(self, env: sys::napi_env) -> sys::napi_value {
let mut err = ptr::null_mut();
let s = self.reason;
@ -97,11 +101,14 @@ impl From<std::io::Error> for Error {
}
}
#[inline]
pub fn check_status(code: sys::napi_status) -> Result<()> {
let status = Status::from(code);
match status {
Status::Ok => Ok(()),
_ => Err(Error::new(status, "".to_owned())),
}
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! check_status {
($code:expr) => {{
let c = $code;
match c {
$crate::sys::Status::napi_ok => Ok(()),
_ => Err($crate::Error::new($crate::Status::from(c), "".to_owned())),
}
}};
}

View file

@ -4,40 +4,31 @@ use std::os::raw::c_void;
use std::ptr;
use super::{Value, ValueType};
use crate::error::check_status;
use crate::check_status;
use crate::{sys, JsUnknown, NapiValue, Ref, Result};
#[repr(transparent)]
#[derive(Debug)]
pub struct JsArrayBuffer(pub(crate) Value);
#[derive(Debug)]
pub struct JsArrayBufferValue {
pub(crate) value: JsArrayBuffer,
data: mem::ManuallyDrop<Vec<u8>>,
}
#[repr(transparent)]
#[derive(Debug)]
pub struct JsTypedArray(pub(crate) Value);
#[derive(Debug)]
pub struct JsTypedArrayValue {
pub arraybuffer: JsArrayBuffer,
data: *mut c_void,
_data: *mut c_void,
pub byte_offset: u64,
pub length: u64,
pub typedarray_type: TypedArrayType,
}
#[repr(transparent)]
#[derive(Debug)]
pub struct JsDataView(pub(crate) Value);
#[derive(Debug)]
pub struct JsDataViewValue {
pub arraybuffer: JsArrayBuffer,
data: *mut c_void,
_data: *mut c_void,
pub byte_offset: u64,
pub length: u64,
}
@ -88,23 +79,26 @@ impl From<TypedArrayType> for sys::napi_typedarray_type {
impl JsArrayBuffer {
#[cfg(feature = "napi7")]
#[inline]
pub fn detach(self) -> Result<()> {
check_status(unsafe { sys::napi_detach_arraybuffer(self.0.env, self.0.value) })
check_status!(unsafe { sys::napi_detach_arraybuffer(self.0.env, self.0.value) })
}
#[cfg(feature = "napi7")]
#[inline]
pub fn is_detached(&self) -> Result<bool> {
let mut is_detached = false;
check_status(unsafe {
check_status!(unsafe {
sys::napi_is_detached_arraybuffer(self.0.env, self.0.value, &mut is_detached)
})?;
Ok(is_detached)
}
#[inline]
pub fn into_value(self) -> Result<JsArrayBufferValue> {
let mut data = ptr::null_mut();
let mut len: usize = 0;
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_arraybuffer_info(
self.0.env,
self.0.value,
@ -118,6 +112,7 @@ impl JsArrayBuffer {
})
}
#[inline]
pub fn into_typedarray(
self,
typedarray_type: TypedArrayType,
@ -125,7 +120,7 @@ impl JsArrayBuffer {
byte_offset: u64,
) -> Result<JsTypedArray> {
let mut typedarray_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_typedarray(
self.0.env,
typedarray_type.into(),
@ -142,9 +137,10 @@ impl JsArrayBuffer {
}))
}
#[inline]
pub fn into_dataview(self, length: u64, byte_offset: u64) -> Result<JsDataView> {
let mut dataview_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_dataview(
self.0.env,
length as _,
@ -167,6 +163,7 @@ impl JsArrayBuffer {
}
impl JsArrayBufferValue {
#[inline]
pub fn new(value: JsArrayBuffer, data: Vec<u8>) -> Self {
JsArrayBufferValue {
value,
@ -174,10 +171,12 @@ impl JsArrayBufferValue {
}
}
#[inline]
pub fn into_raw(self) -> JsArrayBuffer {
self.value
}
#[inline]
pub fn into_unknown(self) -> JsUnknown {
unsafe { JsUnknown::from_raw_unchecked(self.value.0.env, self.value.0.value) }
}
@ -202,13 +201,14 @@ impl JsTypedArray {
/// https://nodejs.org/api/n-api.html#n_api_napi_get_typedarray_info
///
/// ***Warning***: Use caution while using this API since the underlying data buffer is managed by the VM.
#[inline]
pub fn into_value(self) -> Result<JsTypedArrayValue> {
let mut typedarray_type = 0;
let mut len = 0u64;
let mut data = ptr::null_mut();
let mut arraybuffer_value = ptr::null_mut();
let mut byte_offset = 0u64;
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_typedarray_info(
self.0.env,
self.0.value,
@ -221,7 +221,7 @@ impl JsTypedArray {
})?;
Ok(JsTypedArrayValue {
data,
_data: data,
length: len,
byte_offset,
typedarray_type: typedarray_type.into(),
@ -231,13 +231,14 @@ impl JsTypedArray {
}
impl JsDataView {
#[inline]
pub fn into_value(self) -> Result<JsDataViewValue> {
let mut length = 0u64;
let mut byte_offset = 0u64;
let mut arraybuffer_value = ptr::null_mut();
let mut data = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_dataview_info(
self.0.env,
self.0.value,
@ -251,7 +252,7 @@ impl JsDataView {
arraybuffer: unsafe { JsArrayBuffer::from_raw_unchecked(self.0.env, arraybuffer_value) },
byte_offset,
length,
data,
_data: data,
})
}
}

View file

@ -2,16 +2,15 @@ use std::convert::TryFrom;
use std::ptr;
use super::*;
use crate::error::check_status;
use crate::{sys, Result};
use crate::{check_status, sys, Result};
#[derive(Debug)]
pub struct JsBigint {
pub(crate) raw: Value,
pub word_count: u64,
}
impl JsBigint {
#[inline]
pub(crate) fn from_raw_unchecked(
env: sys::napi_env,
value: sys::napi_value,
@ -35,7 +34,7 @@ impl JsBigint {
#[inline]
pub fn coerce_to_number(self) -> Result<JsNumber> {
let mut new_raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_coerce_to_number(self.raw.env, self.raw.value, &mut new_raw_value)
})?;
Ok(JsNumber(Value {
@ -48,7 +47,7 @@ impl JsBigint {
#[inline]
pub fn coerce_to_string(self) -> Result<JsString> {
let mut new_raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_coerce_to_string(self.raw.env, self.raw.value, &mut new_raw_value)
})?;
Ok(JsString(Value {
@ -60,7 +59,7 @@ impl JsBigint {
#[inline]
pub fn coerce_to_object(self) -> Result<JsObject> {
let mut new_raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_coerce_to_object(self.raw.env, self.raw.value, &mut new_raw_value)
})?;
Ok(JsObject(Value {
@ -74,49 +73,49 @@ impl JsBigint {
#[cfg(feature = "napi5")]
pub fn is_date(&self) -> Result<bool> {
let mut is_date = true;
check_status(unsafe { sys::napi_is_date(self.raw.env, self.raw.value, &mut is_date) })?;
check_status!(unsafe { sys::napi_is_date(self.raw.env, self.raw.value, &mut is_date) })?;
Ok(is_date)
}
#[inline]
pub fn is_error(&self) -> Result<bool> {
let mut result = false;
check_status(unsafe { sys::napi_is_error(self.raw.env, self.raw.value, &mut result) })?;
check_status!(unsafe { sys::napi_is_error(self.raw.env, self.raw.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.raw.env, self.raw.value, &mut result) })?;
check_status!(unsafe { sys::napi_is_typedarray(self.raw.env, self.raw.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.raw.env, self.raw.value, &mut result) })?;
check_status!(unsafe { sys::napi_is_dataview(self.raw.env, self.raw.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.raw.env, self.raw.value, &mut is_array) })?;
check_status!(unsafe { sys::napi_is_array(self.raw.env, self.raw.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.raw.env, self.raw.value, &mut is_buffer) })?;
check_status!(unsafe { sys::napi_is_buffer(self.raw.env, self.raw.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 {
check_status!(unsafe {
sys::napi_instanceof(self.raw.env, self.raw.value, constructor.raw(), &mut result)
})?;
Ok(result)
@ -130,7 +129,7 @@ impl NapiValue for JsBigint {
unsafe fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
let mut word_count: u64 = 0;
check_status(sys::napi_get_value_bigint_words(
check_status!(sys::napi_get_value_bigint_words(
env,
value,
ptr::null_mut(),
@ -196,7 +195,7 @@ impl JsBigint {
let mut words: Vec<u64> = Vec::with_capacity(self.word_count as usize);
let word_count = &mut self.word_count;
let mut sign_bit = 0;
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_value_bigint_words(
self.raw.env,
self.raw.value,
@ -217,7 +216,7 @@ impl JsBigint {
pub fn get_u64(&self) -> Result<(u64, bool)> {
let mut val: u64 = 0;
let mut loss = false;
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_value_bigint_uint64(self.raw.env, self.raw.value, &mut val, &mut loss)
})?;
@ -228,7 +227,7 @@ impl JsBigint {
pub fn get_i64(&self) -> Result<(i64, bool)> {
let mut val: i64 = 0;
let mut loss: bool = false;
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_value_bigint_int64(self.raw.env, self.raw.value, &mut val, &mut loss)
})?;
Ok((val, loss))

View file

@ -1,17 +1,16 @@
use std::convert::TryFrom;
use super::Value;
use crate::error::check_status;
use crate::check_status;
use crate::{sys, Error, Result};
#[repr(transparent)]
#[derive(Debug)]
pub struct JsBoolean(pub(crate) Value);
impl JsBoolean {
#[inline]
pub fn get_value(&self) -> Result<bool> {
let mut result = false;
check_status(unsafe { sys::napi_get_value_bool(self.0.env, self.0.value, &mut result) })?;
check_status!(unsafe { sys::napi_get_value_bool(self.0.env, self.0.value, &mut result) })?;
Ok(result)
}
}

View file

@ -5,24 +5,22 @@ use std::ptr;
use super::Value;
#[cfg(feature = "serde-json")]
use super::ValueType;
use crate::error::check_status;
use crate::check_status;
use crate::{sys, JsUnknown, NapiValue, Ref, Result};
#[repr(transparent)]
#[derive(Debug)]
pub struct JsBuffer(pub(crate) Value);
#[derive(Debug)]
pub struct JsBufferValue {
pub(crate) value: JsBuffer,
data: mem::ManuallyDrop<Vec<u8>>,
}
impl JsBuffer {
#[inline]
pub fn into_value(self) -> Result<JsBufferValue> {
let mut data = ptr::null_mut();
let mut len: usize = 0;
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_buffer_info(
self.0.env,
self.0.value,
@ -44,10 +42,11 @@ impl JsBuffer {
impl JsBufferValue {
#[cfg(feature = "serde-json")]
#[inline]
pub(crate) fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
let mut data = ptr::null_mut();
let mut len = 0usize;
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_buffer_info(env, value, &mut data, &mut len as *mut usize as *mut _)
})?;
Ok(Self {
@ -60,6 +59,7 @@ impl JsBufferValue {
})
}
#[inline]
pub fn new(value: JsBuffer, data: Vec<u8>) -> Self {
JsBufferValue {
value,
@ -67,10 +67,12 @@ impl JsBufferValue {
}
}
#[inline]
pub fn into_raw(self) -> JsBuffer {
self.value
}
#[inline]
pub fn into_unknown(self) -> JsUnknown {
unsafe { JsUnknown::from_raw_unchecked(self.value.0.env, self.value.0.value) }
}

View file

@ -1,14 +1,13 @@
use super::check_status;
use crate::{sys, Result, Value};
#[repr(transparent)]
#[derive(Debug)]
pub struct JsDate(pub(crate) Value);
impl JsDate {
#[inline]
pub fn value_of(&self) -> Result<f64> {
let mut timestamp: f64 = 0.0;
check_status(unsafe { sys::napi_get_date_value(self.0.env, self.0.value, &mut timestamp) })?;
check_status!(unsafe { sys::napi_get_date_value(self.0.env, self.0.value, &mut timestamp) })?;
Ok(timestamp)
}
}

View file

@ -3,9 +3,9 @@ use std::convert::TryInto;
use serde::de::Visitor;
use serde::de::{DeserializeSeed, EnumAccess, MapAccess, SeqAccess, Unexpected, VariantAccess};
use super::{type_of, NapiValue, Value, ValueType};
#[cfg(feature = "napi6")]
use crate::JsBigint;
use crate::{type_of, NapiValue, Value, ValueType};
use crate::{
Error, JsBoolean, JsBufferValue, JsNumber, JsObject, JsString, JsUnknown, Result, Status,
};
@ -20,7 +20,7 @@ impl<'x, 'de, 'env> serde::de::Deserializer<'x> for &'de mut De<'env> {
where
V: Visitor<'x>,
{
let js_value_type = type_of(self.0.env, self.0.value)?;
let js_value_type = unsafe { type_of!(self.0.env, self.0.value) }?;
match js_value_type {
ValueType::Null | ValueType::Undefined => visitor.visit_unit(),
ValueType::Boolean => {
@ -89,7 +89,7 @@ impl<'x, 'de, 'env> serde::de::Deserializer<'x> for &'de mut De<'env> {
where
V: Visitor<'x>,
{
match type_of(self.0.env, self.0.value)? {
match unsafe { type_of!(self.0.env, self.0.value) }? {
ValueType::Undefined | ValueType::Null => visitor.visit_none(),
_ => visitor.visit_some(self),
}
@ -104,7 +104,7 @@ impl<'x, 'de, 'env> serde::de::Deserializer<'x> for &'de mut De<'env> {
where
V: Visitor<'x>,
{
let js_value_type = type_of(self.0.env, self.0.value)?;
let js_value_type = unsafe { type_of!(self.0.env, self.0.value)? };
match js_value_type {
ValueType::String => visitor.visit_enum(JsEnumAccess::new(
unsafe { JsString::from_raw_unchecked(self.0.env, self.0.value) }

View file

@ -1,7 +1,7 @@
use std::ops::Deref;
use std::ptr;
use super::check_status;
use crate::check_status;
use crate::{sys, Env, NapiValue, Result};
pub struct EscapableHandleScope<T: NapiValue> {
@ -13,9 +13,9 @@ impl<T: NapiValue> EscapableHandleScope<T> {
#[inline]
pub fn open(env: sys::napi_env, value: T) -> Result<Self> {
let mut handle_scope = ptr::null_mut();
check_status(unsafe { sys::napi_open_escapable_handle_scope(env, &mut handle_scope) })?;
check_status!(unsafe { sys::napi_open_escapable_handle_scope(env, &mut handle_scope) })?;
let mut result = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_escape_handle(env, handle_scope, NapiValue::raw(&value), &mut result)
})?;
Ok(Self {
@ -26,7 +26,7 @@ impl<T: NapiValue> EscapableHandleScope<T> {
#[must_use]
pub fn close(self, env: Env) -> Result<()> {
check_status(unsafe { sys::napi_close_escapable_handle_scope(env.0, self.handle_scope) })
check_status!(unsafe { sys::napi_close_escapable_handle_scope(env.0, self.handle_scope) })
}
}

View file

@ -1,11 +1,9 @@
use std::ptr;
use super::Value;
use crate::error::check_status;
use crate::check_status;
use crate::{sys, Env, Error, JsObject, JsUnknown, NapiValue, Result, Status};
#[repr(transparent)]
#[derive(Debug)]
pub struct JsFunction(pub(crate) Value);
/// See [Working with JavaScript Functions](https://nodejs.org/api/n-api.html#n_api_working_with_javascript_functions).
@ -24,6 +22,7 @@ pub struct JsFunction(pub(crate) Value);
/// ```
impl JsFunction {
/// [napi_call_function](https://nodejs.org/api/n-api.html#n_api_napi_call_function)
#[inline]
pub fn call(&self, this: Option<&JsObject>, args: &[JsUnknown]) -> Result<JsUnknown> {
let raw_this = this
.map(|v| unsafe { v.raw() })
@ -42,7 +41,7 @@ impl JsFunction {
.map(|arg| arg.0.value)
.collect::<Vec<sys::napi_value>>();
let mut return_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_call_function(
self.0.env,
raw_this,
@ -58,6 +57,7 @@ impl JsFunction {
/// https://nodejs.org/api/n-api.html#n_api_napi_new_instance
/// This method is used to instantiate a new `JavaScript` value using a given `JsFunction` that represents the constructor for the object.
#[inline]
pub fn new<V>(&self, args: &[V]) -> Result<JsObject>
where
V: NapiValue,
@ -68,7 +68,7 @@ impl JsFunction {
.iter()
.map(|arg| unsafe { arg.raw() })
.collect::<Vec<sys::napi_value>>();
check_status(unsafe {
check_status!(unsafe {
sys::napi_new_instance(
self.0.env,
self.0.value,

View file

@ -3,15 +3,12 @@ use std::convert::TryInto;
use super::*;
use crate::Env;
#[repr(transparent)]
#[derive(Debug)]
pub struct JsGlobal(pub(crate) Value);
#[repr(transparent)]
#[derive(Debug)]
pub struct JsTimeout(pub(crate) Value);
impl JsGlobal {
#[inline]
pub fn set_interval(&self, handler: JsFunction, interval: f64) -> Result<JsTimeout> {
let func: JsFunction = self.get_named_property("setInterval")?;
func
@ -34,6 +31,7 @@ impl JsGlobal {
.and_then(|ret| ret.try_into())
}
#[inline]
pub fn set_timeout(&self, handler: JsFunction, interval: f64) -> Result<JsTimeout> {
let func: JsFunction = self.get_named_property("setTimeout")?;
func
@ -49,6 +47,7 @@ impl JsGlobal {
.and_then(|ret| ret.try_into())
}
#[inline]
pub fn clear_timeout(&self, timer: JsTimeout) -> Result<JsUndefined> {
let func: JsFunction = self.get_named_property("clearTimeout")?;
func

View file

@ -2,8 +2,8 @@ use std::convert::TryFrom;
use std::ffi::CString;
use std::ptr;
use crate::error::check_status;
use crate::{sys, Error, Result, Status};
use crate::check_status;
use crate::{sys, Callback, Error, Result, Status};
#[cfg(feature = "serde-json")]
mod de;
@ -57,36 +57,33 @@ 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 {
#[doc(hidden)]
#[macro_export(local_inner_macros)]
macro_rules! type_of {
($env:expr, $value:expr) => {{
use std::convert::TryFrom;
use $crate::sys;
let mut value_type = 0;
check_status(sys::napi_typeof(env, raw_value, &mut value_type))?;
ValueType::try_from(value_type).or_else(|_| Ok(ValueType::Unknown))
}
let status = sys::napi_typeof($env, $value, &mut value_type);
check_status!(status)
.and_then(|_| ValueType::try_from(value_type).or_else(|_| Ok(ValueType::Unknown)))
}};
}
macro_rules! impl_napi_value_trait {
($js_value:ident, $value_type:ident) => {
impl NapiValue for $js_value {
unsafe fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<$js_value> {
let value_type = type_of(env, value)?;
let value_type = type_of!(env, value)?;
if value_type != $value_type {
Err(Error::new(
Status::InvalidArg,
@ -134,9 +131,9 @@ macro_rules! impl_js_value_methods {
#[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)?;
check_status!(unsafe {
sys::napi_coerce_to_number(self.0.env, self.0.value, &mut new_raw_value)
})?;
Ok(JsNumber(Value {
env: self.0.env,
value: new_raw_value,
@ -147,9 +144,9 @@ macro_rules! impl_js_value_methods {
#[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)?;
check_status!(unsafe {
sys::napi_coerce_to_string(self.0.env, self.0.value, &mut new_raw_value)
})?;
Ok(JsString(Value {
env: self.0.env,
value: new_raw_value,
@ -160,9 +157,9 @@ macro_rules! impl_js_value_methods {
#[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)?;
check_status!(unsafe {
sys::napi_coerce_to_object(self.0.env, self.0.value, &mut new_raw_value)
})?;
Ok(JsObject(Value {
env: self.0.env,
value: new_raw_value,
@ -170,59 +167,60 @@ macro_rules! impl_js_value_methods {
}))
}
#[inline]
#[cfg(feature = "napi5")]
#[inline]
pub fn is_date(&self) -> Result<bool> {
let mut is_date = true;
check_status(unsafe { sys::napi_is_date(self.0.env, self.0.value, &mut is_date) })?;
check_status!(unsafe { sys::napi_is_date(self.0.env, self.0.value, &mut is_date) })?;
Ok(is_date)
}
#[inline]
pub fn is_promise(&self) -> Result<bool> {
let mut is_promise = true;
check_status(unsafe { sys::napi_is_promise(self.0.env, self.0.value, &mut is_promise) })?;
check_status!(unsafe { sys::napi_is_promise(self.0.env, self.0.value, &mut is_promise) })?;
Ok(is_promise)
}
#[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) })?;
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) })?;
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) })?;
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) })?;
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) })?;
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 {
check_status!(unsafe {
sys::napi_instanceof(self.0.env, self.0.value, constructor.raw(), &mut result)
})?;
Ok(result)
@ -234,125 +232,168 @@ macro_rules! impl_js_value_methods {
macro_rules! impl_object_methods {
($js_value:ident) => {
impl $js_value {
#[inline]
pub fn set_property<V>(&mut self, key: JsString, value: V) -> Result<()>
where
V: NapiValue,
{
check_status(unsafe {
check_status!(unsafe {
sys::napi_set_property(self.0.env, self.0.value, key.0.value, value.raw())
})
}
#[inline]
pub fn get_property<K, T>(&self, key: &K) -> Result<T>
where
K: NapiValue,
T: NapiValue,
{
let mut raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_property(self.0.env, self.0.value, key.raw(), &mut raw_value)
})?;
unsafe { T::from_raw(self.0.env, raw_value) }
}
#[inline]
pub fn set_named_property<T>(&mut self, name: &str, value: T) -> Result<()>
where
T: NapiValue,
{
let key = CString::new(name)?;
check_status(unsafe {
check_status!(unsafe {
sys::napi_set_named_property(self.0.env, self.0.value, key.as_ptr(), value.raw())
})
}
#[inline]
pub fn create_named_method(&mut self, name: &str, function: Callback) -> Result<()> {
let mut js_function = ptr::null_mut();
let len = name.len();
let name = CString::new(name.as_bytes())?;
check_status!(unsafe {
sys::napi_create_function(
self.0.env,
name.as_ptr(),
len,
Some(function),
ptr::null_mut(),
&mut js_function,
)
})?;
check_status!(unsafe {
sys::napi_set_named_property(self.0.env, self.0.value, name.as_ptr(), js_function)
})
}
#[inline]
pub fn get_named_property<T>(&self, name: &str) -> Result<T>
where
T: NapiValue,
{
let key = CString::new(name)?;
let mut raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_named_property(self.0.env, self.0.value, key.as_ptr(), &mut raw_value)
})?;
unsafe { T::from_raw(self.0.env, raw_value) }
}
#[inline]
pub fn has_named_property(&self, name: &str) -> Result<bool> {
let mut result = false;
let key = CString::new(name)?;
check_status(unsafe {
check_status!(unsafe {
sys::napi_has_named_property(self.0.env, self.0.value, key.as_ptr(), &mut result)
})?;
Ok(result)
}
#[inline]
pub fn delete_property<S>(&mut self, name: S) -> Result<bool>
where
S: NapiValue,
{
let mut result = false;
check_status(unsafe {
check_status!(unsafe {
sys::napi_delete_property(self.0.env, self.0.value, name.raw(), &mut result)
})?;
Ok(result)
}
#[inline]
pub fn delete_named_property(&mut self, name: &str) -> Result<bool> {
let mut result = false;
let key_str = CString::new(name)?;
let mut js_key = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_string_utf8(self.0.env, key_str.as_ptr(), name.len(), &mut js_key)
})?;
check_status(unsafe {
check_status!(unsafe {
sys::napi_delete_property(self.0.env, self.0.value, js_key, &mut result)
})?;
Ok(result)
}
#[inline]
pub fn has_own_property(&self, key: &str) -> Result<bool> {
let mut result = false;
let string = CString::new(key)?;
let mut js_key = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_string_utf8(self.0.env, string.as_ptr(), key.len(), &mut js_key)
})?;
check_status(unsafe {
check_status!(unsafe {
sys::napi_has_own_property(self.0.env, self.0.value, js_key, &mut result)
})?;
Ok(result)
}
#[inline]
pub fn has_own_property_js<K>(&self, key: K) -> Result<bool>
where
K: NapiValue,
{
let mut result = false;
check_status(unsafe {
check_status!(unsafe {
sys::napi_has_own_property(self.0.env, self.0.value, key.raw(), &mut result)
})?;
Ok(result)
}
#[inline]
pub fn has_property(&self, name: &str) -> Result<bool> {
let string = CString::new(name)?;
let mut js_key = ptr::null_mut();
let mut result = false;
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_string_utf8(self.0.env, string.as_ptr(), name.len() as _, &mut js_key)
})?;
check_status(unsafe {
check_status!(unsafe {
sys::napi_has_property(self.0.env, self.0.value, js_key, &mut result)
})?;
Ok(result)
}
#[inline]
pub fn has_property_js<K>(&self, name: K) -> Result<bool>
where
K: NapiValue,
{
let mut result = false;
check_status(unsafe {
check_status!(unsafe {
sys::napi_has_property(self.0.env, self.0.value, name.raw(), &mut result)
})?;
Ok(result)
}
#[inline]
pub fn get_property_names<T>(&self) -> Result<T>
where
T: NapiValue,
{
let mut raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_property_names(self.0.env, self.0.value, &mut raw_value)
})?;
unsafe { T::from_raw(self.0.env, raw_value) }
@ -361,6 +402,7 @@ macro_rules! impl_object_methods {
/// https://nodejs.org/api/n-api.html#n_api_napi_get_all_property_names
/// return `Array` of property names
#[cfg(feature = "napi6")]
#[inline]
pub fn get_all_property_names(
&self,
mode: KeyCollectionMode,
@ -368,7 +410,7 @@ macro_rules! impl_object_methods {
conversion: KeyConversion,
) -> Result<JsObject> {
let mut properties_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_all_property_names(
self.0.env,
self.0.value,
@ -382,49 +424,60 @@ macro_rules! impl_object_methods {
}
/// This returns the equivalent of `Object.getPrototypeOf` (which is not the same as the function's prototype property).
#[inline]
pub fn get_prototype<T>(&self) -> Result<T>
where
T: NapiValue,
{
let mut result = ptr::null_mut();
check_status(unsafe { sys::napi_get_prototype(self.0.env, self.0.value, &mut result) })?;
check_status!(unsafe { sys::napi_get_prototype(self.0.env, self.0.value, &mut result) })?;
unsafe { T::from_raw(self.0.env, result) }
}
#[inline]
pub fn set_element<T>(&mut self, index: u32, value: T) -> Result<()>
where
T: NapiValue,
{
check_status(unsafe { sys::napi_set_element(self.0.env, self.0.value, index, value.raw()) })
check_status!(unsafe {
sys::napi_set_element(self.0.env, self.0.value, index, value.raw())
})
}
#[inline]
pub fn has_element(&self, index: u32) -> Result<bool> {
let mut result = false;
check_status(unsafe {
check_status!(unsafe {
sys::napi_has_element(self.0.env, self.0.value, index, &mut result)
})?;
Ok(result)
}
#[inline]
pub fn delete_element(&mut self, index: u32) -> Result<bool> {
let mut result = false;
check_status(unsafe {
check_status!(unsafe {
sys::napi_delete_element(self.0.env, self.0.value, index, &mut result)
})?;
Ok(result)
}
#[inline]
pub fn get_element<T>(&self, index: u32) -> Result<T>
where
T: NapiValue,
{
let mut raw_value = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_element(self.0.env, self.0.value, index, &mut raw_value)
})?;
unsafe { T::from_raw(self.0.env, raw_value) }
}
/// This method allows the efficient definition of multiple properties on a given object.
#[inline]
pub fn define_properties(&mut self, properties: &[Property]) -> Result<()> {
check_status(unsafe {
check_status!(unsafe {
sys::napi_define_properties(
self.0.env,
self.0.value,
@ -440,6 +493,7 @@ macro_rules! impl_object_methods {
/// Perform `is_array` check before get the length
/// if `Object` is not array, `ArrayExpected` error returned
#[inline]
pub fn get_array_length(&self) -> Result<u32> {
if self.is_array()? != true {
return Err(Error::new(
@ -454,7 +508,7 @@ macro_rules! impl_object_methods {
#[inline]
pub fn get_array_length_unchecked(&self) -> Result<u32> {
let mut length: u32 = 0;
check_status(unsafe { sys::napi_get_array_length(self.0.env, self.raw(), &mut length) })?;
check_status!(unsafe { sys::napi_get_array_length(self.0.env, self.raw(), &mut length) })?;
Ok(length)
}
}
@ -516,6 +570,7 @@ impl_napi_value_trait!(JsExternal, External);
impl_napi_value_trait!(JsSymbol, Symbol);
impl NapiValue for JsUnknown {
#[inline]
unsafe fn from_raw(env: sys::napi_env, value: sys::napi_value) -> Result<Self> {
Ok(JsUnknown(Value {
env,
@ -524,6 +579,7 @@ impl NapiValue for JsUnknown {
}))
}
#[inline]
unsafe fn from_raw_unchecked(env: sys::napi_env, value: sys::napi_value) -> Self {
JsUnknown(Value {
env,
@ -533,6 +589,7 @@ impl NapiValue for JsUnknown {
}
/// get raw js value ptr
#[inline]
unsafe fn raw(&self) -> sys::napi_value {
self.0.value
}
@ -541,6 +598,6 @@ impl NapiValue for JsUnknown {
impl JsUnknown {
#[inline]
pub fn get_type(&self) -> Result<ValueType> {
type_of(self.0.env, self.0.value)
unsafe { type_of!(self.0.env, self.0.value) }
}
}

View file

@ -1,11 +1,9 @@
use std::convert::TryFrom;
use super::Value;
use crate::error::check_status;
use crate::check_status;
use crate::{sys, Error, Result};
#[repr(transparent)]
#[derive(Debug)]
pub struct JsNumber(pub(crate) Value);
impl TryFrom<JsNumber> for usize {
@ -13,7 +11,7 @@ impl TryFrom<JsNumber> for usize {
fn try_from(value: JsNumber) -> Result<usize> {
let mut result = 0;
check_status(unsafe { sys::napi_get_value_int64(value.0.env, value.0.value, &mut result) })?;
check_status!(unsafe { sys::napi_get_value_int64(value.0.env, value.0.value, &mut result) })?;
Ok(result as usize)
}
}
@ -23,7 +21,7 @@ impl TryFrom<JsNumber> for u32 {
fn try_from(value: JsNumber) -> Result<u32> {
let mut result = 0;
check_status(unsafe { sys::napi_get_value_uint32(value.0.env, value.0.value, &mut result) })?;
check_status!(unsafe { sys::napi_get_value_uint32(value.0.env, value.0.value, &mut result) })?;
Ok(result)
}
}
@ -33,7 +31,7 @@ impl TryFrom<JsNumber> for i32 {
fn try_from(value: JsNumber) -> Result<i32> {
let mut result = 0;
check_status(unsafe { sys::napi_get_value_int32(value.0.env, value.0.value, &mut result) })?;
check_status!(unsafe { sys::napi_get_value_int32(value.0.env, value.0.value, &mut result) })?;
Ok(result)
}
}
@ -43,7 +41,7 @@ impl TryFrom<JsNumber> for i64 {
fn try_from(value: JsNumber) -> Result<i64> {
let mut result = 0;
check_status(unsafe { sys::napi_get_value_int64(value.0.env, value.0.value, &mut result) })?;
check_status!(unsafe { sys::napi_get_value_int64(value.0.env, value.0.value, &mut result) })?;
Ok(result)
}
}
@ -53,7 +51,7 @@ impl TryFrom<JsNumber> for f64 {
fn try_from(value: JsNumber) -> Result<f64> {
let mut result = 0_f64;
check_status(unsafe { sys::napi_get_value_double(value.0.env, value.0.value, &mut result) })?;
check_status!(unsafe { sys::napi_get_value_double(value.0.env, value.0.value, &mut result) })?;
Ok(result)
}
}

View file

@ -6,8 +6,6 @@ use crate::{Error, Result};
#[cfg(feature = "napi6")]
use std::convert::TryFrom;
#[repr(transparent)]
#[derive(Debug)]
pub struct JsObject(pub(crate) Value);
#[cfg(feature = "napi6")]

View file

@ -2,11 +2,11 @@ use std::convert::From;
use std::ffi::CString;
use std::ptr;
use crate::{error::check_status, sys, Callback, Env, NapiValue, Result};
use crate::{check_status, sys, Callback, Env, NapiValue, Result};
#[derive(Debug, Clone, Copy)]
#[derive(Clone, Copy)]
pub struct Property<'env> {
name: &'env str,
pub name: &'env str,
pub(crate) raw_descriptor: sys::napi_property_descriptor,
}
@ -33,10 +33,11 @@ impl From<PropertyAttributes> for sys::napi_property_attributes {
}
impl<'env> Property<'env> {
#[inline]
pub fn new(env: &'env Env, name: &'env str) -> Result<Self> {
let string_value = CString::new(name)?;
let mut result = ptr::null_mut();
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_string_utf8(env.0, string_value.as_ptr(), name.len(), &mut result)
})?;
Ok(Property {
@ -54,31 +55,37 @@ impl<'env> Property<'env> {
})
}
#[inline]
pub fn with_value<T: NapiValue>(mut self, value: T) -> Self {
self.raw_descriptor.value = unsafe { T::raw(&value) };
self
}
#[inline]
pub fn with_method(mut self, callback: Callback) -> Self {
self.raw_descriptor.method = Some(callback);
self
}
#[inline]
pub fn with_getter(mut self, callback: Callback) -> Self {
self.raw_descriptor.getter = Some(callback);
self
}
#[inline]
pub fn with_setter(mut self, callback: Callback) -> Self {
self.raw_descriptor.setter = Some(callback);
self
}
#[inline]
pub fn with_property_attributes(mut self, attributes: PropertyAttributes) -> Self {
self.raw_descriptor.attributes = attributes.into();
self
}
#[inline]
pub(crate) fn raw(&self) -> sys::napi_property_descriptor {
self.raw_descriptor
}

View file

@ -14,23 +14,28 @@ pub struct JsStringLatin1 {
}
impl JsStringLatin1 {
#[inline]
pub fn as_slice(&self) -> &[u8] {
&self.buf
}
#[inline]
pub fn len(&self) -> usize {
self.buf.len()
}
#[inline]
pub fn take(self) -> Vec<u8> {
self.as_slice().to_vec()
}
#[inline]
pub fn into_value(self) -> JsString {
self.inner
}
#[cfg(feature = "latin1")]
#[inline]
pub fn into_latin1_string(self) -> Result<String> {
let mut dst_str = unsafe { String::from_utf8_unchecked(vec![0; self.len() * 2 + 1]) };
encoding_rs::mem::convert_latin1_to_str(self.buf.as_slice(), dst_str.as_mut_str());

View file

@ -2,7 +2,7 @@ use std::mem;
use std::ptr;
use super::Value;
use crate::error::check_status;
use crate::check_status;
use crate::{sys, Ref, Result};
pub use latin1::JsStringLatin1;
@ -13,41 +13,44 @@ mod latin1;
mod utf16;
mod utf8;
#[repr(transparent)]
#[derive(Debug, Clone, Copy)]
#[derive(Clone, Copy)]
pub struct JsString(pub(crate) Value);
impl JsString {
#[inline]
pub fn utf8_len(&self) -> Result<usize> {
let mut length = 0;
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_value_string_utf8(self.0.env, self.0.value, ptr::null_mut(), 0, &mut length)
})?;
Ok(length as usize)
}
#[inline]
pub fn utf16_len(&self) -> Result<usize> {
let mut length = 0;
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_value_string_utf16(self.0.env, self.0.value, ptr::null_mut(), 0, &mut length)
})?;
Ok(length as usize)
}
#[inline]
pub fn latin1_len(&self) -> Result<usize> {
let mut length = 0;
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_value_string_latin1(self.0.env, self.0.value, ptr::null_mut(), 0, &mut length)
})?;
Ok(length as usize)
}
#[inline]
pub fn into_utf8(self) -> Result<JsStringUtf8> {
let mut written_char_count = 0;
let len = self.utf8_len()? + 1;
let mut result = Vec::with_capacity(len);
let buf_ptr = result.as_mut_ptr();
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_value_string_utf8(
self.0.env,
self.0.value,
@ -71,16 +74,18 @@ impl JsString {
})
}
#[inline]
pub fn into_utf8_ref(self) -> Result<Ref<JsStringUtf8>> {
Ref::new(self.0, 1, self.into_utf8()?)
}
#[inline]
pub fn into_utf16(self) -> Result<JsStringUtf16> {
let mut written_char_count = 0;
let len = self.utf16_len()? + 1;
let mut result = Vec::with_capacity(len);
let buf_ptr = result.as_mut_ptr();
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_value_string_utf16(
self.0.env,
self.0.value,
@ -99,16 +104,18 @@ impl JsString {
})
}
#[inline]
pub fn into_utf16_ref(self) -> Result<Ref<JsStringUtf16>> {
Ref::new(self.0, 1, self.into_utf16()?)
}
#[inline]
pub fn into_latin1(self) -> Result<JsStringLatin1> {
let mut written_char_count: u64 = 0;
let len = self.latin1_len()? + 1;
let mut result = Vec::with_capacity(len);
let buf_ptr = result.as_mut_ptr();
check_status(unsafe {
check_status!(unsafe {
sys::napi_get_value_string_latin1(
self.0.env,
self.0.value,
@ -132,6 +139,7 @@ impl JsString {
})
}
#[inline]
pub fn into_latin1_ref(self) -> Result<Ref<JsStringLatin1>> {
Ref::new(self.0, 1, self.into_latin1()?)
}

View file

@ -10,19 +10,23 @@ pub struct JsStringUtf16 {
}
impl JsStringUtf16 {
#[inline]
pub fn as_str(&self) -> Result<String> {
String::from_utf16(self.as_slice())
.map_err(|e| Error::new(Status::InvalidArg, format!("{}", e)))
}
#[inline]
pub fn as_slice(&self) -> &[u16] {
self.buf.as_slice()
}
#[inline]
pub fn len(&self) -> usize {
self.buf.len()
}
#[inline]
pub fn into_value(self) -> JsString {
self.inner
}

View file

@ -10,27 +10,33 @@ pub struct JsStringUtf8 {
}
impl JsStringUtf8 {
#[inline]
pub fn as_str(&self) -> Result<&str> {
str::from_utf8(self.buf.as_slice())
.map_err(|e| Error::new(Status::InvalidArg, format!("{}", e)))
}
#[inline]
pub fn as_slice(&self) -> &[u8] {
&self.buf
}
#[inline]
pub fn len(&self) -> usize {
self.buf.len()
}
#[inline]
pub fn to_owned(self) -> Result<String> {
Ok(self.as_str()?.to_owned())
}
#[inline]
pub fn take(self) -> Vec<u8> {
self.as_slice().to_vec()
}
#[inline]
pub fn into_value(self) -> JsString {
self.inner
}

View file

@ -1,5 +1,3 @@
use super::Value;
#[repr(transparent)]
#[derive(Debug)]
pub struct JsUndefined(pub(crate) Value);

View file

@ -2,7 +2,7 @@ use crate::sys;
use super::ValueType;
#[derive(Debug, Clone, Copy)]
#[derive(Clone, Copy)]
pub struct Value {
pub env: sys::napi_env,
pub value: sys::napi_value,

View file

@ -14,10 +14,11 @@ unsafe impl<T> Send for Ref<T> {}
unsafe impl<T> Sync for Ref<T> {}
impl<T> Ref<T> {
#[inline]
pub(crate) fn new(js_value: Value, ref_count: u32, inner: T) -> Result<Ref<T>> {
let mut raw_ref = ptr::null_mut();
let initial_ref_count = 1;
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_reference(
js_value.env,
js_value.value,
@ -32,17 +33,19 @@ impl<T> Ref<T> {
})
}
#[inline]
pub fn reference(&mut self, env: &Env) -> Result<u32> {
check_status(unsafe { sys::napi_reference_ref(env.0, self.raw_ref, &mut self.count) })?;
check_status!(unsafe { sys::napi_reference_ref(env.0, self.raw_ref, &mut self.count) })?;
Ok(self.count)
}
#[must_use]
#[inline]
pub fn unref(mut self, env: Env) -> Result<u32> {
check_status(unsafe { sys::napi_reference_unref(env.0, self.raw_ref, &mut self.count) })?;
check_status!(unsafe { sys::napi_reference_unref(env.0, self.raw_ref, &mut self.count) })?;
if self.count == 0 {
check_status(unsafe { sys::napi_delete_reference(env.0, self.raw_ref) })?;
check_status!(unsafe { sys::napi_delete_reference(env.0, self.raw_ref) })?;
}
Ok(self.count)
}

View file

@ -132,6 +132,7 @@ extern crate serde;
pub type ContextlessResult<T> = Result<Option<T>>;
/// Deprecated
/// register nodejs module
///
/// ## Example
@ -143,6 +144,7 @@ pub type ContextlessResult<T> = Result<Option<T>>;
/// }
/// ```
#[macro_export]
#[deprecated(since = "1.0.0", note = "[module_exports] macro instead")]
macro_rules! register_module {
($module_name:ident, $init:ident) => {
#[inline]
@ -170,6 +172,10 @@ macro_rules! register_module {
#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
use $crate::shutdown_tokio_rt;
if cfg!(debug_assertions) {
println!("`register_module` macro will deprecate soon, please migrate to [module_exports]");
}
let env = Env::from_raw(raw_env);
let mut exports: JsObject = JsObject::from_raw_unchecked(raw_env, raw_exports);
let mut cjs_module = Module { env, exports };

View file

@ -5,6 +5,7 @@ pub struct Module {
pub exports: JsObject,
}
#[deprecated(since = "1.0.0", note = "[module_exports] macro instead")]
impl Module {
pub fn create_named_method(&mut self, name: &str, function: Callback) -> Result<()> {
self

View file

@ -2,8 +2,7 @@ use futures::prelude::*;
use std::os::raw::{c_char, c_void};
use std::ptr;
use crate::error::check_status;
use crate::{sys, Env, NapiValue, Result};
use crate::{check_status, sys, Env, NapiValue, Result};
pub struct FuturePromise<T, V: NapiValue> {
deferred: sys::napi_deferred,
@ -16,6 +15,7 @@ pub struct FuturePromise<T, V: NapiValue> {
unsafe impl<T, V: NapiValue> Send for FuturePromise<T, V> {}
impl<T, V: NapiValue> FuturePromise<T, V> {
#[inline]
pub fn create(
env: sys::napi_env,
raw_deferred: sys::napi_deferred,
@ -23,7 +23,7 @@ impl<T, V: NapiValue> FuturePromise<T, V> {
) -> Result<Self> {
let mut async_resource_name = ptr::null_mut();
let s = "napi_resolve_promise_from_future";
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_string_utf8(
env,
s.as_ptr() as *const c_char,
@ -41,13 +41,14 @@ impl<T, V: NapiValue> FuturePromise<T, V> {
})
}
#[inline]
pub(crate) fn start(self) -> Result<TSFNValue> {
let mut tsfn_value = ptr::null_mut();
let async_resource_name = self.async_resource_name;
let initial_thread_count = 1;
let env = self.env;
let self_ref = Box::leak(Box::from(self));
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_threadsafe_function(
env,
ptr::null_mut(),
@ -77,9 +78,9 @@ pub(crate) async fn resolve_from_future<T: Send, F: Future<Output = Result<T>>>(
fut: F,
) {
let val = fut.await;
check_status(unsafe { sys::napi_acquire_threadsafe_function(tsfn_value.0) })
check_status!(unsafe { sys::napi_acquire_threadsafe_function(tsfn_value.0) })
.expect("Failed to acquire thread safe function");
check_status(unsafe {
check_status!(unsafe {
sys::napi_call_threadsafe_function(
tsfn_value.0,
Box::into_raw(Box::from(val)) as *mut _ as *mut c_void,
@ -112,7 +113,7 @@ unsafe extern "C" fn call_js_cb<T, V: NapiValue>(
debug_assert!(status == sys::Status::napi_ok, "Reject promise failed");
}
};
check_status(sys::napi_release_threadsafe_function(
check_status!(sys::napi_release_threadsafe_function(
tsfn,
sys::napi_threadsafe_function_release_mode::napi_tsfn_release,
))

View file

@ -5,8 +5,7 @@ use std::ptr;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use crate::error::check_status;
use crate::{sys, Env, Error, JsFunction, NapiValue, Result, Status};
use crate::{check_status, sys, Env, Error, JsFunction, NapiValue, Result, Status};
use sys::napi_threadsafe_function_call_mode;
@ -86,7 +85,6 @@ pub struct ThreadsafeFunction<T: 'static> {
unsafe impl<T> Send for ThreadsafeFunction<T> {}
unsafe impl<T> Sync for ThreadsafeFunction<T> {}
#[repr(transparent)]
struct ThreadSafeContext<T: 'static, V: NapiValue>(
Box<dyn FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>>,
);
@ -94,7 +92,7 @@ struct ThreadSafeContext<T: 'static, V: NapiValue>(
impl<T: 'static> ThreadsafeFunction<T> {
/// See [napi_create_threadsafe_function](https://nodejs.org/api/n-api.html#n_api_napi_create_threadsafe_function)
/// for more information.
#[inline(always)]
#[inline]
pub fn create<
V: NapiValue,
R: 'static + Send + FnMut(ThreadSafeCallContext<T>) -> Result<Vec<V>>,
@ -106,7 +104,7 @@ impl<T: 'static> ThreadsafeFunction<T> {
) -> Result<Self> {
let mut async_resource_name = ptr::null_mut();
let s = "napi_rs_threadsafe_function";
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_string_utf8(
env,
s.as_ptr() as *const c_char,
@ -119,7 +117,7 @@ impl<T: 'static> ThreadsafeFunction<T> {
let mut raw_tsfn = ptr::null_mut();
let context = ThreadSafeContext(Box::from(callback));
let ptr = Box::into_raw(Box::new(context)) as *mut _;
check_status(unsafe {
check_status!(unsafe {
sys::napi_create_threadsafe_function(
env,
func.0.value,
@ -169,7 +167,7 @@ impl<T: 'static> ThreadsafeFunction<T> {
format!("Can not ref, Thread safe function already aborted"),
));
}
check_status(unsafe { sys::napi_ref_threadsafe_function(env.0, self.raw_tsfn) })
check_status!(unsafe { sys::napi_ref_threadsafe_function(env.0, self.raw_tsfn) })
}
/// See [napi_unref_threadsafe_function](https://nodejs.org/api/n-api.html#n_api_napi_unref_threadsafe_function)
@ -181,7 +179,7 @@ impl<T: 'static> ThreadsafeFunction<T> {
format!("Can not unref, Thread safe function already aborted"),
));
}
check_status(unsafe { sys::napi_unref_threadsafe_function(env.0, self.raw_tsfn) })
check_status!(unsafe { sys::napi_unref_threadsafe_function(env.0, self.raw_tsfn) })
}
pub fn aborted(&self) -> bool {
@ -189,7 +187,7 @@ impl<T: 'static> ThreadsafeFunction<T> {
}
pub fn abort(self) -> Result<()> {
check_status(unsafe {
check_status!(unsafe {
sys::napi_release_threadsafe_function(
self.raw_tsfn,
sys::napi_threadsafe_function_release_mode::napi_tsfn_abort,
@ -206,7 +204,7 @@ impl<T: 'static> ThreadsafeFunction<T> {
format!("Can not clone, Thread safe function already aborted"),
));
}
check_status(unsafe { sys::napi_acquire_threadsafe_function(self.raw_tsfn) })?;
check_status!(unsafe { sys::napi_acquire_threadsafe_function(self.raw_tsfn) })?;
Ok(Self {
raw_tsfn: self.raw_tsfn,
aborted: Arc::clone(&self.aborted),

File diff suppressed because it is too large Load diff

View file

@ -23,3 +23,6 @@ tokio = {version = "0.3", features = ["default", "fs"]}
[build-dependencies]
napi-build = {path = "../build"}
[profile.release]
lto = true

View file

@ -6,6 +6,7 @@
"build-napi3": "cargo build --features \"napi3\" && node ../scripts/index.js build",
"build-aarch64": "cargo build --features \"latest\" --target aarch64-unknown-linux-gnu && node ../scripts/index.js build --target-triple aarch64-unknown-linux-gnu",
"build-i686": "cargo build --features \"latest\" --target i686-pc-windows-msvc && node ../scripts/index.js build --target-triple i686-pc-windows-msvc",
"build-i686-release": "cargo build --release --features \"latest\" --target i686-pc-windows-msvc && node ../scripts/index.js build --release --target-triple i686-pc-windows-msvc",
"build-release": "cargo build --features \"latest\" --release && node ../scripts/index.js build --release",
"test": "node ./index.js"
}

View file

@ -2,7 +2,7 @@ use std::convert::TryInto;
use napi::{
CallContext, ContextlessResult, Env, JsBoolean, JsNumber, JsObject, JsUndefined, JsUnknown,
Module, Result,
Result,
};
#[contextless_function]
@ -43,12 +43,12 @@ fn test_delete_element(ctx: CallContext) -> Result<JsBoolean> {
ctx.env.get_boolean(arr.delete_element(index.try_into()?)?)
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("testCreateArray", test_create_array)?;
module.create_named_method("testCreateArrayWithLength", test_create_array_with_length)?;
module.create_named_method("testSetElement", test_set_element)?;
module.create_named_method("testHasElement", test_has_element)?;
module.create_named_method("testDeleteElement", test_delete_element)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("testCreateArray", test_create_array)?;
exports.create_named_method("testCreateArrayWithLength", test_create_array_with_length)?;
exports.create_named_method("testSetElement", test_set_element)?;
exports.create_named_method("testHasElement", test_has_element)?;
exports.create_named_method("testDeleteElement", test_delete_element)?;
Ok(())
}

View file

@ -1,6 +1,6 @@
use std::str;
use napi::{CallContext, JsArrayBuffer, JsNumber, Module, Result};
use napi::{CallContext, JsArrayBuffer, JsNumber, JsObject, Result};
#[js_function(1)]
pub fn get_arraybuffer_length(ctx: CallContext) -> Result<JsNumber> {
@ -8,7 +8,7 @@ pub fn get_arraybuffer_length(ctx: CallContext) -> Result<JsNumber> {
ctx.env.create_uint32((&buffer).len() as u32)
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("getArraybufferLength", get_arraybuffer_length)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("getArraybufferLength", get_arraybuffer_length)?;
Ok(())
}

View file

@ -1,6 +1,6 @@
use std::str;
use napi::{CallContext, Error, JsBuffer, JsNumber, JsString, Module, Result, Status};
use napi::{CallContext, Error, JsBuffer, JsNumber, JsObject, JsString, Result, Status};
#[js_function(1)]
pub fn get_buffer_length(ctx: CallContext) -> Result<JsNumber> {
@ -22,9 +22,9 @@ pub fn copy_buffer(ctx: CallContext) -> Result<JsBuffer> {
ctx.env.create_buffer_copy(buffer).map(|b| b.into_raw())
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("getBufferLength", get_buffer_length)?;
module.create_named_method("bufferToString", buffer_to_string)?;
module.create_named_method("copyBuffer", copy_buffer)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("getBufferLength", get_buffer_length)?;
exports.create_named_method("bufferToString", buffer_to_string)?;
exports.create_named_method("copyBuffer", copy_buffer)?;
Ok(())
}

View file

@ -1,6 +1,6 @@
use std::convert::TryInto;
use napi::{CallContext, JsFunction, JsNumber, JsObject, JsUndefined, Module, Property, Result};
use napi::{CallContext, JsFunction, JsNumber, JsObject, JsUndefined, Property, Result};
struct NativeClass {
value: i32,
@ -58,8 +58,8 @@ fn new_test_class(ctx: CallContext) -> Result<JsObject> {
test_class.new(&vec![ctx.env.create_int32(42)?])
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("createTestClass", create_test_class)?;
module.create_named_method("newTestClass", new_test_class)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("createTestClass", create_test_class)?;
exports.create_named_method("newTestClass", new_test_class)?;
Ok(())
}

View file

@ -1,5 +1,5 @@
use napi::{
CallContext, CleanupEnvHook, ContextlessResult, Env, JsExternal, JsUndefined, Module, Result,
CallContext, CleanupEnvHook, ContextlessResult, Env, JsExternal, JsObject, JsUndefined, Result,
};
#[contextless_function]
@ -20,8 +20,8 @@ fn remove_cleanup_hook(ctx: CallContext) -> Result<JsUndefined> {
ctx.env.get_undefined()
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("addCleanupHook", add_cleanup_hook)?;
module.create_named_method("removeCleanupHook", remove_cleanup_hook)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("addCleanupHook", add_cleanup_hook)?;
exports.create_named_method("removeCleanupHook", remove_cleanup_hook)?;
Ok(())
}

View file

@ -1,6 +1,6 @@
use std::convert::TryInto;
use napi::{CallContext, Either, JsNumber, JsString, Module, Result};
use napi::{CallContext, Either, JsNumber, JsObject, JsString, Result};
#[js_function(1)]
pub fn either_number_string(ctx: CallContext) -> Result<Either<JsNumber, JsString>> {
@ -28,8 +28,8 @@ pub fn dynamic_argument_length(ctx: CallContext) -> Result<JsNumber> {
}
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("eitherNumberString", either_number_string)?;
module.create_named_method("dynamicArgumentLength", dynamic_argument_length)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("eitherNumberString", either_number_string)?;
exports.create_named_method("dynamicArgumentLength", dynamic_argument_length)?;
Ok(())
}

View file

@ -1,4 +1,4 @@
use napi::{CallContext, JsBoolean, JsUnknown, Module, Result};
use napi::{CallContext, JsBoolean, JsObject, JsUnknown, Result};
#[js_function(2)]
pub fn instanceof(ctx: CallContext) -> Result<JsBoolean> {
@ -26,10 +26,10 @@ pub fn strict_equals(ctx: CallContext) -> Result<JsBoolean> {
ctx.env.get_boolean(ctx.env.strict_equals(a, b)?)
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("instanceof", instanceof)?;
module.create_named_method("isTypedarray", is_typedarray)?;
module.create_named_method("isDataview", is_dataview)?;
module.create_named_method("strictEquals", strict_equals)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("instanceof", instanceof)?;
exports.create_named_method("isTypedarray", is_typedarray)?;
exports.create_named_method("isDataview", is_dataview)?;
exports.create_named_method("strictEquals", strict_equals)?;
Ok(())
}

View file

@ -1,4 +1,4 @@
use napi::{CallContext, Error, JsBoolean, JsString, JsUnknown, Module, Result, Status};
use napi::{CallContext, Error, JsBoolean, JsObject, JsString, JsUnknown, Result, Status};
#[js_function]
fn test_throw(_ctx: CallContext) -> Result<JsUnknown> {
@ -25,9 +25,9 @@ pub fn is_error(ctx: CallContext) -> Result<JsBoolean> {
ctx.env.get_boolean(js_value.is_error()?)
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("testThrow", test_throw)?;
module.create_named_method("testThrowWithReason", test_throw_with_reason)?;
module.create_named_method("isError", is_error)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("testThrow", test_throw)?;
exports.create_named_method("testThrowWithReason", test_throw_with_reason)?;
exports.create_named_method("isError", is_error)?;
Ok(())
}

View file

@ -1,6 +1,6 @@
use std::convert::TryInto;
use napi::{CallContext, JsExternal, JsNumber, Module, Result};
use napi::{CallContext, JsExternal, JsNumber, JsObject, Result};
struct NativeObject {
count: i32,
@ -20,8 +20,8 @@ pub fn get_external_count(ctx: CallContext) -> Result<JsNumber> {
ctx.env.create_int32(native_object.count)
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("createExternal", create_external)?;
module.create_named_method("getExternalCount", get_external_count)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("createExternal", create_external)?;
exports.create_named_method("getExternalCount", get_external_count)?;
Ok(())
}

View file

@ -1,4 +1,4 @@
use napi::{CallContext, JsFunction, JsNull, JsObject, Module, Result};
use napi::{CallContext, JsFunction, JsNull, JsObject, Result};
#[js_function(1)]
pub fn call_function(ctx: CallContext) -> Result<JsNull> {
@ -21,8 +21,8 @@ pub fn call_function_with_this(ctx: CallContext) -> Result<JsNull> {
ctx.env.get_null()
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("testCallFunction", call_function)?;
module.create_named_method("testCallFunctionWithThis", call_function_with_this)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("testCallFunction", call_function)?;
exports.create_named_method("testCallFunctionWithThis", call_function_with_this)?;
Ok(())
}

View file

@ -1,6 +1,6 @@
use std::convert::TryInto;
use napi::{CallContext, JsFunction, JsNumber, JsTimeout, JsUndefined, Module, Result};
use napi::{CallContext, JsFunction, JsNumber, JsObject, JsTimeout, JsUndefined, Result};
#[js_function(2)]
pub fn set_timeout(ctx: CallContext) -> Result<JsTimeout> {
@ -18,8 +18,8 @@ pub fn clear_timeout(ctx: CallContext) -> Result<JsUndefined> {
ctx.env.get_global()?.clear_timeout(timer)
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("setTimeout", set_timeout)?;
module.create_named_method("clearTimeout", clear_timeout)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("setTimeout", set_timeout)?;
exports.create_named_method("clearTimeout", clear_timeout)?;
Ok(())
}

View file

@ -1,11 +1,9 @@
#[macro_use]
extern crate napi;
#[macro_use]
extern crate napi_derive;
#[macro_use]
extern crate serde_derive;
use napi::{Module, Result};
use napi::{JsObject, Result};
mod cleanup_env;
#[cfg(feature = "latest")]
@ -36,33 +34,32 @@ mod task;
use napi_version::get_napi_version;
register_module!(test_module, init);
fn init(module: &mut Module) -> Result<()> {
module.create_named_method("getNapiVersion", get_napi_version)?;
array::register_js(module)?;
error::register_js(module)?;
string::register_js(module)?;
serde::register_js(module)?;
task::register_js(module)?;
external::register_js(module)?;
arraybuffer::register_js(module)?;
buffer::register_js(module)?;
either::register_js(module)?;
symbol::register_js(module)?;
function::register_js(module)?;
class::register_js(module)?;
env::register_js(module)?;
object::register_js(module)?;
global::register_js(module)?;
cleanup_env::register_js(module)?;
#[module_exports]
fn init(mut exports: JsObject) -> Result<()> {
exports.create_named_method("getNapiVersion", get_napi_version)?;
array::register_js(&mut exports)?;
error::register_js(&mut exports)?;
string::register_js(&mut exports)?;
serde::register_js(&mut exports)?;
task::register_js(&mut exports)?;
external::register_js(&mut exports)?;
arraybuffer::register_js(&mut exports)?;
buffer::register_js(&mut exports)?;
either::register_js(&mut exports)?;
symbol::register_js(&mut exports)?;
function::register_js(&mut exports)?;
class::register_js(&mut exports)?;
env::register_js(&mut exports)?;
object::register_js(&mut exports)?;
global::register_js(&mut exports)?;
cleanup_env::register_js(&mut exports)?;
#[cfg(feature = "latest")]
napi4::register_js(module)?;
napi4::register_js(&mut exports)?;
#[cfg(feature = "latest")]
tokio_rt::register_js(module)?;
tokio_rt::register_js(&mut exports)?;
#[cfg(feature = "latest")]
napi5::register_js(module)?;
napi5::register_js(&mut exports)?;
#[cfg(feature = "latest")]
napi6::register_js(module)?;
napi6::register_js(&mut exports)?;
Ok(())
}

View file

@ -1,22 +1,22 @@
use napi::{Module, Result};
use napi::{JsObject, Result};
mod tsfn;
use tsfn::*;
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("testThreadsafeFunction", test_threadsafe_function)?;
module.create_named_method("testTsfnError", test_tsfn_error)?;
module.create_named_method("testTokioReadfile", test_tokio_readfile)?;
module.create_named_method(
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("testThreadsafeFunction", test_threadsafe_function)?;
exports.create_named_method("testTsfnError", test_tsfn_error)?;
exports.create_named_method("testTokioReadfile", test_tokio_readfile)?;
exports.create_named_method(
"testAbortThreadsafeFunction",
test_abort_threadsafe_function,
)?;
module.create_named_method(
exports.create_named_method(
"testAbortIndependentThreadsafeFunction",
test_abort_independent_threadsafe_function,
)?;
module.create_named_method(
exports.create_named_method(
"testCallAbortedThreadsafeFunction",
test_call_aborted_threadsafe_function,
)?;

View file

@ -1,10 +1,10 @@
use napi::{Module, Result};
use napi::{JsObject, Result};
mod date;
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("testObjectIsDate", date::test_object_is_date)?;
module.create_named_method("testCreateDate", date::test_create_date)?;
module.create_named_method("testGetDateValue", date::test_get_date_value)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("testObjectIsDate", date::test_object_is_date)?;
exports.create_named_method("testCreateDate", date::test_create_date)?;
exports.create_named_method("testGetDateValue", date::test_get_date_value)?;
Ok(())
}

View file

@ -1,17 +1,17 @@
use napi::{Module, Result};
use napi::{JsObject, Result};
mod bigint;
use bigint::*;
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("testCreateBigintFromI64", test_create_bigint_from_i64)?;
module.create_named_method("testCreateBigintFromU64", test_create_bigint_from_u64)?;
module.create_named_method("testCreateBigintFromI128", test_create_bigint_from_i128)?;
module.create_named_method("testCreateBigintFromU128", test_create_bigint_from_u128)?;
module.create_named_method("testCreateBigintFromWords", test_create_bigint_from_words)?;
module.create_named_method("testGetBigintI64", test_get_bigint_i64)?;
module.create_named_method("testGetBigintU64", test_get_bigint_u64)?;
module.create_named_method("testGetBigintWords", test_get_bigint_words)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("testCreateBigintFromI64", test_create_bigint_from_i64)?;
exports.create_named_method("testCreateBigintFromU64", test_create_bigint_from_u64)?;
exports.create_named_method("testCreateBigintFromI128", test_create_bigint_from_i128)?;
exports.create_named_method("testCreateBigintFromU128", test_create_bigint_from_u128)?;
exports.create_named_method("testCreateBigintFromWords", test_create_bigint_from_words)?;
exports.create_named_method("testGetBigintI64", test_get_bigint_i64)?;
exports.create_named_method("testGetBigintU64", test_get_bigint_u64)?;
exports.create_named_method("testGetBigintWords", test_get_bigint_words)?;
Ok(())
}

View file

@ -1,8 +1,7 @@
use std::convert::TryInto;
use napi::{
CallContext, JsBoolean, JsNumber, JsObject, JsString, JsUndefined, JsUnknown, Module, Property,
Result,
CallContext, JsBoolean, JsNumber, JsObject, JsString, JsUndefined, JsUnknown, Property, Result,
};
#[js_function(2)]
@ -164,28 +163,28 @@ fn test_is_promise(ctx: CallContext) -> Result<JsBoolean> {
ctx.env.get_boolean(obj.is_promise()?)
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("testSetProperty", test_set_property)?;
module.create_named_method("testGetProperty", test_get_property)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("testSetProperty", test_set_property)?;
exports.create_named_method("testGetProperty", test_get_property)?;
module.create_named_method("testSetNamedProperty", test_set_named_property)?;
module.create_named_method("testGetNamedProperty", test_get_named_property)?;
module.create_named_method("testHasNamedProperty", test_has_named_property)?;
exports.create_named_method("testSetNamedProperty", test_set_named_property)?;
exports.create_named_method("testGetNamedProperty", test_get_named_property)?;
exports.create_named_method("testHasNamedProperty", test_has_named_property)?;
module.create_named_method("testHasOwnProperty", test_has_own_property)?;
module.create_named_method("testHasOwnPropertyJs", test_has_own_property_js)?;
module.create_named_method("testHasProperty", test_has_property)?;
module.create_named_method("testHasPropertyJs", test_has_property_js)?;
module.create_named_method("testDeleteProperty", test_delete_property)?;
module.create_named_method("testDeleteNamedProperty", test_delete_named_property)?;
module.create_named_method("testGetPropertyNames", test_get_property_names)?;
module.create_named_method("testGetPrototype", test_get_prototype)?;
module.create_named_method("testSetElement", test_set_element)?;
module.create_named_method("testHasElement", test_has_element)?;
module.create_named_method("testGetElement", test_get_element)?;
module.create_named_method("testDeleteElement", test_delete_element)?;
module.create_named_method("testDefineProperties", test_define_properties)?;
exports.create_named_method("testHasOwnProperty", test_has_own_property)?;
exports.create_named_method("testHasOwnPropertyJs", test_has_own_property_js)?;
exports.create_named_method("testHasProperty", test_has_property)?;
exports.create_named_method("testHasPropertyJs", test_has_property_js)?;
exports.create_named_method("testDeleteProperty", test_delete_property)?;
exports.create_named_method("testDeleteNamedProperty", test_delete_named_property)?;
exports.create_named_method("testGetPropertyNames", test_get_property_names)?;
exports.create_named_method("testGetPrototype", test_get_prototype)?;
exports.create_named_method("testSetElement", test_set_element)?;
exports.create_named_method("testHasElement", test_has_element)?;
exports.create_named_method("testGetElement", test_get_element)?;
exports.create_named_method("testDeleteElement", test_delete_element)?;
exports.create_named_method("testDefineProperties", test_define_properties)?;
module.create_named_method("testIsPromise", test_is_promise)?;
exports.create_named_method("testIsPromise", test_is_promise)?;
Ok(())
}

View file

@ -1,4 +1,4 @@
use napi::{CallContext, JsObject, JsUndefined, JsUnknown, Module, Result};
use napi::{CallContext, JsObject, JsUndefined, JsUnknown, Result};
#[derive(Serialize, Debug, Deserialize)]
struct AnObject {
@ -162,21 +162,21 @@ fn roundtrip_object(ctx: CallContext) -> Result<JsUnknown> {
ctx.env.to_js_value(&de_serialized)
}
pub fn register_js(m: &mut Module) -> Result<()> {
m.create_named_method("make_num_77", make_num_77)?;
m.create_named_method("make_num_32", make_num_32)?;
m.create_named_method("make_str_hello", make_str_hello)?;
m.create_named_method("make_num_array", make_num_array)?;
m.create_named_method("make_buff", make_buff)?;
m.create_named_method("make_obj", make_obj)?;
m.create_named_method("make_object", make_object)?;
m.create_named_method("make_map", make_map)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("make_num_77", make_num_77)?;
exports.create_named_method("make_num_32", make_num_32)?;
exports.create_named_method("make_str_hello", make_str_hello)?;
exports.create_named_method("make_num_array", make_num_array)?;
exports.create_named_method("make_buff", make_buff)?;
exports.create_named_method("make_obj", make_obj)?;
exports.create_named_method("make_object", make_object)?;
exports.create_named_method("make_map", make_map)?;
m.create_named_method("expect_hello_world", expect_hello_world)?;
m.create_named_method("expect_obj", expect_obj)?;
m.create_named_method("expect_num_array", expect_num_array)?;
m.create_named_method("expect_buffer", expect_buffer)?;
exports.create_named_method("expect_hello_world", expect_hello_world)?;
exports.create_named_method("expect_obj", expect_obj)?;
exports.create_named_method("expect_num_array", expect_num_array)?;
exports.create_named_method("expect_buffer", expect_buffer)?;
m.create_named_method("roundtrip_object", roundtrip_object)?;
exports.create_named_method("roundtrip_object", roundtrip_object)?;
Ok(())
}

View file

@ -1,4 +1,4 @@
use napi::{CallContext, JsString, Module, Result};
use napi::{CallContext, JsObject, JsString, Result};
#[js_function(1)]
fn concat_string(ctx: CallContext) -> Result<JsString> {
@ -23,9 +23,9 @@ fn create_latin1(ctx: CallContext) -> Result<JsString> {
ctx.env.create_string_latin1(bytes.as_slice())
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("concatString", concat_string)?;
module.create_named_method("concatLatin1String", concat_latin1_string)?;
module.create_named_method("createLatin1", create_latin1)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("concatString", concat_string)?;
exports.create_named_method("concatLatin1String", concat_latin1_string)?;
exports.create_named_method("createLatin1", create_latin1)?;
Ok(())
}

View file

@ -1,4 +1,4 @@
use napi::{CallContext, JsString, JsSymbol, Module, Result};
use napi::{CallContext, JsObject, JsString, JsSymbol, Result};
#[js_function]
pub fn create_named_symbol(ctx: CallContext) -> Result<JsSymbol> {
@ -16,9 +16,9 @@ pub fn create_symbol_from_js_string(ctx: CallContext) -> Result<JsSymbol> {
ctx.env.create_symbol_from_js_string(name)
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("createNamedSymbol", create_named_symbol)?;
module.create_named_method("createUnnamedSymbol", create_unnamed_symbol)?;
module.create_named_method("createSymbolFromJsString", create_symbol_from_js_string)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("createNamedSymbol", create_named_symbol)?;
exports.create_named_method("createUnnamedSymbol", create_unnamed_symbol)?;
exports.create_named_method("createSymbolFromJsString", create_symbol_from_js_string)?;
Ok(())
}

View file

@ -1,8 +1,6 @@
use std::convert::TryInto;
use napi::{
CallContext, Env, JsBuffer, JsBufferValue, JsNumber, JsObject, Module, Ref, Result, Task,
};
use napi::{CallContext, Env, JsBuffer, JsBufferValue, JsNumber, JsObject, Ref, Result, Task};
struct ComputeFib {
n: u32,
@ -75,8 +73,8 @@ fn test_spawn_thread_with_ref(ctx: CallContext) -> Result<JsObject> {
Ok(async_work_promise.promise_object())
}
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("testSpawnThread", test_spawn_thread)?;
module.create_named_method("testSpawnThreadWithRef", test_spawn_thread_with_ref)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("testSpawnThread", test_spawn_thread)?;
exports.create_named_method("testSpawnThreadWithRef", test_spawn_thread_with_ref)?;
Ok(())
}

View file

@ -1,11 +1,11 @@
use napi::{Module, Result};
use napi::{JsObject, Result};
mod read_file;
use read_file::*;
pub fn register_js(module: &mut Module) -> Result<()> {
module.create_named_method("testExecuteTokioReadfile", test_execute_tokio_readfile)?;
module.create_named_method("testTokioError", error_from_tokio_future)?;
pub fn register_js(exports: &mut JsObject) -> Result<()> {
exports.create_named_method("testExecuteTokioReadfile", test_execute_tokio_readfile)?;
exports.create_named_method("testTokioError", error_from_tokio_future)?;
Ok(())
}