rhai_rustler
Elixir NIF bindings for Rhai, a tiny, simple and fast embedded scripting language for Rust that gives you a safe and easy way to add scripting to your applications.
Please refer to The Rhai Book for extended information about the language.
Installation
Add :rhai_rustler
to the list of dependencies in mix.exs
:
def deps do
[
{:rhai_rustler, "~> 1.0.0"}
]
end
Features
rhai_rustler
exposes a subset of the Rhai API to Elixir:
Note that not all the Rhai API features are supported. For instance, advanced and low-level APIs are not exposed.
If any usage patterns become apparent, they will be included in the future.
Please refer to NIF bindings to see the methods supported by the Elixir NIF.
The Elixir NIF provides a way to extend Rhai with external native Rust modules, see: Extending Rhai with external native Rust modules and rhai_dylib for more information.
To check the supported types conversion, see Type conversion table.
Usage patterns
"Hello Rhai"
engine = Rhai.Engine.new()
{:ok, "Hello Rhai!"} = Rhai.Engine.eval(engine, "\"Hello Rhai!\"")
Eval
engine = Rhai.Engine.new()
# Simple evaluation
{:ok, 2} = Rhai.Engine.eval(engine, "1 + 1")
# Evaluation with scope
scope = Rhai.Scope.new() |> Rhai.Scope.push("a", 10) |> Rhai.Scope.push("b", 3)
{:ok, 30} = Rhai.Engine.eval_with_scope(engine, scope, "a * b")
AST
engine = Rhai.Engine.new()
scope = Rhai.Scope.new() |> Rhai.Scope.push_constant("a", 10) |> Rhai.Scope.push_constant("b", 3)
{:ok, %Rhai.AST{} = ast} = Rhai.Engine.compile_with_scope(engine, scope, "a * b")
{:ok, 30} = Rhai.Engine.eval_ast(engine, ast)
# AST can be shared between engines
task = Task.async(fn -> Rhai.Engine.eval_ast(Rhai.Engine.new(), ast) end)
{:ok, 30} = Task.await(task)
Raw Engine
engine = Rhai.Engine.new_raw()
# Returns an error since BasicArrayPackage is not registered
{:error, {:function_not_found, _}} = Rhai.Engine.eval(engine, "[1, 2, 3].find(|x| x > 2)")
# Please refer to https://rhai.rs/book/rust/packages/builtin.html for more information about packages
engine = Rhai.Engine.register_package(engine, :basic_array)
{:ok, 3} = Rhai.Engine.eval(engine, "[1, 2, 3].find(|x| x > 2)")
Extending rhai_rustler with external native Rust modules
rhai_rustler
utilizes the [rhai_dylib](https://github.com/rhaiscript/rhai-dylib)
library to expand the capabilities of Rhai by loading external native Rust modules. This allows users to introduce new functions, custom types, and operators.
test_dylib_module serves as an example of how to create a dylib module. A dummy rustler module is employed to trigger the compilation process. This same approach can be adopted in real-world projects, such as when distributing the dylib module as a Hex package.
Type conversion table
Elixir Types are converted to Rhai types (and back) as follows:
Elixir | Rhai |
---|---|
integer() | Integer |
float() | Float |
float() | Decimal |
bool() | Boolean |
String.t() | String |
String.t() | Char |
list() | Array |
tuple() | Array |
%{ String.t() => Rhai.Any.t() } | Object map |
nil() | Empty |
pid() | Empty (not supported) |
ref() | Empty (not supported) |
fun() | Empty (not supported) |
map() | Empty (not supported) |
Rustler precompiled
By default, you don't need the Rust toolchain installed because the lib will try to download
a precompiled NIF file.
In case you want to force compilation set the
RHAI_RUSTLER_FORCE_BUILD
environment variable to true
or 1
.
Precompiled NIFs are available for the following platforms:
- aarch64-apple-darwin
- x86_64-apple-darwin
- x86_64-unknown-linux-gnu
- x86_64-unknown-linux-musl
- arm-unknown-linux-gnueabihf
- aarch64-unknown-linux-gnu
- aarch64-unknown-linux-musl
- x86_64-pc-windows-msvc
- x86_64-pc-windows-gnu
Release flow
Please follow this guide when releasing a new version of the library.
License
This library is licensed under Apache 2.0 License. See LICENSE for details.
Links
- rhai The Rust crate doing most of the dirty work.
- RustlerPrecompiled Use precompiled NIFs from trusted sources in your Elixir code.
- NimbleLZ4 Major inspiration for the RustlerPrecompiled GitHub actions workflow and general setup.