Hello World!
Full source code: examples/cpu-count
This small example project will be a module that returns the number of processors in the current device. If you're not familiar with fancy systems concepts like processors and CPUs, don't panic! We'll be using the num_cpus
crate to do all the heavy lifting for us, and we'll just return the number it gives us.
The tutorial is short, but it demonstrates some of Neon's power: Rust's crate ecosystem is growing quickly and full of many useful and unique libraries, often providing low-level capabilities or high-performance data structures that can be hard to find in npm. A library like num_cpus
could be useful, for example, as a hint for tuning the size of a Web Worker pool in an Electron app.
#
Creating a New ProjectThe first thing we have to do is create our new cpu-count
Neon project:
npm init neon cpu-count
This will ask us a series of questions similar to the ones asked by npm init
. When it completes, the tool will have created a cpu-count
directory with the following layout:
cpu-count/├── Cargo.toml├── README.md├── package.json└── src └── lib.rs
The first thing to notice about this layout is that a Neon project is both a Node package, and a Rust crate.
The Rust source lives in src/
, but JavaScript that augments Rust can live side-by-side.
Similar to how Babel can be adjusted to target a minimum JavaScript version, Neon can target a Node version by adjusting the napi
feature in the Cargo.toml
. By default, npm init neon
will use the currently installed Node version.
[dependencies.neon]features = ["napi-6"]
See the Node-API version matrix for more details.
#
Building and RunningWe haven't yet implemented anything, but just to see that npm init neon
produced a complete, minimal Neon project, let's try building it:
cd cpu-countnpm install
The build process generates a handful of files:
target/
: The build directory used by Rustindex.node
: The compiled Neon module
An easy way to clean up build artifacts is to run:
cargo clean
Once we've built the project, we can try running it:
node> require('.').hello()hello node
#
Adding a Rust DependencyLet's add a Rust dependency on the num_cpus crate. In Cargo.toml
, add the following lines:
[dependencies]num_cpus = "1"
This tells Cargo, Rust's build tool, to fetch a version of the num_cpus
crate that is semver-compatible with 1
. (The package.json
equivalent would be "num_cpus": "^1"
.)
#
Implementing our FunctionNext we can replace the sample hello
function that was generated by npm init neon
with the function we actually want. Instead of returning a string, our function should return a JavaScript number. So we'll use cx.number()
helper. Since cx.number()
expects a Rust f64
(i.e., a 64-bit floating-point number), and num_cpus::get()
returns a usize
(i.e., a pointer-sized integer), we'll use Rust'sas
operator to cast to convert the integer to floating-point:
use neon::prelude::*;
fn get_num_cpus(mut cx: FunctionContext) -> JsResult<JsNumber> { Ok(cx.number(num_cpus::get() as f64))}
A few more things to note about this code:
- The
cx
argument toget_num_cpus
: this contains information about the function call, such as the arguments and the value ofthis
. - The
JsResult
output type: this is a RustResult
type that indicates whether the function returned (Ok
) or threw a JavaScript exception (Err
). It also tracks the lifetime of the returned handle. - The
cx.number()
function tells the JavaScript garbage collector that we need to keep the value we allocate alive long enough to return it to the caller ofget_num_cpus
.
Finally, we'll modify the code that npm init neon
created for us to set up the module exports with this function instead of the initial "hello world" function it created for us:
#[neon::main]fn main(mut cx: ModuleContext) -> NeonResult<()> { cx.export_function("get", get_num_cpus)?; Ok(())}
This tells Neon to initialize the module when it's first loaded by creating a JavaScript function implemented with the get_num_cpus
function we defined above and exporting it as a module property named "get"
.
You can see the full lib.rs
file in the examples repository.
#
Try it Out!Now we should be able to rebuild the project:
npm run build -- --release
This will create a release build for us. Release builds take longer to compile, but the final library executes more quickly. Assuming we didn't make any mistakes, we can test out our new Neon module at the Node console from the root of our project directory:
node> const cpuCount = require('.')> cpuCount.get()4
Keep in mind that the result of calling cpuCount.get()
will vary based on the machine you run this demo on—by design!