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 ~ napi8
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: [n_api_version_matrix](https://nodejs.org/api/n-api.html#n_api_n_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::{CallContext, Error, JsObject, JsString, Result, Status};
24//! use tokio;
25//!
26//! #[napi]
27//! pub async fn tokio_readfile(js_filepath: String) -> Result<JsBuffer> {
28//! ctx.env.execute_tokio_future(
29//! tokio::fs::read(js_filepath)
30//! .map(|v| v.map_err(|e| Error::new(Status::Unknown, format!("failed to read file, {}", e)))),
31//! |&mut env, data| env.create_buffer_with_data(data),
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(feature = "napi8")]
69mod async_cleanup_hook;
70#[cfg(feature = "napi8")]
71pub use async_cleanup_hook::AsyncCleanupHook;
72mod async_work;
73mod bindgen_runtime;
74mod call_context;
75#[cfg(feature = "napi3")]
76mod cleanup_env;
77mod env;
78mod error;
79mod js_values;
80mod status;
81mod task;
82#[cfg(all(feature = "tokio_rt", feature = "napi4"))]
83mod tokio_runtime;
84mod value_type;
85#[cfg(feature = "napi3")]
86pub use cleanup_env::CleanupEnvHook;
87#[cfg(feature = "napi4")]
88pub mod threadsafe_function;
89
90mod version;
91
92pub use napi_sys as sys;
93
94pub use async_work::AsyncWorkPromise;
95pub use call_context::CallContext;
96
97pub use bindgen_runtime::iterator;
98pub use env::*;
99pub use error::*;
100pub use js_values::*;
101pub use status::Status;
102pub use task::Task;
103pub use value_type::*;
104pub use version::NodeVersion;
105#[cfg(feature = "serde-json")]
106#[macro_use]
107extern crate serde;
108
109pub type ContextlessResult<T> = Result<Option<T>>;
110
111#[doc(hidden)]
112#[macro_export(local_inner_macros)]
113macro_rules! type_of {
114 ($env:expr, $value:expr) => {{
115 let mut value_type = 0;
116 #[allow(unused_unsafe)]
117 check_status!(unsafe { $crate::sys::napi_typeof($env, $value, &mut value_type) })
118 .and_then(|_| Ok($crate::ValueType::from(value_type)))
119 }};
120}
121
122#[doc(hidden)]
123#[macro_export]
124macro_rules! assert_type_of {
125 ($env: expr, $value:expr, $value_ty: expr) => {
126 $crate::type_of!($env, $value).and_then(|received_type| {
127 if received_type == $value_ty {
128 Ok(())
129 } else {
130 Err($crate::Error::new(
131 $crate::Status::InvalidArg,
132 format!(
133 "Expect value to be {}, but received {}",
134 $value_ty, received_type
135 ),
136 ))
137 }
138 })
139 };
140}
141
142pub use crate::bindgen_runtime::ctor as module_init;
143
144pub mod bindgen_prelude {
145 #[cfg(all(feature = "compat-mode", not(feature = "noop")))]
146 pub use crate::bindgen_runtime::register_module_exports;
147 #[cfg(feature = "tokio_rt")]
148 pub use crate::tokio_runtime::*;
149 pub use crate::{
150 assert_type_of, bindgen_runtime::*, check_pending_exception, check_status,
151 check_status_or_throw, error, error::*, sys, type_of, JsError, Property, PropertyAttributes,
152 Result, Status, Task, ValueType,
153 };
154
155 // This function's signature must be kept in sync with the one in tokio_runtime.rs, otherwise napi
156 // will fail to compile without the `tokio_rt` feature.
157
158 /// If the feature `tokio_rt` has been enabled this will enter the runtime context and
159 /// then call the provided closure. Otherwise it will just call the provided closure.
160 #[cfg(not(all(feature = "tokio_rt", feature = "napi4")))]
161 pub fn within_runtime_if_available<F: FnOnce() -> T, T>(f: F) -> T {
162 f()
163 }
164}
165
166#[doc(hidden)]
167pub mod __private {
168 pub use crate::bindgen_runtime::{
169 get_class_constructor, iterator::create_iterator, register_class, ___CALL_FROM_FACTORY,
170 };
171
172 use crate::sys;
173
174 pub unsafe fn log_js_value<V: AsRef<[sys::napi_value]>>(
175 // `info`, `log`, `warning` or `error`
176 method: &str,
177 env: sys::napi_env,
178 values: V,
179 ) {
180 use std::ffi::CString;
181 use std::ptr;
182
183 let mut g = ptr::null_mut();
184 unsafe { sys::napi_get_global(env, &mut g) };
185 let mut console = ptr::null_mut();
186 let console_c_string = CString::new("console").unwrap();
187 let method_c_string = CString::new(method).unwrap();
188 unsafe { sys::napi_get_named_property(env, g, console_c_string.as_ptr(), &mut console) };
189 let mut method_js_fn = ptr::null_mut();
190 unsafe {
191 sys::napi_get_named_property(env, console, method_c_string.as_ptr(), &mut method_js_fn)
192 };
193 unsafe {
194 sys::napi_call_function(
195 env,
196 console,
197 method_js_fn,
198 values.as_ref().len(),
199 values.as_ref().as_ptr(),
200 ptr::null_mut(),
201 )
202 };
203 }
204}
205
206#[cfg(feature = "tokio_rt")]
207pub extern crate tokio;
208
209#[cfg(feature = "error_anyhow")]
210pub extern crate anyhow;
211