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.
152 lines
4.5 KiB
Markdown
152 lines
4.5 KiB
Markdown
# 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](https://rhai.rs/) 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
|
|
|
|
```rust
|
|
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:
|
|
|
|
```rust
|
|
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:
|
|
|
|
```rust
|
|
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:
|
|
|
|
```rust
|
|
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:
|
|
|
|
```bash
|
|
# Run all tests
|
|
cargo test
|
|
|
|
# Run a specific test
|
|
cargo test test_hot_reload_callback
|
|
```
|
|
|
|
## Installation
|
|
|
|
Add this to your `Cargo.toml`:
|
|
|
|
```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 |