Appearance
Functions
Fresh 🌱Neon's main way of connecting Rust and JavaScript is letting you define functions implemented in Rust. A Neon function looks and acts like a regular JavaScript function, but its body is Rust.
Defining functions
A Neon function is a Rust function of type fn(FunctionContext) -> JsResult<T>, where T is any type implementing the Value trait:
rust
fn hello(mut cx: FunctionContext) -> JsResult<JsString> {
Ok(cx.string("hello"))
}cx: FunctionContextgives access to the JavaScript runtime (arguments,this, value constructors).JsResult<T>signals the function may throw a JavaScript error. Here we just build a string and wrap it inOk.
Export it from your module:
rust
#[neon::main]
pub fn main(mut cx: ModuleContext) -> NeonResult<()> {
cx.export_function("hello", hello)?;
Ok(())
}main returns a result too, because export_function interacts with the module object and could throw. The ? operator propagates any error. Then from JavaScript:
javascript
const { hello } = require('./index');
console.log(hello()); // prints "hello"Accessing arguments
Read positional arguments with FunctionContext::argument():
rust
fn create_pair(mut cx: FunctionContext) -> JsResult<JsObject> {
let x: Handle<JsValue> = cx.argument(0)?;
let y: Handle<JsValue> = cx.argument(1)?;
let obj = cx.empty_object();
obj.set(&mut cx, "x", x)?;
obj.set(&mut cx, "y", y)?;
Ok(obj)
}Checking argument types
Choose a more specific type than JsValue to both check and cast the argument. If a check fails, the function throws a TypeError:
rust
fn create_book(mut cx: FunctionContext) -> JsResult<JsObject> {
let title = cx.argument::<JsString>(0)?;
let author = cx.argument::<JsString>(1)?;
let year = cx.argument::<JsNumber>(2)?;
let obj = cx.empty_object();
obj.set(&mut cx, "title", title)?;
obj.set(&mut cx, "author", author)?;
obj.set(&mut cx, "year", year)?;
Ok(obj)
}javascript
try {
createBook(null, null, null);
} catch (e) {
console.log(e); // TypeError
}Optional arguments
FunctionContext::argument_opt() extracts an argument that may be absent:
rust
fn create_job(mut cx: FunctionContext) -> JsResult<JsObject> {
let company = cx.argument::<JsString>(0)?;
let title = cx.argument::<JsString>(1)?;
let start_year = cx.argument::<JsNumber>(2)?;
let end_year = cx.argument_opt(3);
let obj = cx.empty_object();
obj.set(&mut cx, "company", company)?;
obj.set(&mut cx, "title", title)?;
obj.set(&mut cx, "startYear", start_year)?;
if let Some(end_year) = end_year {
obj.set(&mut cx, "endYear", end_year)?;
} else {
let null = cx.null();
obj.set(&mut cx, "endYear", null)?;
}
Ok(obj)
}Calling JavaScript functions
Call a JS function from Rust with JsFunction::call_with(). This example pulls parseInt off the global object and calls parseInt("42"):
rust
let parse_int: Handle<JsFunction> = cx.global().get(&mut cx, "parseInt")?;
let x: Handle<JsNumber> = parse_int
.call_with(&mut cx)
.arg(cx.string("42"))
.apply(&mut cx)?;Calling constructor functions
Invoke a JS function as a constructor (as if with new) using JsFunction::construct_with(). This example calls new URL("..."):
rust
let url: Handle<JsFunction> = cx.global().get(&mut cx, "URL")?;
let obj = url
.construct_with(&mut cx)
.arg(cx.string("https://neon-bindings.com"))
.apply(&mut cx)?;A newer builder: bind()
Recent Neon also offers a bind() builder for calling and constructing functions with typed argument conversion. See Calling JavaScript from Rust for that style plus Root for holding a function across async boundaries.
To export functions with plain Rust types instead of FunctionContext, see the Export Functions SOP and the #[neon::export] macro.