rhaiscript/rhai
63.3
Adequate · 29 September 2026
72.9k
lines of production code
Rust
primary language
2
measurements over time
What this system is
Rhai is an embedded scripting engine for Rust that executes scripts via a traditional AST walker or a new, memory-efficient Grain bytecode virtual machine. It provides a comprehensive API for registering custom Rust types and functions, supporting both procedural macros and manual builders for seamless integration. The system includes tooling for compiling, debugging, and running scripts, along with robust features for serialization, fuzzing, and static analysis.
How it got here
2016–2020 — Core engine development and modularization
16 changes.
This period established the Rhai scripting engine's foundational architecture, introducing the Grain bytecode VM, a modular plugin system, and comprehensive procedural macro support for Rust integration. It expanded the project's capabilities with serde serialization, no\_std compatibility, and a flexible module resolution API, while simultaneously building out a robust suite of tests, benchmarks, and CLI tools to ensure performance and usability.
2021–2022 — Engine refactoring and API expansion
13 changes.
This period focused on a comprehensive architectural overhaul of the Rhai engine, restructuring the AST, evaluation logic, and type systems into modular components to improve performance and maintainability. Concurrently, the project expanded its public API by introducing a new TypeBuilder for custom type registration and a definitions API for generating script metadata. These core improvements were complemented by new examples demonstrating state management patterns and operator definitions.
2023–2026 — Grain bytecode VM implementation
10 changes.
This period focused on introducing the Grain bytecode virtual machine, which compiles Rhai scripts into a compact, portable binary format to reduce memory overhead and improve execution speed. The work involved building the compiler backend, the VM runtime with callback support, and the serialization format, while ensuring correctness through extensive differential testing and fuzzing against the existing AST-based interpreter.
Features
Add JS-style event handler example with state management
A new example demonstrating the event handler with state pattern in a JavaScript-like style has been added. The Rust main program loads a Rhai script, initializes a custom scope with constants, and manages state via an object map bound to the script's 'this' context. The accompanying script defines an initialization function and handlers for 'start', 'end', and 'update' events, illustrating how to maintain persistent state and handle conditional logic within the Rhai engine.
_examples/event\_handler\js · high confidence
Add Rhai language definitions for built-in operators and functions
The \examples/definitions/.rhai/definitions\ directory now includes example definition files that specify the signatures for Rhai's built-in operators and functions. These new \.d.rhai\ files define operator overloads for arithmetic, comparison, and bitwise operations across integer, float, decimal, string, and boolean types, as well as function signatures for core utilities like \print\, \debug\, \type\_of\, \eval\, and \contains\. This provides a reference for the available language features within the Rhai scripting context.
examples/definitions/.rhai/definitions · high confidence
Add Rhai scripting examples and documentation
The \scripts\ directory now contains a comprehensive suite of Rhai example scripts and a README. The README provides instructions for installing the \rhai-run\ tool and running scripts. The examples cover core language features including variables, operators, control flow (if, switch, loops), functions, modules, object-oriented patterns, string manipulation, arrays, and performance benchmarks (fibonacci, primes, matrix multiplication).
scripts · high confidence
Add bare-bones no\_std test application
A new \no\_std\ test application has been added to the \no\_std/no\_std\_test\ directory. This bare-bones example demonstrates how to integrate the Rhai engine in a \no\_std\ environment by evaluating a simple expression (\40 + 2\) and returning the result. It includes necessary configurations for memory allocation using \wee\_alloc\, custom panic and allocation error handlers, and platform-specific link settings for Windows MSVC to ensure compatibility across different build targets.
_no\_std/no\_std\test · high confidence
Add event handler example using a map for state management
Added a new example demonstrating the 'Event Handler With State Pattern' using a map style. This example shows how to use a custom scope and an object map to hold state variables, allowing scripts to initialize, update, and access persistent state across multiple event calls.
_examples/event\_handler\map · high confidence
Add event handler example with state management
Added a new example demonstrating the event handler pattern with state persistence. The Rust main program loads a Rhai script, initializes a custom scope with constants, and runs an 'init' function to set up state. It then enters a loop to process events (start, end, update, scope, quit) by calling corresponding functions in the script, allowing the script to maintain and modify state across invocations.
_examples/event\_handler\main · high confidence
Add serde serialization and deserialization support for Dynamic and Scope
This change introduces a new \serde\ feature that enables converting Rhai's \Dynamic\ values to and from standard Rust types using the \serde\ crate. Users can now use \rhai::serde::to\_dynamic\ to serialize Rust structs into Rhai's dynamic type system and \rhai::serde::from\_dynamic\ to deserialize them back. The implementation also adds serialization support for the \Scope\ type, allowing engine state to be serialized, and includes metadata serialization for function signatures and custom types.
src/serde · high confidence
Initial source code release of the Rhai scripting engine
This entry introduces the core source code for the Rhai scripting engine, establishing the project's initial structure and functionality. The codebase includes the main engine implementation, a tokenizer, parser, and optimizer, along with utilities for deferred resource cleanup and type reification. It provides a comprehensive set of unit tests to verify critical data structure sizes across different architectures and feature configurations, ensuring memory efficiency. The release also includes a detailed README documenting the source file layout and sub-directories, covering modules for configuration, types, public API, AST, modules, packages, function handling, evaluation, serialization, and the Grain bytecode VM.
src · high confidence
Introduce Grain bytecode VM with new instruction set and execution model
The \src/grain/bytecode\ module introduces a new bytecode virtual machine for the Grain language, replacing the previous execution model. This change adds a new instruction set defined in \code.rs\ and \op.rs\, including opcodes for local variable management, function calls, property access, and control flow. It implements a chain-walking mechanism for member access (\chain.rs\) and a hash-based dispatch table for \switch\ statements (\switch.rs\). The VM supports optimized stack usage via \Chunk\ metadata (\chunk.rs\), improved error reporting with position tables (\positions.rs\), and efficient string handling via a shared blob (\strings.rs\). The verifier (\verify.rs\) ensures bytecode integrity, including capability checks and stack depth validation. This foundational change enables faster script execution and better debugging support.
src/grain/bytecode · high confidence
Introduce Rhai Grain bytecode VM
Added a new \grain\ module that compiles Rhai scripts into a flat bytecode instruction stream, enabling execution via a dedicated VM without retaining the original AST. This allows scripts to be serialized and loaded on devices that lack a parser or interpreter, significantly reducing memory overhead. The implementation includes a compiler, a VM, and a position table system for error reporting, with support for stripping positions to minimize artifact size.
src/grain · high confidence
Introduce Rhai Grain bytecode format for portable, stripped program artifacts
The \src/grain/format\ module now defines a new on-the-wire bytecode format (version 11) that serializes Rhai programs into a compact binary representation. This allows scripts to be loaded and executed by a VM without parsing source or building an AST, significantly reducing memory overhead and startup time. The format includes an ABI layer that checks for capability mismatches (such as missing features like \no\_float\ or \no\_module\) and data width differences to prevent loading incompatible artifacts. It also supports stripping debug information (position tables) into a separate 'sidecar' to reduce artifact size while retaining the ability to resolve error locations on the host. The format uses a magic header ('RGRN'), LEB128 encoding for metadata, and verbatim bytecode for the code section, ensuring efficient dispatch and minimal allocation during loading.
src/grain/format · high confidence
Introduction of module namespace and function metadata APIs
This change introduces the \FnNamespace\ enum and \FuncMetadata\ struct to the module system, allowing functions to be explicitly registered in either the module's internal namespace or the global namespace. It also adds the \Namespace\ type to handle qualified name resolution chains for variables and functions. These additions enable more granular control over function visibility and provide detailed metadata (such as signatures, parameter types, and return types) for registered functions, which is essential for features like documentation generation and introspection.
src/module · high confidence
New Grain bytecode compiler for switch ranges and constant pooling
The \src/grain/compile\ module introduces a new compiler backend that lowers AST nodes into Grain bytecode. It implements a dispatch table for \switch\ statements to correctly handle overlapping range arms by splitting them into disjoint intervals, and adds a constant pool mechanism that determines which values (such as integers, strings, arrays, and function pointers) can be safely serialized and reused across programs. The compiler also manages local variable slots to mirror Rhai's scope behavior, including shadowing and block exit unwinding.
src/grain/compile · high confidence
New Rhai definition files for static operators and module structures
Added new Rhai definition files (\all\_in\_one.d.rhai\, \all\_in\_one\_without\_standard.d.rhai\, and \defs.json\) that establish static operator overloads for primitive types (int, float, Decimal, String, Blob, Range) and define module structures with constants and functions. These files provide the foundational type definitions and operator signatures required for the Rhai engine's static analysis and module resolution, including a specific \general\_kenobi\ module example.
examples/definitions/.rhai · high confidence
New TypeBuilder API for registering custom types
The engine now exposes a \TypeBuilder\ trait and builder pattern for registering custom Rust types. Users can implement the \CustomType\ trait to define constructors, methods, getters, setters, and display/debug hooks, then register the type via \Engine::build\_type\. This replaces the previous manual registration approach and is supported by a new \deprecated.rs\ module that marks older registration methods for removal.
src/api · high confidence
New and updated example applications
The examples directory now includes a comprehensive set of sample applications demonstrating core Rhai capabilities, including a new README index. New examples cover registering Rust types with arrays and structs, using the \CustomType\ derive macro for automatic registration, handling callbacks via closures, and serializing/deserializing Rust types with \serde\. Additional samples illustrate string handling, function registration, and advanced threading patterns such as duplex communication and pausing/resuming execution via MPSC channels. The collection also features a benchmark (\grain\_bench\) comparing the new Bytecode VM against the walker, and demonstrates scope reuse across multiple script runs.
examples · high confidence
New command-line tools for compiling, debugging, and running Rhai scripts
The \src/bin\ directory now includes dedicated CLI tools: \rhai-run\ executes Rhai scripts or Grain bytecodes (\.rgrn\), \rhai-repl\ provides an interactive read-eval-print loop with history and key bindings, \rhai-dbg\ offers a debugger with breakpoints and step controls, and \grain-compile\/\grain-dump\ handle compiling scripts to and disassembling Grain bytecodes. These tools are gated by specific features (e.g., \grain\, \debugging\, \rustyline\) and can be installed together via the \bin-features\ meta-feature.
src/bin · high confidence
New definitions API for generating Rhai script metadata
The \src/api/definitions\ module now provides a programmatic way to generate \.rhai\ definition files for the engine and its scope. Users can call \Engine::definitions()\ or \Engine::definitions\_with\_scope()\ to obtain a \Definitions\ helper, which supports configuring whether to include standard packages and module headers. The helper can write these definitions to a directory (\write\_to\_dir\) or a single file (\write\_to\_file\), or return them as a string (\single\_file\). This feature is gated behind the \internals\ and \metadata\ features and is not available in \no\_std\ or WASM environments without stdio.
src/api/definitions · high confidence
New definitions example demonstrating scope and module export generation
Added an example in examples/definitions that demonstrates how to register a custom module (general\_kenobi), scope variables, constants, and custom operators in a Rhai engine, and then generate corresponding definitions. The example shows writing definitions to a directory, exporting all definitions to a single file, optionally excluding standard packages, and generating a JSON representation of function definitions.
examples/definitions · high confidence
New fuzzing harnesses for the Rhai engine and bytecode VM
Added a suite of fuzzing targets in the \fuzz\ directory to improve stability and security of the Rhai scripting engine. The \ast\ and \scripting\ targets exercise the parser, compiler, and interpreter with arbitrary scripts and engine configurations, while \fuzz\_serde\ validates serialization round-trips. New targets \grain\_roundtrip\ and \grain\_generated\ verify that the new bytecode VM (introduced in commit \#1109) produces results consistent with the AST walker, and \load\ ensures that untrusted bytecode artifacts are safe to execute. A dictionary of Rhai keywords is also included to guide the fuzzer.
fuzz · high confidence
New module resolver API with collection and static resolvers
The module resolution system has been restructured into a new \module\_resolvers\ module, introducing a \ModuleResolver\ trait and several concrete implementations. Users can now use \ModuleResolversCollection\ to chain multiple resolvers in sequential order, allowing fallback logic (e.g., try file system, then static). A \StaticModuleResolver\ is provided for loading modules from an in-memory map, and a \FileModuleResolver\ handles loading scripts from the file system with configurable base paths, extensions, and caching. A \DummyModuleResolver\ is also available for disabling resolution. This change replaces the previous single-resolver model with a more flexible, composable approach.
src/module/resolvers · high confidence
New procedural macro crate for Rhai plugin modules
A new \codegen\ crate has been introduced to simplify the creation of Rhai plugin modules. It provides the \\#\[export\_module\]\ attribute macro to convert Rust modules into Rhai modules, the \\#\[rhai\_fn\]\ attribute for individual plugin functions (supporting parameters like \pure\, \global\, \internal\, and \index\_get\/\index\_set\), and a \CustomType\ derive macro for exposing Rust structs to Rhai. The crate also includes the \exported\_module!\ macro to generate the module and \combine\_with\_exported\_module!\ to merge plugin modules into existing ones, with optional documentation metadata support via the \metadata\ feature.
codegen/src · high confidence
Architecture
AST structure refactored into separate modules
The Abstract Syntax Tree (AST) implementation has been reorganized from a single monolithic file into separate modules (\ast.rs\, \expr.rs\, \stmt.rs\, \flags.rs\). This change splits the definition of script expressions (\Expr\), statements (\Stmt\), and AST flags (\ASTFlags\) into their own files to improve code maintainability and readability, while preserving the existing public API and functionality for users.
src/ast · high confidence
Introduce internal type modules for core data structures
The \src/types\ module has been restructured into distinct sub-modules (\bloom\_filter\, \custom\_types\, \dynamic\, \error\, \float\, \fn\_ptr\, \ident\, \immutable\_string\, \interner\, \parse\_error\, \position\, \scope\, \token\, \var\_def\, \variant\) to organize the engine's core data types. This change introduces a new \BloomFilterU64\ for optimizing string interning by avoiding cache pollution from one-hit wonders, refactors \CustomTypeInfo\ and \CustomTypesCollection\ to support doc-comment metadata, and reorganizes the \Dynamic\ union and \EvalAltResult\ error types for better clarity and feature-gate management.
src/types · high confidence
Standard library functions moved into modular packages
The standard library has been restructured from a monolithic implementation into distinct, feature-gated packages (e.g., \BasicArrayPackage\, \BasicBlobPackage\, \LogicPackage\). This change introduces a modular plugin architecture where core functions are now registered via \def\_package!\ and \combine\_with\_exported\_module!\ macros. Users benefit from finer control over the engine's footprint, as many standard capabilities can now be disabled via features like \no\_index\, \no\_object\, or \no\_function\, and the new structure supports better separation of concerns for built-in types like Arrays, Maps, Blobs, and BitFields.
src/packages · high confidence
Behavioural changes
Introduce bytecode VM with Rhai callback support
The Grain language runtime now executes compiled bytecode via a new VM implementation in \src/grain/vm\, replacing the previous AST-based interpreter. This change introduces a \callback.rs\ module that registers Grain functions as native wrappers within Rhai, enabling seamless interoperability where Rhai can invoke Grain code and Grain can call back into Rhai. The VM handles chain resolution, scoping, and function calls directly through opcodes, providing a more efficient execution model for Grain programs.
src/grain/vm · high confidence
Introduce configurable hashing seed for stable hashing
Users can now configure the hashing seed used for stable hashing in Rhai via the new \rhai::config::hashing\ module. The \set\_hashing\_seed\ function allows setting a custom seed at runtime (once, before any Rhai operations), while the \RHAI\_HASHING\_SEED\ environment variable enables compile-time configuration. If no seed is provided, the hashing seed is randomized to protect against DoS attacks. This change replaces the previous \ahash\_seed\ naming with \hashing\_seed\ and introduces a new \no\_ast\ feature flag.
src/config · high confidence
Major refactoring of the function execution engine and built-in operators
The function execution subsystem has been significantly restructured to improve performance and code organization. Built-in binary operators (such as arithmetic and comparison) are now implemented directly in the engine via optimized macros in \builtin.rs\, bypassing the overhead of registered function calls. The function call mechanism has been rewritten to use pre-calculated \FnCallHashes\ for faster resolution of both native and script-defined functions. Additionally, the \FuncArgs\ trait has been expanded to support \SmallVec\ and arrays, allowing more efficient argument passing, and the \NativeCallContext\ has been refined to include function source information and improved encapsulated environment handling.
src/func · high confidence
Refactor evaluation engine into modular sub-components
The evaluation logic in \src/eval\ has been reorganized into distinct modules (\cache\, \chaining\, \data\_check\, \debugger\, \eval\_context\, \expr\, \global\_state\, \indexing\, \stmt\, \switch\, \target\) to improve code structure and maintainability. This change introduces a new \Caches\ system for function resolution caching with bloom filters, expands the debugging interface with support for property breakpoints and function exit/enter events, and adds data size validation checks for arrays, maps, and strings to prevent excessive memory usage during script execution.
src/eval · high confidence
Rhai 1.4.0 release: new documentation, build infrastructure, and dependency updates
This release introduces the 1.4.0 version of the Rhai embedded scripting engine. The update includes a comprehensive rewrite of the README to highlight new features such as the Grain bytecode VM, WASM support, and \no-std\ compatibility, alongside updated badges and links. A new \AGENTS.md\ file provides architectural guidance and coding standards for contributors. The build system has been updated to use a \build.template\ and \build.rs\ script to generate a hashing seed configuration file, and the \Cargo.msrv.lock\ file has been added to pin the Minimum Supported Rust Version (MSRV) dependencies. Additionally, \.gitattributes\ and \.gitignore\ files have been added to configure language detection for \.rhai\ files and manage build artifacts.
(repo-wide) · high confidence
Test coverage
Add micro-benchmark suite for Rhai engine performance; Added UI tests for codegen attribute validation and diagnostics; Added comprehensive test coverage for codegen features; Added corpus tests to verify VM consistency with Rhai; Added test coverage for the Grain bytecode VM; Added test fixtures for Grain script validation; Added tests for custom root type and module registration; Added unit tests for codegen custom types, functions, and modules; Expanded test coverage for core language features.
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
How this codebase got here
Score
- CAI 56 → 63 (+7.7)
- Rubric changed (rubric-2026.09.10 → rubric-2026.09.18) — scores are not directly comparable.
Lenses
- Code Health 78 → 77 (-0.1)
- Architecture 98 → 92 (-5.8)
- Maturity 58 → 65 (+6.4)
- Readiness 74 → 70 (-3.3)
- Security 39 → 54 (+15.3)
- Performance 90 (new)
Resolved (17)
- Change coupling: mod.rs ↔ read.rs (src/grain/compile/mod.rs)
- Change coupling: verify.rs ↔ mod.rs (src/grain/bytecode/verify.rs)
- Change coupling: verify.rs ↔ mod.rs (src/grain/bytecode/verify.rs)
- Documentation: no licence statement (README.md)
- Duplicated block (12 lines × 2) (src/grain/compile/mod.rs)
- Duplicated block (12 lines × 2) (src/grain/vm/mod.rs)
- Duplicated block (16 lines × 2) (src/eval/eval_context.rs)
- Duplicated block (8 lines × 2) (src/grain/vm/mod.rs)
- Engine::eval_op_assignment (cognitive 35) (src/eval/stmt.rs)
- Engine::eval_op_assignment (cyclomatic 39) (src/eval/stmt.rs)
- FnPtr::call_raw (cognitive 18) (src/types/fn_ptr.rs)
- Hotspot: src/eval/chaining.rs (src/eval/chaining.rs)
- Hotspot: src/eval/expr.rs (src/eval/expr.rs)
- Hotspot: src/eval/indexing.rs (src/eval/indexing.rs)
- Hotspot: src/packages/array_basic.rs (src/packages/array_basic.rs)
- Hotspot: src/types/dynamic.rs (src/types/dynamic.rs)
- Members sharing a duplicated core (4 members, 50+ identical tokens) (src/func/native.rs)
New (24)
- Change coupling: verify.rs ↔ mod.rs (src/grain/bytecode/verify.rs)
- Change coupling: verify.rs ↔ mod.rs (src/grain/bytecode/verify.rs)
- Dependency hygiene PARTLY measured — Cargo dependencies read, no committed lock to grade for currency
- Duplicated block (10 lines × 2) (src/grain/bytecode/op.rs)
- Duplicated block (10 lines × 2) (src/grain/compile/mod.rs)
- Duplicated block (12–14 lines × 2) (src/grain/vm/mod.rs)
- Duplicated block (5 lines × 2) (src/func/native.rs)
- Duplicated block (7 lines × 2) (src/grain/vm/mod.rs)
- Engine::eval_fn_call_expr (cognitive 30) (src/func/call.rs)
- Engine::eval_fn_call_expr (cyclomatic 16) (src/func/call.rs)
- Excessive duplication of execution methods with nearly identical semantics. consume, eval, and run appear to execute scripts/ASTs. The distinction between them is not immediately obvious from the signatures (e.g., does consume store it? does eval return a value? does run just execute?). Having three verbs for essentially the same action (executing code) creates cognitive load.
- FileTooLong: func/native.rs (src/func/native.rs)
- FnPtr::_call_raw (cognitive 19) (src/types/fn_ptr.rs)
- Fragmented function registration on Module. There are specific methods for getters, setters, indexers, and generic functions, plus a raw variant. This duplicates the logic found in Engine and TypeBuilder but with even more variation. set_fn vs set_native_fn is unclear.
- Hotspot: src/grain/bytecode/op.rs (src/grain/bytecode/op.rs)
- Inconsistent naming and grouping for compilation methods. compile takes a script string, compile_file takes a path, compile_expression takes a string but implies a different AST structure. The _with_scope variants are repetitive. compile_into_self_contained is an outlier in naming convention.
- Inconsistent type registration API. register_type takes no arguments (likely inferring name), register_type_with_name takes a string name, and register_type_with_name_raw takes identifiers. Meanwhile, build_type returns a builder for complex definitions. The existence of three distinct methods for simple type registration with slight signature variations is confusing.
- Low cohesion: DynamicSerializer (LCOM4 14) (src/serde/ser.rs)
- Low cohesion: ImmutableString (LCOM4 12) (src/types/immutable_string.rs)
- Members sharing a duplicated core (4 members, 50+ identical tokens) (src/func/native.rs)
- …and 4 more
Changes since last survey
- 38 commits — 28 feature/other, 10 fixes
By area
- src/grain — 13 commits
- (repo) — 10 commits
- (root) — 8 commits
- src/bin — 2 commits
- src/eval — 2 commits
- src/api — 1 commit
- src/func — 1 commit
- tests/grain — 1 commit
Notable commits
- fix: Fix VM bug in call!(fnptr, args...) syntax.
- fix: Fix bug in VM and accept call/curry methods anywhere in a chain.
- fix: Fix bug in VM: is_shared
- fix: Fix bug in loop lowering.
- fix: Fix errors under no_ast.
- fix: Fix feature gate
- fix: Fix feature gating
- fix: Fix missing verify on switch statement constants.
- fix: Fix no_ast build: remove misplaced feature gate in formatting.rs
- fix: Merge branch 'fix'
- change: Add AGENTS.md
- change: Avoid cloning GlobalRuntimeState unnecessarily.
- change: Clean up docs.
- change: Gate compact_str behind an opt-in compact_str feature.
- change: Leave switch subject on stack and avoid putting it into scope.
- change: Lower NOOP instead of fragment.
- change: Merge branch 'main' of https://github.com/rhaiscript/rhai
- change: Merge pull request #1163 from rhaiscript/vm-speed-up-chaining-assign
- change: Merge pull request #1164 from rhaiscript/vm-revise-walk-property
- change: Merge pull request #1165 from rhaiscript/vm-optimize-switch
- …and 18 more
Written by watchdog.canine.dev from the codebase's own history, inside the signed delivery this page is composed from.
Survey your own repository
rhaiscript/rhai was measured the same way every project in this corpus was: the same rubric, at a pinned commit, with the result published in full. Point a surveyor at a repository you know and see whether you agree with it.
About this page
- The score is its most recent published measurement, taken on 29 September 2026 at a pinned commit. It is not a live figure and does not change until the project is measured again.
- Measured at commit 8bd31196553f877f3c266447cf26923a1528bf16 — the exact code this score is about.
- Scored under rubric-2026.09.18 — the same rubric and the same method as every other entry in this index.
- Measured by watchdog.canine.dev using codehealth-analyzer preprod-5ff527f25b99.