Introduction
Rhai is an embedded scripting language designed for Rust applications. It compiles scripts to an AST evaluated by a tree-walking interpreter and provides a sandboxed execution model with no external dependencies.
What Rhai Does
- Evaluates scripts in a sandbox that blocks file system and network access by default
- Lets Rust functions, closures, and custom types be registered and called from scripts
- Supports dynamic typing, closures, arrays, object maps, and string interpolation
- Provides operator overloading and custom syntax extensions for domain-specific needs
- Compiles scripts to an AST for repeated evaluation without re-parsing
Architecture Overview
Rhai's architecture consists of a lexer, parser, optimizer, and tree-walking evaluator in a single Rust crate with no external dependencies. The Engine struct holds registered functions and configuration. Scripts are parsed into an AST, optionally optimized for constant folding, then evaluated against a Scope holding variable bindings.
Self-Hosting & Configuration
- Add
rhaias a Cargo dependency; no separate runtime binary is needed - Register Rust functions via
engine.register_fn()or procedural macro plugins - Set execution limits for expression depth, statement count, and call stack size
- Toggle language features like looping and closures through Engine configuration
- Use the
no_stdfeature flag for embedded or WebAssembly targets
Key Features
- Zero external dependencies by default, keeping compile times minimal
- Sandboxed execution preventing I/O unless explicitly allowed
- Plugin module system with procedural macros for ergonomic Rust integration
- AST optimization with constant folding and dead-code elimination
- WebAssembly and
no_stdtarget support
Comparison with Similar Tools
- mlua (Lua): Access to the Lua ecosystem and LuaJIT speed, but requires managing a C runtime boundary
- Deno/V8: Full JavaScript runtime with high performance, but much larger dependency and memory footprint
- Gluon: Statically typed with type inference, but smaller community and fewer resources
- Rune: Rust-native with async support, but less mature and smaller user base
FAQ
Q: How does Rhai's performance compare to Lua? A: Rhai uses tree-walking interpretation, so it is slower than LuaJIT for compute-heavy work. It is suited for configuration, rules, and lightweight scripting.
Q: Can I restrict what scripts do? A: Yes, Rhai is sandboxed by default. Scripts cannot access I/O unless you register those capabilities.
Q: Does Rhai support async/await?
A: Not natively, but you can register async Rust functions and use Engine::call_fn_async with Tokio or similar runtimes.
Q: Can Rhai run in WebAssembly?
A: Yes, it compiles to WebAssembly and supports no_std via Cargo feature flags.
Sources
- Repository: https://github.com/rhaiscript/rhai
- Documentation: https://rhai.rs/book/