### Error Handling in Dynamic Functions When working with the dynamic function signature, error handling is slightly different: ```rust fn dynamic_function(ctx: NativeCallContext, args: &mut [&mut Dynamic]) -> Result> { // Get the position information from the context let pos = ctx.position(); // Validate arguments if args.len() < 2 { return Err(Box::new(EvalAltResult::ErrorRuntime( format!("Expected at least 2 arguments, got {}", args.len()), pos ))); } // Try to convert arguments with proper error handling let arg1 = match args[0].as_int() { Ok(val) => val, Err(_) => return Err(Box::new(EvalAltResult::ErrorMismatchOutputType( "Expected first argument to be an integer".into(), pos, "i64".into() ))) }; // Process with error handling if arg1 <= 0 { return Err(Box::new(EvalAltResult::ErrorRuntime( "First argument must be positive".into(), pos ))); } // Return success Ok(Dynamic::from(arg1 * 2)) } ``` ## Advanced Patterns ### Working with Function Pointers You can create function pointers that bind to Rust functions: ```rust fn my_awesome_fn(ctx: NativeCallContext, args: &mut[&mut Dynamic]) -> Result> { // Check number of arguments if args.len() != 2 { return Err("one argument is required, plus the object".into()); } // Get call arguments let x = args[1].try_cast::().map_err(|_| "argument must be an integer".into())?; // Get mutable reference to the object map, which is passed as the first argument let map = &mut *args[0].as_map_mut().map_err(|_| "object must be a map".into())?; // Do something awesome here ... let result = x * 2; Ok(result.into()) } // Register a function to create a pre-defined object engine.register_fn("create_awesome_object", || { // Use an object map as base let mut map = Map::new(); // Create a function pointer that binds to 'my_awesome_fn' let fp = FnPtr::from_fn("awesome", my_awesome_fn)?; // ^ name of method // ^ native function // Store the function pointer in the object map map.insert("awesome".into(), fp.into()); Ok(Dynamic::from_map(map)) }); ``` ### Creating Rust Closures from Rhai Functions You can encapsulate a Rhai script as a Rust closure: ```rust use rhai::{Engine, Func}; let engine = Engine::new(); let script = "fn calc(x, y) { x + y.len < 42 }"; // Create a Rust closure from a Rhai function let func = Func::<(i64, &str), bool>::create_from_script( engine, // the 'Engine' is consumed into the closure script, // the script "calc" // the entry-point function name )?; // Call the closure let result = func(123, "hello")?; // Pass it as a callback to another function schedule_callback(func); ``` ### Calling Rhai Functions from Rust You can call Rhai functions from Rust: ```rust // Compile the script to AST let ast = engine.compile(script)?; // Create a custom 'Scope' let mut scope = Scope::new(); // Add variables to the scope scope.push("my_var", 42_i64); scope.push("my_string", "hello, world!"); scope.push_constant("MY_CONST", true); // Call a function defined in the script let result = engine.call_fn::(&mut scope, &ast, "hello", ("abc", 123_i64))?; // For a function with one parameter, use a tuple with a trailing comma let result = engine.call_fn::(&mut scope, &ast, "hello", (123_i64,))?; // For a function with no parameters let result = engine.call_fn::(&mut scope, &ast, "hello", ())?; ```