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