Neon Documentation

repository·main·Indexed 27 days ago

https://github.com/neon-bindings/neon

Neon provides Rust bindings for writing safe, high-performance native addons for Node.js. It includes tools like create-neon for bootstrapping projects and cargo-cp-artifact for managing compiler artifacts. The library provides macros such as #[neon::main], #[neon::export], and #[neon::class] to define module entry points, export functions, and create JavaScript classes from Rust structs. It supports Linux, macOS, and Windows, requiring Rust stable 1.65 or higher.

Tokens
8.9K
Snippets
26
Records
62
Agent score
93%

What's inside Neon

  1. Handle concurrency with the Channel API

    main

    The Task API and EventHandler API are deprecated in the N-API backend. Use the Channel API (neon::event::Channel) and the Event Queue API instead.

    To use the Channel API, you must enable the "channel-api" feature flag in your Cargo.toml.

    Configuration Example:

    [dependencies.neon]
    version = "0.9.1"
    default-features = false
    features = ["napi-6", "channel-api"]

    Using the Event Queue API

    Instead of using the libuv thread pool (via Task), spawn native threads and use cx.queue() to send results back to the main JavaScript thread.

    Example:

    pub fn start_task(mut cx: FunctionContext) -> JsResult<JsUndefined> {
        let callback = cx.argument::<JsFunction>(0)?.root(&mut cx);
        let queue = cx.queue();
    
        std::thread::spawn(move || {
            let result = // compute the result...
            queue.send(move |mut cx| {
                let callback = callback.into_inner(&mut cx);
                let this = cx.undefined();
                let args = match result {
                    Ok(n) => vec![
                        cx.null().upcast::<JsValue>(),
                        cx.number(n).upcast()
                    ],
                    Err(msg) => vec![
                        cx.error(msg).upcast()
                    ]
                };
                callback.call(&mut cx, this, args)?;
                Ok(())
            });
        });
    
        Ok(cx.undefined())
    }
  2. Migrate to Neon 1.0.0

    main
    Neon 1.0.0 introduced breaking changes to address unsoundness, improve consistency, and add new features. If you are upgrading an existing project, you must follow the official migration guide to port your code to the 1.0.0 API.
  3. Call or construct JS functions in Neon 0.10

    main

    Neon 0.10 introduces two layers for function interaction:

    1. Low-level API: .call() and .construct() are now primitives that do not automatically downcast arguments or results. They accept arrays of handles.
    2. High-level API: .call_with() and .construct_with() provide a convenient builder pattern for method chaining and automatic argument handling.

    Use the high-level API for cleaner, more idi-omatic code.

    // High-level API: Calling a function
    f.call_with(&cx)
     .args((cx.string("hello"), cx.number(42)))
     .apply(&mut cx)
    
    // High-level API: Constructing (new) a function
    f.construct_with(&cx)
     .args((s, n))
     .apply(&mut cx)
    
    // Low-level API: Calling a function
    f.call(&mut cx, this, [s.upcast(), n.upcast()])
    
    // Low-level API: Constructing a function
    f.construct(&mut cx, [s.upcast(), n.upcast()])
  4. Update Cargo.toml feature flags for Neon 1.0.0

    main

    In Neon 1.0.0, many previously unstable features (like try-catch-api or channel-api) have been stabilized and their feature flags removed. You should remove these from your Cargo.toml.

    Only the following feature flags remain:

    • napi-N: Specifies the Node-API version.
    • futures: Provides compatibility between Rust Future and JavaScript Promise.
  5. Access Typed Arrays as Rust slices in Neon 0.10

    main

    Neon 0.10 replaces the old JsArrayBuffer API with idiomatic JsTypedArray<T> types. This allows you to access the underlying data as Rust slices directly via .as_slice() or .as_mut_slice().

    To cast between different buffer types (e.g., from u8 to f32), use a crate like bytemuck instead of the deprecated Neon casting methods.

    // Reading a buffer
    let b: Handle<JsTypedArray<u32>> = ...;
    let slice = b.as_slice(&cx);
    
    // Reading and writing buffers
    let src_buf: Handle<JsTypedArray<u32>> = ...;
    let dst_buf: Handle<JsTypedArray<u32>> = ...;
    {
        let lock = cx.lock();
        let src = src_buf.as_slice(&lock).unwrap();
        let dst = dst_buf.as_mut_slice(&lock).unwrap();
    }
    
    // Casting buffer types using bytemuck
    use bytemuck::cast_slice;
    let b: Handle<JsTypedArray<u8>> = ...;
    let u8_slice = b.as_slice(&cx);
    let f32_slice: &[f32] = cast_slice(u8_slice);
  6. Enable the N-API backend in Neon

    main

    To migrate to the N-API backend, follow these steps:

    1. Remove build script: Delete build.rs from your project directory and remove the build = "build.rs" line from your Cargo.toml.
    2. Disable default features: Set default-features = false in your Cargo.toml to opt out of the legacy backend.
    3. Select N-API version: Enable the specific N-API version feature flag required for your target Node.js environment (e.g., "napi-4").

    Requirements:

    • Minimum Node.js version: 10.0.
    • Consult the official N-API feature matrix to determine the appropriate version for your Node.js release.
    [dependencies.neon]
    version = "0.9.1"
    default-features = false
    features = ["napi-4"]
  7. Bootstrap a simple Neon project

    main

    Use create-neon to bootstrap a Neon project consisting purely of Rust code. This allows you to build binary Node modules written in Rust.

    To create a project, use the npm init neon syntax. Note that the -- separator is required to pass options through npm init to the Neon tool.

    $ npm init neon[@latest] -- [<opts> ...] my-project
  8. Migrate `JsFunction` and `CallContext` usage

    main

    In Neon 1.0.0, CallContext<T> is replaced by FunctionContext. The This trait is also removed. Instead of relying on the T parameter in JsFunction to type-check cx.this(), cx.this() now always returns a JsValue. You must use .this::<T>()? to downcast the context to a specific type.

    // Before
    fn example(mut cx: CallContext<JsObject>) -> JsResult<JsUndefined> {
        let a = cx.this().get::<JsValue, _, _>(&mut cx, "a")?;
        Ok(cx.undefined())
    }
    
    // After
    fn example(mut cx: FunctionContext) -> JsResult<JsUndefined> {
        let a = cx.this::<JsObject>()?.get::<JsValue, _, _>(&mut cx, "a")?;
        Ok(cx.undefined())
    }