napi_h/
lib.rs

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