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