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" )] |
69 | mod async_cleanup_hook; |
70 | #[cfg (feature = "napi8" )] |
71 | pub use async_cleanup_hook::AsyncCleanupHook; |
72 | mod async_work; |
73 | mod bindgen_runtime; |
74 | mod call_context; |
75 | #[cfg (feature = "napi3" )] |
76 | mod cleanup_env; |
77 | mod env; |
78 | mod error; |
79 | mod js_values; |
80 | mod status; |
81 | mod task; |
82 | #[cfg (all(feature = "tokio_rt" , feature = "napi4" ))] |
83 | mod tokio_runtime; |
84 | mod value_type; |
85 | #[cfg (feature = "napi3" )] |
86 | pub use cleanup_env::CleanupEnvHook; |
87 | #[cfg (feature = "napi4" )] |
88 | pub mod threadsafe_function; |
89 | |
90 | mod version; |
91 | |
92 | pub use napi_sys as sys; |
93 | |
94 | pub use async_work::AsyncWorkPromise; |
95 | pub use call_context::CallContext; |
96 | |
97 | pub use bindgen_runtime::iterator; |
98 | pub use env::*; |
99 | pub use error::*; |
100 | pub use js_values::*; |
101 | pub use status::Status; |
102 | pub use task::Task; |
103 | pub use value_type::*; |
104 | pub use version::NodeVersion; |
105 | #[cfg (feature = "serde-json" )] |
106 | #[macro_use ] |
107 | extern crate serde; |
108 | |
109 | pub type ContextlessResult<T> = Result<Option<T>>; |
110 | |
111 | #[doc (hidden)] |
112 | #[macro_export (local_inner_macros)] |
113 | macro_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 ] |
124 | macro_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 | |
142 | pub use crate::bindgen_runtime::ctor as module_init ; |
143 | |
144 | pub 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)] |
167 | pub 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" )] |
207 | pub extern crate tokio; |
208 | |
209 | #[cfg (feature = "error_anyhow" )] |
210 | pub extern crate anyhow; |
211 | |