Skip to main content

napi/
lib.rs

1#![deny(clippy::all)]
2#![allow(non_upper_case_globals)]
3
4//! High level Node.js [N-API](https://nodejs.org/api/n-api.html) binding
5//!
6//! **napi-rs** provides minimal overhead to write N-API modules in `Rust`.
7//!
8//! ## Feature flags
9//!
10//! ### napi1 ~ napi10
11//!
12//! Because `Node.js` N-API has versions. So there are feature flags to choose what version of `N-API` you want to build for.
13//! For example, if you want build a library which can be used by `node@10.17.0`, you should choose the `napi5` or lower.
14//!
15//! The details of N-API versions and support matrix: [Node-API version matrix](https://nodejs.org/api/n-api.html#node-api-version-matrix)
16//!
17//! ### tokio_rt
18//! With `tokio_rt` feature, `napi-rs` provides a ***tokio runtime*** in an additional thread.
19//! And you can easily run tokio `future` in it and return `promise`.
20//!
21//! ```
22//! use futures::prelude::*;
23//! use napi::bindgen_prelude::*;
24//! use tokio;
25//!
26//! #[napi]
27//! pub fn tokio_readfile(js_filepath: String) -> Result<Buffer> {
28//!     ctx.env.spawn_future_with_callback(
29//!         tokio::fs::read(js_filepath)
30//!           .map(|v| v.map_err(|e| Error::new(Status::Unknown, format!("failed to read file, {}", e)))),
31//!         |_, data| data.into(),
32//!     )
33//! }
34//! ```
35//!
36//! ### latin1
37//!
38//! Decode latin1 string from JavaScript using [encoding_rs](https://docs.rs/encoding_rs).
39//!
40//! With this feature, you can use `JsString.as_latin1_string` function
41//!
42//! ### serde-json
43//!
44//! Enable Serialize/Deserialize data cross `JavaScript Object` and `Rust struct`.
45//!
46//! ```
47//! #[derive(Serialize, Debug, Deserialize)]
48//! struct AnObject {
49//!     a: u32,
50//!     b: Vec<f64>,
51//!     c: String,
52//! }
53//!
54//! #[napi]
55//! fn deserialize_from_js(arg0: JsUnknown) -> Result<JsUndefined> {
56//!     let de_serialized: AnObject = ctx.env.from_js_value(arg0)?;
57//!     ...
58//! }
59//!
60//! #[napi]
61//! fn serialize(env: Env) -> Result<JsUnknown> {
62//!     let value = AnyObject { a: 1, b: vec![0.1, 2.22], c: "hello" };
63//!     env.to_js_value(&value)
64//! }
65//! ```
66//!
67
68#[cfg(all(target_family = "wasm", not(feature = "noop"), feature = "napi3"))]
69#[link(wasm_import_module = "napi")]
70extern "C" {
71  fn napi_add_env_cleanup_hook(
72    env: sys::napi_env,
73    fun: Option<unsafe extern "C" fn(arg: *mut core::ffi::c_void)>,
74    arg: *mut core::ffi::c_void,
75  ) -> sys::napi_status;
76}
77
78#[cfg(feature = "napi8")]
79mod async_cleanup_hook;
80#[cfg(feature = "napi8")]
81pub use async_cleanup_hook::AsyncCleanupHook;
82mod async_work;
83mod bindgen_runtime;
84#[cfg(feature = "compat-mode")]
85mod call_context;
86#[cfg(feature = "napi3")]
87mod cleanup_env;
88mod env;
89mod error;
90mod js_values;
91mod status;
92mod task;
93#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
94mod tokio_runtime;
95mod value_type;
96#[cfg(feature = "napi3")]
97pub use cleanup_env::CleanupEnvHook;
98#[cfg(not(feature = "noop"))]
99mod sendable_resolver;
100#[cfg(feature = "napi4")]
101pub mod threadsafe_function;
102#[cfg(not(feature = "noop"))]
103pub use sendable_resolver::SendableResolver;
104
105mod version;
106
107pub use napi_sys as sys;
108
109pub use async_work::AsyncWorkPromise;
110#[cfg(feature = "compat-mode")]
111pub use call_context::CallContext;
112
113pub use bindgen_runtime::iterator;
114pub use env::*;
115pub use error::*;
116pub use js_values::*;
117pub use status::Status;
118pub use task::{ScopedTask, Task};
119pub use value_type::*;
120pub use version::NodeVersion;
121#[cfg(feature = "serde-json")]
122#[macro_use]
123extern crate serde;
124
125pub type ContextlessResult<T> = Result<Option<T>>;
126
127#[doc(hidden)]
128#[macro_export(local_inner_macros)]
129macro_rules! type_of {
130  ($env:expr, $value:expr) => {{
131    let mut value_type = 0;
132    #[allow(unused_unsafe)]
133    check_status!(unsafe { $crate::sys::napi_typeof($env, $value, &mut value_type) })
134      .and_then(|_| Ok($crate::ValueType::from(value_type)))
135  }};
136}
137
138#[doc(hidden)]
139#[macro_export]
140macro_rules! assert_type_of {
141  ($env: expr, $value:expr, $value_ty: expr) => {
142    $crate::type_of!($env, $value).and_then(|received_type| {
143      if received_type == $value_ty {
144        Ok(())
145      } else {
146        Err($crate::Error::new(
147          $crate::Status::InvalidArg,
148          format!(
149            "Expect value to be {}, but received {}",
150            $value_ty, received_type
151          ),
152        ))
153      }
154    })
155  };
156}
157
158pub mod bindgen_prelude {
159  #[cfg(all(feature = "compat-mode", not(feature = "noop")))]
160  pub use crate::bindgen_runtime::register_module_exports;
161  #[cfg(feature = "tokio_rt")]
162  pub use crate::tokio_runtime::*;
163  pub use crate::{
164    assert_type_of, bindgen_runtime::*, check_pending_exception, check_status,
165    check_status_or_throw, error, error::*, sys, type_of, JsError, JsValue, Property,
166    PropertyAttributes, Result, Status, Task, ValueType,
167  };
168  #[cfg(feature = "tracing")]
169  pub use ::tracing;
170
171  // This function's signature must be kept in sync with the one in tokio_runtime.rs, otherwise napi
172  // will fail to compile without the `tokio_rt` feature.
173
174  /// If the feature `tokio_rt` has been enabled this will enter the runtime context and
175  /// then call the provided closure. Otherwise it will just call the provided closure.
176  #[cfg(not(all(feature = "tokio_rt", feature = "napi4")))]
177  pub fn within_runtime_if_available<F: FnOnce() -> T, T>(f: F) -> T {
178    f()
179  }
180}
181
182#[doc(hidden)]
183pub mod __private {
184  pub use crate::bindgen_runtime::{
185    get_class_constructor, iterator::create_iterator, register_class, ___CALL_FROM_FACTORY,
186  };
187
188  #[cfg(feature = "tokio_rt")]
189  pub use crate::bindgen_runtime::async_iterator::create_async_iterator;
190
191  use crate::sys;
192
193  pub unsafe fn log_js_value<V: AsRef<[sys::napi_value]>>(
194    // `info`, `log`, `warning` or `error`
195    method: &str,
196    env: sys::napi_env,
197    values: V,
198  ) {
199    use std::ffi::CString;
200    use std::ptr;
201
202    let mut g = ptr::null_mut();
203    unsafe { sys::napi_get_global(env, &mut g) };
204    let mut console = ptr::null_mut();
205    let console_c_string = CString::new("console").unwrap();
206    let method_c_string = CString::new(method).unwrap();
207    unsafe { sys::napi_get_named_property(env, g, console_c_string.as_ptr(), &mut console) };
208    let mut method_js_fn = ptr::null_mut();
209    unsafe {
210      sys::napi_get_named_property(env, console, method_c_string.as_ptr(), &mut method_js_fn)
211    };
212    unsafe {
213      sys::napi_call_function(
214        env,
215        console,
216        method_js_fn,
217        values.as_ref().len(),
218        values.as_ref().as_ptr(),
219        ptr::null_mut(),
220      )
221    };
222  }
223}
224
225pub extern crate ctor;
226
227#[cfg(feature = "tokio_rt")]
228pub extern crate tokio;
229
230#[cfg(feature = "error_anyhow")]
231pub extern crate anyhow;
232
233#[cfg(feature = "web_stream")]
234pub extern crate futures_core;
235#[cfg(feature = "web_stream")]
236pub extern crate tokio_stream;