doc: add some documents
This commit is contained in:
parent
9118e9e62d
commit
62482ab2e6
6 changed files with 108 additions and 11 deletions
|
@ -5,10 +5,11 @@ use std::mem;
|
||||||
use std::os::raw::{c_char, c_void};
|
use std::os::raw::{c_char, c_void};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
|
||||||
|
use crate::async_work::AsyncWork;
|
||||||
use crate::error::check_status;
|
use crate::error::check_status;
|
||||||
use crate::js_values::*;
|
use crate::js_values::*;
|
||||||
use crate::task::Task;
|
use crate::task::Task;
|
||||||
use crate::{sys, AsyncWork, Error, NodeVersion, Result, Status};
|
use crate::{sys, Error, NodeVersion, Result, Status};
|
||||||
|
|
||||||
#[cfg(all(any(feature = "libuv", feature = "tokio_rt"), napi4))]
|
#[cfg(all(any(feature = "libuv", feature = "tokio_rt"), napi4))]
|
||||||
use crate::promise;
|
use crate::promise;
|
||||||
|
|
|
@ -37,7 +37,7 @@ impl Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn into_raw(self, env: sys::napi_env) -> sys::napi_value {
|
pub(crate) fn into_raw(self, env: sys::napi_env) -> sys::napi_value {
|
||||||
let mut err = ptr::null_mut();
|
let mut err = ptr::null_mut();
|
||||||
let s = self.reason;
|
let s = self.reason;
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|
|
@ -25,9 +25,9 @@ pub use function::JsFunction;
|
||||||
pub use number::JsNumber;
|
pub use number::JsNumber;
|
||||||
pub use object::JsObject;
|
pub use object::JsObject;
|
||||||
pub use string::JsString;
|
pub use string::JsString;
|
||||||
pub use tagged_object::TaggedObject;
|
pub(crate) use tagged_object::TaggedObject;
|
||||||
pub use value::Value;
|
pub(crate) use value::Value;
|
||||||
pub use value_ref::Ref;
|
pub(crate) use value_ref::Ref;
|
||||||
pub use value_type::ValueType;
|
pub use value_type::ValueType;
|
||||||
|
|
||||||
// Value types
|
// Value types
|
||||||
|
@ -51,7 +51,7 @@ pub struct JsSymbol(pub(crate) Value);
|
||||||
pub struct JsExternal(pub(crate) Value);
|
pub struct JsExternal(pub(crate) Value);
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn type_of(env: sys::napi_env, raw_value: sys::napi_value) -> Result<ValueType> {
|
pub(crate) fn type_of(env: sys::napi_env, raw_value: sys::napi_value) -> Result<ValueType> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let mut value_type = sys::napi_valuetype::napi_undefined;
|
let mut value_type = sys::napi_valuetype::napi_undefined;
|
||||||
check_status(sys::napi_typeof(env, raw_value, &mut value_type))?;
|
check_status(sys::napi_typeof(env, raw_value, &mut value_type))?;
|
||||||
|
|
|
@ -1,3 +1,61 @@
|
||||||
|
//! High level NodeJS [N-API](https://nodejs.org/api/n-api.html) binding
|
||||||
|
//!
|
||||||
|
//! **napi-rs** provides minimal overhead to write N-API modules in `Rust`.
|
||||||
|
//! ## Feature flags
|
||||||
|
//! ### libuv
|
||||||
|
//! With `libuv` feature, you can execute a rust future in `libuv` in NodeJS, and return a `promise` object.
|
||||||
|
//! ```
|
||||||
|
//! use std::thread;
|
||||||
|
//! use std::fs;
|
||||||
|
//!
|
||||||
|
//! use futures::prelude::*;
|
||||||
|
//! use futures::channel::oneshot;
|
||||||
|
//! use napi::{CallContext, Result, JsString, JsObject, Status, Error};
|
||||||
|
//!
|
||||||
|
//! #[js_function(1)]
|
||||||
|
//! pub fn uv_read_file(ctx: CallContext) -> Result<JsObject> {
|
||||||
|
//! let path = ctx.get::<JsString>(0)?;
|
||||||
|
//! let (sender, receiver) = oneshot::channel();
|
||||||
|
//! let p = path.as_str()?.to_owned();
|
||||||
|
//! thread::spawn(|| {
|
||||||
|
//! let res = fs::read(p).map_err(|e| Error::new(Status::Unknown, format!("{}", e)));
|
||||||
|
//! sender.send(res).expect("Send data failed");
|
||||||
|
//! });
|
||||||
|
//! ctx.env.execute(receiver.map_err(|e| Error::new(Status::Unknown, format!("{}", e))).map(|x| x.and_then(|x| x)), |&mut env, data| {
|
||||||
|
//! env.create_buffer_with_data(data)
|
||||||
|
//! })
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//! ### tokio_rt
|
||||||
|
//! With `tokio_rt` feature, `napi-rs` provides a ***tokio runtime*** in an additional thread.
|
||||||
|
//! And you can easily run tokio `future` in it and return `promise`.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! use futures::prelude::*;
|
||||||
|
//! use napi::{CallContext, Error, JsObject, JsString, Result, Status};
|
||||||
|
//! use tokio;
|
||||||
|
//!
|
||||||
|
//! #[js_function(1)]
|
||||||
|
//! pub fn tokio_readfile(ctx: CallContext) -> Result<JsObject> {
|
||||||
|
//! let js_filepath = ctx.get::<JsString>(0)?;
|
||||||
|
//! let path_str = js_filepath.as_str()?;
|
||||||
|
//! ctx.env.execute_tokio_future(
|
||||||
|
//! tokio::fs::read(path_str.to_owned())
|
||||||
|
//! .map(|v| v.map_err(|e| Error::new(Status::Unknown, format!("failed to read file, {}", e)))),
|
||||||
|
//! |&mut env, data| env.create_buffer_with_data(data),
|
||||||
|
//! )
|
||||||
|
//! }
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! ***Tokio channel in `napi-rs` buffer size is default `100`.***
|
||||||
|
//!
|
||||||
|
//! ***You can adjust it via `NAPI_RS_TOKIO_CHANNEL_BUFFER_SIZE` environment variable***
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! NAPI_RS_TOKIO_CHANNEL_BUFFER_SIZE=1000 node ./app.js
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
|
||||||
mod async_work;
|
mod async_work;
|
||||||
mod call_context;
|
mod call_context;
|
||||||
mod env;
|
mod env;
|
||||||
|
@ -17,20 +75,28 @@ mod tokio_rt;
|
||||||
mod uv;
|
mod uv;
|
||||||
mod version;
|
mod version;
|
||||||
|
|
||||||
pub use async_work::AsyncWork;
|
|
||||||
pub use call_context::CallContext;
|
pub use call_context::CallContext;
|
||||||
pub use env::*;
|
pub use env::*;
|
||||||
pub use error::{Error, Result};
|
pub use error::{Error, Result};
|
||||||
pub use js_values::*;
|
pub use js_values::*;
|
||||||
pub use module::Module;
|
pub use module::Module;
|
||||||
pub use status::Status;
|
pub use status::Status;
|
||||||
pub use sys::napi_valuetype;
|
|
||||||
pub use task::Task;
|
pub use task::Task;
|
||||||
pub use version::NodeVersion;
|
pub use version::NodeVersion;
|
||||||
|
|
||||||
#[cfg(all(feature = "tokio_rt", napi4))]
|
#[cfg(all(feature = "tokio_rt", napi4))]
|
||||||
pub use tokio_rt::shutdown as shutdown_tokio_rt;
|
pub use tokio_rt::shutdown as shutdown_tokio_rt;
|
||||||
|
|
||||||
|
/// register nodejs module
|
||||||
|
///
|
||||||
|
/// ## Example
|
||||||
|
/// ```
|
||||||
|
/// register_module!(test_module, init);
|
||||||
|
///
|
||||||
|
/// fn init(module: &mut Module) -> Result<()> {
|
||||||
|
/// module.create_named_method("nativeFunction", native_function)?;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! register_module {
|
macro_rules! register_module {
|
||||||
($module_name:ident, $init:ident) => {
|
($module_name:ident, $init:ident) => {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
use std::env::var;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::mem;
|
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::thread::spawn;
|
use std::thread::spawn;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
@ -20,7 +20,11 @@ pub(crate) enum Message {
|
||||||
pub(crate) fn get_tokio_sender() -> &'static mpsc::Sender<Message> {
|
pub(crate) fn get_tokio_sender() -> &'static mpsc::Sender<Message> {
|
||||||
static SENDER: OnceCell<mpsc::Sender<Message>> = OnceCell::new();
|
static SENDER: OnceCell<mpsc::Sender<Message>> = OnceCell::new();
|
||||||
SENDER.get_or_init(|| {
|
SENDER.get_or_init(|| {
|
||||||
let (sender, mut receiver) = mpsc::channel(100);
|
let buffer_size = var("NAPI_RS_TOKIO_CHANNEL_BUFFER_SIZE")
|
||||||
|
.map_err(|_| ())
|
||||||
|
.and_then(|s| s.parse().map_err(|_| ()))
|
||||||
|
.unwrap_or(100);
|
||||||
|
let (sender, mut receiver) = mpsc::channel(buffer_size);
|
||||||
spawn(move || {
|
spawn(move || {
|
||||||
let mut rt = Runtime::new().expect("Failed to create tokio runtime");
|
let mut rt = Runtime::new().expect("Failed to create tokio runtime");
|
||||||
rt.block_on(async {
|
rt.block_on(async {
|
||||||
|
@ -33,7 +37,6 @@ pub(crate) fn get_tokio_sender() -> &'static mpsc::Sender<Message> {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
rt.shutdown_timeout(Duration::from_secs(5));
|
rt.shutdown_timeout(Duration::from_secs(5));
|
||||||
mem::drop(receiver);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
sender
|
sender
|
||||||
|
|
27
test_module/__test__/napi4/tokio_rt-isolate.spec.js
Normal file
27
test_module/__test__/napi4/tokio_rt-isolate.spec.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
const test = require('ava')
|
||||||
|
const { join } = require('path')
|
||||||
|
|
||||||
|
const napiVersion = require('../napi-version')
|
||||||
|
|
||||||
|
const filepath = join(__dirname, './example.txt')
|
||||||
|
|
||||||
|
process.env.NAPI_RS_TOKIO_CHANNEL_BUFFER_SIZE = '1'
|
||||||
|
|
||||||
|
const bindings = require('../../index.node')
|
||||||
|
|
||||||
|
test('should be able adjust queue size via process.env', async (t) => {
|
||||||
|
if (napiVersion < 4) {
|
||||||
|
t.is(bindings.testExecuteTokioReadfile, undefined)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await Promise.all(
|
||||||
|
Array.from({ length: 50 }).map((_) =>
|
||||||
|
bindings.testExecuteTokioReadfile(filepath),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
throw new TypeError('Unreachable')
|
||||||
|
} catch (e) {
|
||||||
|
t.is(e.message, 'QueueFull: Failed to run future: no available capacity')
|
||||||
|
}
|
||||||
|
})
|
Loading…
Reference in a new issue