Skip to content

Function

Defining a JavaScript function is very simple in NAPI-RS. Just a plain Rust fn:

lib.rs
rust
#[napi]
pub fn sum(a: u32, b: u32) -> u32 {
  a + b
}

The most important thing you should keep in mind is NAPI-RS fn does not support every Rust type. Here is a table to illustrate how JavaScript types map to Rust types when they are fn arguments and return types:

Arguments

Rust Type JavaScript Type
u32 number
i32 number
i64 number
f64 number
bool boolean
String string
Latin1String string
UTF16String string
#[napi(object)] struct Object
& struct or &mut struct Class instance
serde_json::Map Object
serde_json::Value unknown
std::collections::HashMap Object
Array unknown[]
Vec<T> T must be types in this table T[]
Buffer Buffer
External External
Null null
Undefined / () undefined
Option<T> T or null
Fn(Arg) ->T Arg and T must be types in this table (arg: Arg) => T
Promise<T> Promise<T>
AbortSignal AbortSignal
JsSymbol Symbol
Int8Array / Uint8Array / Int16Array... TypedArray
BigInt BigInt

Return Type

Rust Type JavaScript Type
u32 number
i32 number
i64 number
f64 number
bool boolean
String string
Latin1String string
UTF16String string
#[napi(object)] struct Object
#[napi] struct Class
serde_json::Map Object
serde_json::Value unknown
std::collections::HashMap Object
Array unknown[]
Vec<T> T must be types in this table T[]
Buffer Buffer
External External
Null null
Undefined / () undefined
Option<T> T or null
AsyncTask<Task<JsValue = T>> Promise<T>
JsSymbol Symbol
Int8Array / Uint8Array / Int16Array... TypedArray
BigInt BigInt
i64n BigInt
i128 BigInt
u128 BigInt

Function as parameter

You can pass a Function as a parameter to a fn:

lib.rs
rust
use napi::bindgen_prelude::*;
use napi_derive::napi;

#[napi]
pub fn call_function(callback: Function<u32, u32>) -> Result<u32> {
  callback.call(1)
}

⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️

index.d.ts
ts
export declare function callFunction(callback: (arg: number) => number): number

INFO

You can also create a Function at the Rust side, see Env::create_function

FnArgs

When the number of parameters exceeds 1, you can use FnArgs to define the parameters.

INFO

The tuple type can be converted to FnArgs by calling .into().

lib.rs
rust
use napi::bindgen_prelude::*;
use napi_derive::napi;

#[napi]
pub fn call_function_with_args(callback: Function<FnArgs<(u32, u32)>, u32>) -> Result<u32> {
  callback.call((1, 2).into()) 
}

⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️ ⬇️

index.d.ts
ts
export declare function callFunctionWithArgs(
  callback: (arg1: number, arg2: number) => number,
): number

apply

Like JavaScript, you can also use apply to call a Function with the this value.

lib.rs
rust
use napi::bindgen_prelude::*;
use napi_derive::napi;

#[napi]
pub struct RustClass {
  pub name: String,
}

#[napi]
impl RustClass {
  #[napi(constructor)]
  pub fn new(name: String) -> Self {
    Self { name }
  }
}

#[napi]
pub fn call_function_with_apply(
  this: ClassInstance<RustClass>,
  callback: Function<(), ()>,
) -> Result<()> {
  callback.apply(this, ())
}
index.ts
ts
import { callFunctionWithApply, RustClass } from './index.js'

const rustClass = new RustClass('foo')

callFunctionWithApply(rustClass, function () {
  console.log(this.name) // foo
})

create_ref

See Function Reference for more details.

build_threadsafe_function

You can build a ThreadsafeFunction from a Function by calling build_threadsafe_function.

The return type of the build_threadsafe_function is a ThreadsafeFunctionBuilder.

By default, the ThreadsafeFunctionBuilder will create a ThreadsafeFunction with the default options:

INFO

See ThreadsafeFunction for the details of options

TIP

Since you can pass ThreadsafeFunction and Arc<ThreadsafeFunction> directly to the #[napi] fn, only use the build_threadsafe_function when you are need to create a ThreadsafeFunction dynamically.

  • max_queue_size is 0
  • weak is false
  • callee_handled is true
  • error_status is napi::Status
lib.rs
rust
use napi::{bindgen_prelude::*, threadsafe_function::ThreadsafeFunctionCallMode};
use napi_derive::napi;

#[napi]
pub fn build_threadsafe_function_from_function(
  callback: Function<FnArgs<(u32, u32)>, u32>,
) -> Result<()> {
  let tsfn = callback.build_threadsafe_function().build()?;
  let jh = std::thread::spawn(move || {
    tsfn.call((1, 2).into(), ThreadsafeFunctionCallMode::NonBlocking);
  });

  Ok(())
}