Docs
Concepts
Function

Function

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

lib.rs
#[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 TypeJavaScript Type
u32number
i32number
i64number
f64number
boolboolean
Stringstring
Latin1Stringstring
UTF16Stringstring
#[napi(object)] structObject
& struct or &mut structClass instance
serde_json::MapObject
serde_json::Valueunknown
std::collections::HashMapObject
Arrayunknown[]
Vec<T> T must be types in this tableT[]
BufferBuffer
ExternalExternal
Nullnull
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>
AbortSignalAbortSignal (opens in a new tab)
JsSymbolSymbol
Int8Array / Uint8Array / Int16Array...TypedArray
BigIntBigInt

Return Type

Rust TypeJavaScript Type
u32number
i32number
i64number
f64number
boolboolean
Stringstring
Latin1Stringstring
UTF16Stringstring
#[napi(object)] structObject
#[napi] structClass
serde_json::MapObject
serde_json::Valueunknown
std::collections::HashMapObject
Arrayunknown[]
Vec<T> T must be types in this tableT[]
BufferBuffer
ExternalExternal
Nullnull
Undefined / ()undefined
Option<T>T or null
AsyncTask<Task<JsValue = T>>Promise<T>
JsSymbolSymbol
Int8Array / Uint8Array / Int16Array...TypedArray
BigIntBigInt
i64nBigInt
i128BigInt
u128BigInt

Function as parameter

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

lib.rs
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
export declare function callFunction(callback: (arg: number) => number): number

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.

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

lib.rs
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
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
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(
  callback: Function<(), ()>,
  this: ClassInstance<RustClass>,
) -> Result<()> {
  callback.apply(this, ())
}
index.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:

See ThreadsafeFunction for the details of options

💡

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
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(())
}