Export a Rust Function to Rhai

Sometimes only a few ad hoc functions are required and it is simpler to register individual functions instead of a full-blown plugin module.

Macros

MacroSignatureDescription
#[export_fn]apply to Rust function defined in a Rust moduleexports the function
register_exported_fn!register_exported_fn!(&mut engine, "name", function)registers the function into an Engine under a specific name
set_exported_fn!set_exported_fn!(&mut module, "name", function)registers the function into a Module under a specific name
set_exported_global_fn!set_exported_global_fn!(&mut module, "name", function)registers the function into a Module under a specific name, exposing it to the global namespace

#[export_fn] and register_exported_fn!

Tip: NativeCallContext parameter

The first parameter of a function can also be NativeCallContext.

Apply #[export_fn] onto a function defined at Rust module level to convert it into a Rhai plugin function.

To register the plugin function, simply call register_exported_fn!.

Global scope only

The function cannot be nested inside another function – it can only be defined directly under a Rust module.

Tip: Overloading

The name of the function can be any text string, so it is possible to register overloaded functions as well as operators.

use rhai::plugin::*;        // import macros

#[export_fn]
fn increment(num: &mut i64) {
    *num += 1;
}

fn main() {
    let mut engine = Engine::new();

    // 'register_exported_fn!' registers the function as 'inc' with the Engine.
    register_exported_fn!(engine, "inc", increment);
}

Pure Functions

Some functions are pure – i.e. they do not mutate any parameter, even though the first parameter may be passed in as &mut (e.g. for a method function).

This is often done to avoid expensive cloning for methods or property getters that return information about a custom type and does not modify it.

Apply the #[export_fn(pure)] attribute on a plugin function to mark it as pure.

Must not modify &mut parameter

Pure functions MUST NOT modify the &mut parameter. There is no checking.

Error: Constants Not OK for non-pure

Non-pure functions raise a runtime error when passed a constant value as the first &mut parameter.

Tip: Constants OK for pure

Pure functions can be passed a constant value as the first &mut parameter.

use rhai::plugin::*;        // a "prelude" import for macros

// This method is pure, so 'len' can be used on a constant 'TestStruct'.
#[export_fn(pure)]
pub fn len(my_type: &mut TestStruct) -> i64 {
    my_type.len()
}

// This method is not pure, so 'clear' will raise an error
// when used on a constant 'TestStruct'.
#[export_fn]
pub fn clear(my_type: &mut TestStruct) {
    my_type.clear();
}

Fallible Functions

To register fallible functions (i.e. functions that may return errors), apply the #[export_fn(return_raw)] attribute on plugin functions that return Result<T, Box<EvalAltResult>> where T is any clonable type.

use rhai::plugin::*;        // a "prelude" import for macros

#[export_fn(return_raw)]
pub fn double_and_divide(x: i64, y: i64) -> Result<i64, Box<EvalAltResult>> {
    if y == 0 {
        Err("Division by zero!".into())
    } else {
        Ok((x * 2) / y)
    }
}

fn main() {
    let mut engine = Engine::new();

    // Overloads the operator '+' with the Engine.
    register_exported_fn!(engine, "+", double_and_divide);
}

Missing #[rhai_fn(return_raw)]

A compilation error — usually something that says Result does not implement Clone — is generated if a fallible function is missing #[rhai_fn(return_raw)].

It is another compilation error for the reverse — a function with #[rhai_fn(return_raw)] does not have the appropriate return type.