This repository has been archived on 2025-08-04. You can view files and clone it, but cannot push or open issues or pull requests.
rhaj/rhai_system/README.md
Timur Gordon 372b7a2772 refactor: Overhaul Rhai scripting with multi-file hot reloading
This commit represents a major refactoring of our Rhai scripting system,
transforming it from a factory-based approach to a more robust system-based
architecture with improved hot reloading capabilities.

Key Changes:
- Renamed package from rhai_factory to rhai_system to better reflect its purpose
- Renamed system_factory.rs to factory.rs for consistency and clarity
- Implemented support for multiple script files in hot reloading
- Added cross-script function calls, allowing functions in one script to call functions in another
- Improved file watching to monitor all script files for changes
- Enhanced error handling for script compilation failures
- Simplified the API with a cleaner create_hot_reloadable_system function
- Removed unused modules (error.rs, factory.rs, hot_reload_old.rs, module_cache.rs, relative_resolver.rs)
- Updated all tests to work with the new architecture

The new architecture:
- Uses a System struct that holds references to script paths and provides a clean API
- Compiles and merges multiple Rhai script files into a single AST
- Automatically detects changes to any script file and recompiles them
- Maintains thread safety with proper synchronization primitives
- Provides better error messages when scripts fail to compile

This refactoring aligns with our BasePathModuleResolver approach for module imports,
making the resolution process more predictable and consistent. The hot reload example
has been updated to demonstrate the new capabilities, showing how to:
1. Load and execute multiple script files
2. Watch for changes to these files
3. Automatically reload scripts when they change
4. Call functions across different script files

All tests are passing, and the example demonstrates the improved functionality.
2025-05-02 21:04:33 +02:00

4.5 KiB

Rhai System

A thread-safe system for creating and managing Rhai script engines with hot reloading support for multiple script files.

Overview

Rhai System is a Rust module that simplifies working with the Rhai scripting language by providing a system for creating thread-safe Rhai engines with pre-compiled scripts. It supports hot reloading of multiple script files, ensuring your application always uses the latest version of your scripts without requiring a restart.

Features

  • Thread Safety: Uses Rhai's sync feature to ensure engines are Send + Sync
  • Multiple Script Support: Compiles and merges multiple Rhai script files into a single AST
  • Hot Reload: Automatically detects changes to script files and recompiles them without requiring application restart
  • Cross-Script Function Calls: Functions defined in one script can call functions defined in another script
  • Detailed Error Handling: Provides clear error messages when scripts fail to compile
  • Performance Optimized: Efficiently recompiles only the scripts that have changed

Usage

Basic Usage

use rhai_system::create_hot_reloadable_system;
use std::path::PathBuf;

// Create a hot reloadable system with multiple script files
let script_paths = vec![
    PathBuf::from("scripts/main.rhai"),
    PathBuf::from("scripts/utils.rhai"),
];
let system = create_hot_reloadable_system(&script_paths, None).unwrap();

// Call a function from the script
let result: i64 = system.call_fn("add", (40, 2)).unwrap();
assert_eq!(result, 42);

// The system will automatically reload scripts when they change

Watching for Changes

The system automatically sets up file watchers for all script files:

use rhai_system::create_hot_reloadable_system;
use std::path::PathBuf;
use std::thread;
use std::time::Duration;

// Create a hot reloadable system
let script_paths = vec![PathBuf::from("scripts/main.rhai")];
let system = create_hot_reloadable_system(&script_paths, None).unwrap();

// Start watching for changes to the script files
system.watch();

// The system will now automatically reload scripts when they change
// Your application can continue running and using the latest version of the scripts

Thread-Safe Usage

The system is designed to be thread-safe, allowing you to use it from multiple threads:

use rhai_system::create_hot_reloadable_system;
use std::path::PathBuf;
use std::thread;
use std::sync::Arc;

// Create a hot reloadable system
let script_paths = vec![PathBuf::from("scripts/main.rhai")];
let system = Arc::new(create_hot_reloadable_system(&script_paths, None).unwrap());

// Clone the system for use in another thread
let system_clone = Arc::clone(&system);

// Start watching for changes in the main thread
system.watch();

// Use the system in another thread
let handle = thread::spawn(move || {
    // Create a thread-local clone of the system
    let thread_system = system_clone.clone_for_thread();
    
    // Call functions from the script
    let result: i64 = thread_system.call_fn("add", (40, 2)).unwrap();
    assert_eq!(result, 42);
});

handle.join().unwrap();

Module Resolution

Rhai System supports the BasePathModuleResolver approach for resolving module imports:

  • Uses a single base path for resolving all module imports
  • Makes the resolution process more predictable and consistent
  • Simplifies the Rhai module import system by removing the complexity of relative path resolution

See the examples/base_path_imports directory for a comprehensive example of this approach.

Error Handling

The system provides detailed error information when scripts fail to compile:

use rhai_system::create_hot_reloadable_system;
use std::path::PathBuf;

let script_paths = vec![PathBuf::from("non_existent.rhai")];
let result = create_hot_reloadable_system(&script_paths, None);

match result {
    Err(err) => {
        // Error will contain:
        // - Which script failed to compile
        // - The reason for the failure
        println!("Error: {}", err);
    }
    Ok(_) => panic!("Expected an error"),
}

Testing

The project follows Rust's standard testing approach:

# Run all tests
cargo test

# Run a specific test
cargo test test_hot_reload_callback

Installation

Add this to your Cargo.toml:

[dependencies]
rhai_system = { path = "path/to/rhai_system" }

Examples

See the examples directory for complete examples:

  • hot_reload: Demonstrates hot reloading of multiple script files
  • base_path_imports: Demonstrates the BasePathModuleResolver approach for module imports