doc: add some documents

This commit is contained in:
LongYinan 2020-07-14 22:57:11 +08:00
parent 9118e9e62d
commit 62482ab2e6
No known key found for this signature in database
GPG key ID: C3666B7FC82ADAD7
6 changed files with 108 additions and 11 deletions

View file

@ -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;

View file

@ -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 {

View file

@ -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))?;

View file

@ -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) => {

View file

@ -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

View 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')
}
})