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.
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 areSend + 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 filesbase_path_imports
: Demonstrates the BasePathModuleResolver approach for module imports