//! # Rhailib Engine //! //! The central Rhai scripting engine for the heromodels ecosystem. This crate provides //! a unified interface for creating, configuring, and executing Rhai scripts with access //! to all business domain modules. //! //! ## Features //! //! - **Unified Engine Creation**: Pre-configured Rhai engine with all DSL modules //! - **Script Execution Utilities**: Direct evaluation, file-based execution, and AST compilation //! - **Mock Database System**: Complete testing environment with seeded data //! - **Feature-Based Architecture**: Modular compilation based on required domains //! //! ## Quick Start //! //! ```rust //! use rhailib_engine::{create_heromodels_engine, eval_script}; //! //! // Create a fully configured engine //! let engine = create_heromodels_engine(); //! //! // Execute a business logic script //! let result = eval_script(&engine, r#" //! let company = new_company() //! .name("Acme Corp") //! .business_type("global"); //! company.name //! "#)?; //! //! println!("Company name: {}", result.as_string().unwrap()); //! ``` //! //! ## Available Features //! //! - `calendar` (default): Calendar and event management //! - `finance` (default): Financial accounts, assets, and marketplace //! - `flow`: Workflow and approval processes //! - `legal`: Contract and legal document management //! - `projects`: Project and task management //! - `biz`: Business operations and entities use rhai::{Engine, EvalAltResult, Scope, AST}; use rhailib_dsl; use std::fs; use std::path::Path; /// Mock database module for testing and examples pub mod mock_db; /// Creates a fully configured Rhai engine with all available DSL modules. /// /// This function creates a new Rhai engine instance, configures it with appropriate /// limits and settings, and registers all available business domain modules based /// on enabled features. /// /// # Engine Configuration /// /// The engine is configured with the following limits: /// - **Expression Depth**: 128 levels for both expressions and functions /// - **String Size**: 10 MB maximum /// - **Array Size**: 10,000 elements maximum /// - **Map Size**: 10,000 key-value pairs maximum /// /// # Registered Modules /// /// All enabled DSL modules are automatically registered, including: /// - Business operations (companies, products, sales, shareholders) /// - Financial models (accounts, assets, marketplace) /// - Content management (collections, images, PDFs, books) /// - Workflow management (flows, steps, signatures) /// - And more based on enabled features /// /// # Returns /// /// A fully configured `Engine` instance ready for script execution. /// /// # Example /// /// ```rust /// use rhailib_engine::create_heromodels_engine; /// /// let engine = create_heromodels_engine(); /// /// // Engine is now ready to execute scripts with access to all DSL functions /// let result = engine.eval::(r#" /// let company = new_company().name("Test Corp"); /// company.name /// "#).unwrap(); /// assert_eq!(result, "Test Corp"); /// ``` pub fn create_heromodels_engine() -> Engine { let mut engine = Engine::new(); // Configure engine settings engine.set_max_expr_depths(128, 128); engine.set_max_string_size(10 * 1024 * 1024); // 10 MB engine.set_max_array_size(10 * 1024); // 10K elements engine.set_max_map_size(10 * 1024); // 10K elements // Register all heromodels Rhai modules rhailib_dsl::register_dsl_modules(&mut engine); engine } // /// Register all heromodels Rhai modules with the engine // pub fn register_all_modules(engine: &mut Engine, db: Arc) { // // Register the calendar module if the feature is enabled // heromodels::models::access::register_access_rhai_module(engine, db.clone()); // #[cfg(feature = "calendar")] // heromodels::models::calendar::register_calendar_rhai_module(engine, db.clone()); // heromodels::models::contact::register_contact_rhai_module(engine, db.clone()); // heromodels::models::library::register_library_rhai_module(engine, db.clone()); // heromodels::models::circle::register_circle_rhai_module(engine, db.clone()); // // Register the flow module if the feature is enabled // #[cfg(feature = "flow")] // heromodels::models::flow::register_flow_rhai_module(engine, db.clone()); // // // Register the finance module if the feature is enabled // // #[cfg(feature = "finance")] // // heromodels::models::finance::register_finance_rhai_module(engine, db.clone()); // // Register the legal module if the feature is enabled // #[cfg(feature = "legal")] // heromodels::models::legal::register_legal_rhai_module(engine, db.clone()); // // Register the projects module if the feature is enabled // #[cfg(feature = "projects")] // heromodels::models::projects::register_projects_rhai_module(engine, db.clone()); // // Register the biz module if the feature is enabled // #[cfg(feature = "biz")] // heromodels::models::biz::register_biz_rhai_module(engine, db.clone()); // println!("Heromodels Rhai modules registered successfully."); // } /// Evaluates a Rhai script string and returns the result. /// /// This function provides a convenient way to execute Rhai script strings directly /// using the provided engine. It's suitable for one-off script execution or when /// the script content is dynamically generated. /// /// # Arguments /// /// * `engine` - The Rhai engine to use for script execution /// * `script` - The Rhai script content as a string /// /// # Returns /// /// * `Ok(Dynamic)` - The result of script execution /// * `Err(Box)` - Script compilation or execution error /// /// # Example /// /// ```rust /// use rhailib_engine::{create_heromodels_engine, eval_script}; /// /// let engine = create_heromodels_engine(); /// let result = eval_script(&engine, r#" /// let x = 42; /// let y = 8; /// x + y /// "#)?; /// assert_eq!(result.as_int().unwrap(), 50); /// ``` pub fn eval_script( engine: &Engine, script: &str, ) -> Result> { engine.eval::(script) } /// Evaluates a Rhai script from a file and returns the result. /// /// This function reads a Rhai script from the filesystem and executes it using /// the provided engine. It handles file reading errors gracefully and provides /// meaningful error messages. /// /// # Arguments /// /// * `engine` - The Rhai engine to use for script execution /// * `file_path` - Path to the Rhai script file /// /// # Returns /// /// * `Ok(Dynamic)` - The result of script execution /// * `Err(Box)` - File reading, compilation, or execution error /// /// # Example /// /// ```rust /// use rhailib_engine::{create_heromodels_engine, eval_file}; /// use std::path::Path; /// /// let engine = create_heromodels_engine(); /// let result = eval_file(&engine, Path::new("scripts/business_logic.rhai"))?; /// println!("Script result: {:?}", result); /// ``` /// /// # Error Handling /// /// File reading errors are converted to Rhai `ErrorSystem` variants with /// descriptive messages including the file path that failed to load. pub fn eval_file( engine: &Engine, file_path: &Path, ) -> Result> { match fs::read_to_string(file_path) { Ok(script_content) => engine.eval::(&script_content), Err(io_err) => Err(Box::new(EvalAltResult::ErrorSystem( format!("Failed to read script file: {}", file_path.display()), Box::new(io_err), ))), } } /// Compiles a Rhai script string into an Abstract Syntax Tree (AST). /// /// This function compiles a Rhai script into an AST that can be executed multiple /// times with different scopes. This is more efficient than re-parsing the script /// for each execution when the same script needs to be run repeatedly. /// /// # Arguments /// /// * `engine` - The Rhai engine to use for compilation /// * `script` - The Rhai script content as a string /// /// # Returns /// /// * `Ok(AST)` - The compiled Abstract Syntax Tree /// * `Err(Box)` - Script compilation error /// /// # Example /// /// ```rust /// use rhailib_engine::{create_heromodels_engine, compile_script, run_ast}; /// use rhai::Scope; /// /// let engine = create_heromodels_engine(); /// let ast = compile_script(&engine, r#" /// let company = new_company().name(company_name); /// save_company(company) /// "#)?; /// /// // Execute the compiled script multiple times with different variables /// let mut scope1 = Scope::new(); /// scope1.push("company_name", "Acme Corp"); /// let result1 = run_ast(&engine, &ast, &mut scope1)?; /// /// let mut scope2 = Scope::new(); /// scope2.push("company_name", "Tech Startup"); /// let result2 = run_ast(&engine, &ast, &mut scope2)?; /// ``` pub fn compile_script(engine: &Engine, script: &str) -> Result> { Ok(engine.compile(script)?) } /// Executes a compiled Rhai script AST with the provided scope. /// /// This function runs a pre-compiled AST using the provided engine and scope. /// The scope can contain variables and functions that will be available to /// the script during execution. /// /// # Arguments /// /// * `engine` - The Rhai engine to use for execution /// * `ast` - The compiled Abstract Syntax Tree to execute /// * `scope` - Mutable scope containing variables and functions for the script /// /// # Returns /// /// * `Ok(Dynamic)` - The result of script execution /// * `Err(Box)` - Script execution error /// /// # Example /// /// ```rust /// use rhailib_engine::{create_heromodels_engine, compile_script, run_ast}; /// use rhai::Scope; /// /// let engine = create_heromodels_engine(); /// let ast = compile_script(&engine, "x + y")?; /// /// let mut scope = Scope::new(); /// scope.push("x", 10_i64); /// scope.push("y", 32_i64); /// /// let result = run_ast(&engine, &ast, &mut scope)?; /// assert_eq!(result.as_int().unwrap(), 42); /// ``` /// /// # Performance Notes /// /// Using compiled ASTs is significantly more efficient than re-parsing scripts /// for repeated execution, especially for complex scripts or when executing /// the same logic with different input parameters. pub fn run_ast( engine: &Engine, ast: &AST, scope: &mut Scope, ) -> Result> { engine.eval_ast_with_scope(scope, ast) }