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