Skip to main content

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

The 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 Running#

We 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 Rust
  • index.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 Dependency#

Let'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 Function#

Next 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 to get_num_cpus: this contains information about the function call, such as the arguments and the value of this.
  • The JsResult output type: this is a Rust Result 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 of get_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!