neon/
lib.rs

1//! The [Neon][neon] crate provides bindings for writing [Node.js addons][addons]
2//! (i.e., dynamically-loaded binary modules) with a safe and fast Rust API.
3//!
4//! ## Getting Started
5//!
6//! You can conveniently bootstrap a new Neon project with the Neon project
7//! generator. You don't need to install anything special on your machine as
8//! long as you have a [supported version of Node and Rust][supported] on
9//! your system.
10//!
11//! To start a new project, open a terminal in the directory where you would
12//! like to place the project, and run at the command prompt:
13//!
14//! ```text
15//! % npm init neon my-project
16//! ... answer the user prompts ...
17//! ✨ Created Neon project `my-project`. Happy 🦀 hacking! ✨
18//! ```
19//!
20//! where `my-project` can be any name you like for the project. This will
21//! run the Neon project generator, prompting you with a few questions and
22//! placing a simple but working Neon project in a subdirectory called
23//! `my-project` (or whatever name you chose).
24//!
25//! You can then install and build the project by changing into the project
26//! directory and running the standard Node installation command:
27//!
28//! ```text
29//! % cd my-project
30//! % npm install
31//! % node
32//! > require(".").hello()
33//! 'hello node'
34//! ```
35//!
36//! You can look in the project's generated `README.md` for more details on
37//! the project structure.
38//!
39//! ## Example
40//!
41//! The generated `src/lib.rs` contains a function annotated with the
42//! [`#[neon::main]`](main) attribute, marking it as the module's main entry
43//! point to be executed when the module is loaded. This function can have
44//! any name but is conventionally called `main`:
45//!
46//! ```no_run
47//! # mod example {
48//! # use neon::prelude::*;
49//! # fn hello(mut cx: FunctionContext) -> JsResult<JsString> {
50//! #    Ok(cx.string("hello node"))
51//! # }
52//! #[neon::main]
53//! fn main(mut cx: ModuleContext) -> NeonResult<()> {
54//!     cx.export_function("hello", hello)?;
55//!     Ok(())
56//! }
57//! # }
58//! ```
59//!
60//! The example code generated by `npm init neon` exports a single
61//! function via [`ModuleContext::export_function`](context::ModuleContext::export_function).
62//! The `hello` function is defined just above `main` in `src/lib.rs`:
63//!
64//! ```
65//! # use neon::prelude::*;
66//! #
67//! fn hello(mut cx: FunctionContext) -> JsResult<JsString> {
68//!     Ok(cx.string("hello node"))
69//! }
70//! ```
71//!
72//! The `hello` function takes a [`FunctionContext`](context::FunctionContext) and
73//! returns a JavaScript string. Because all Neon functions can potentially throw a
74//! JavaScript exception, the return type is wrapped in a [`JsResult`](result::JsResult).
75//!
76//! [neon]: https://www.neon-bindings.com/
77//! [addons]: https://nodejs.org/api/addons.html
78//! [supported]: https://github.com/neon-bindings/neon#platform-support
79#![cfg_attr(docsrs, feature(doc_cfg))]
80
81pub mod context;
82pub mod event;
83pub mod handle;
84mod macros;
85pub mod meta;
86pub mod object;
87pub mod prelude;
88pub mod reflect;
89pub mod result;
90#[cfg(not(feature = "sys"))]
91mod sys;
92#[cfg_attr(docsrs, doc(cfg(feature = "napi-6")))]
93#[cfg(feature = "napi-6")]
94pub mod thread;
95// To use the #[aquamarine] attribute on the top-level neon::types module docs, we have to
96// use this hack so we can keep the module docs in a separate file.
97// See: https://github.com/mersinvald/aquamarine/issues/5#issuecomment-1168816499
98mod types_docs;
99mod types_impl;
100
101#[cfg(feature = "sys")]
102#[cfg_attr(docsrs, doc(cfg(feature = "sys")))]
103pub mod sys;
104
105#[cfg(all(feature = "napi-6", feature = "futures"))]
106#[cfg_attr(docsrs, doc(cfg(all(feature = "napi-6", feature = "futures"))))]
107pub use executor::set_global_executor;
108pub use types_docs::exports as types;
109
110#[doc(hidden)]
111pub mod macro_internal;
112
113pub use crate::macros::*;
114
115use crate::{context::ModuleContext, handle::Handle, result::NeonResult, types::JsValue};
116
117#[cfg(feature = "napi-6")]
118mod lifecycle;
119
120#[cfg(all(feature = "napi-6", feature = "futures"))]
121mod executor;
122
123#[cfg(feature = "napi-8")]
124static MODULE_TAG: once_cell::sync::Lazy<crate::sys::TypeTag> = once_cell::sync::Lazy::new(|| {
125    let mut lower = [0; std::mem::size_of::<u64>()];
126
127    // Generating a random module tag at runtime allows Neon builds to be reproducible. A few
128    //  alternatives considered:
129    // * Generating a random value at build time; this reduces runtime dependencies but, breaks
130    //   reproducible builds
131    // * A static random value; this solves the previous issues, but does not protect against ABI
132    //   differences across Neon and Rust versions
133    // * Calculating a variable from the environment (e.g. Rust version); this theoretically works
134    //   but, is complicated and error prone. This could be a future optimization.
135    getrandom::getrandom(&mut lower).expect("Failed to generate a Neon module type tag");
136
137    // We only use 64-bits of the available 128-bits. The rest is reserved for future versioning and
138    // expansion of implementation.
139    let lower = u64::from_ne_bytes(lower);
140
141    // Note: `upper` must be non-zero or `napi_check_object_type_tag` will always return false
142    // https://github.com/nodejs/node/blob/5fad0b93667ffc6e4def52996b9529ac99b26319/src/js_native_api_v8.cc#L2455
143    crate::sys::TypeTag { lower, upper: 1 }
144});
145
146/// Values exported with [`neon::export`](export)
147pub struct Exports(());
148
149impl Exports {
150    /// Export all values exported with [`neon::export`](export)
151    ///
152    /// ```
153    /// # fn main() {
154    /// # use neon::prelude::*;
155    /// #[neon::main]
156    /// fn main(mut cx: ModuleContext) -> NeonResult<()> {
157    ///     neon::registered().export(&mut cx)?;
158    ///     Ok(())
159    /// }
160    /// # }
161    /// ```
162    ///
163    /// For more control, iterate over exports.
164    ///
165    /// ```
166    /// # fn main() {
167    /// # use neon::prelude::*;
168    /// #[neon::main]
169    /// fn main(mut cx: ModuleContext) -> NeonResult<()> {
170    ///     for create in neon::registered() {
171    ///         let (name, value) = create(&mut cx)?;
172    ///
173    ///         cx.export_value(name, value)?;
174    ///     }
175    ///
176    ///     Ok(())
177    /// }
178    /// # }
179    /// ```
180    pub fn export(self, cx: &mut ModuleContext) -> NeonResult<()> {
181        for create in self {
182            let (name, value) = create(cx)?;
183
184            cx.export_value(name, value)?;
185        }
186
187        Ok(())
188    }
189}
190
191impl IntoIterator for Exports {
192    type Item = <<Self as IntoIterator>::IntoIter as IntoIterator>::Item;
193    type IntoIter = std::slice::Iter<
194        'static,
195        for<'cx> fn(&mut ModuleContext<'cx>) -> NeonResult<(&'static str, Handle<'cx, JsValue>)>,
196    >;
197
198    fn into_iter(self) -> Self::IntoIter {
199        crate::macro_internal::EXPORTS.into_iter()
200    }
201}
202
203/// Access values exported with [`neon::export`](export)
204pub fn registered() -> Exports {
205    Exports(())
206}
207
208#[test]
209fn feature_matrix() {
210    use std::{env, process::Command};
211
212    const NODE_API_VERSIONS: &[&str] = &[
213        "napi-1", "napi-2", "napi-3", "napi-4", "napi-5", "napi-6", "napi-7", "napi-8",
214    ];
215
216    const FEATURES: &[&str] = &["external-buffers", "futures", "serde", "tokio", "tokio-rt"];
217
218    let cargo = env::var_os("CARGO").unwrap_or_else(|| "cargo".into());
219
220    for features in itertools::Itertools::powerset(FEATURES.iter()) {
221        for version in NODE_API_VERSIONS.iter().map(|f| f.to_string()) {
222            let features = features.iter().fold(version, |f, s| f + "," + s);
223            let status = Command::new(&cargo)
224                .args(["check", "-p", "neon", "--features"])
225                .arg(features)
226                .spawn()
227                .unwrap()
228                .wait()
229                .unwrap();
230
231            assert!(status.success());
232        }
233    }
234}