more efforts to automate rhai bindings

This commit is contained in:
timurgordon
2025-05-13 02:00:35 +03:00
parent 16ad4f5743
commit ec4769a6b0
14 changed files with 3174 additions and 52 deletions

View File

@@ -1,15 +1,23 @@
use rhai_wrapper::wrap_for_rhai;
use rhai_wrapper::{ToRhaiMap, FromRhaiMap};
use rhai::{CustomType, TypeBuilder, Engine, INT, FLOAT, Array};
use rhai_macros_derive::{ToRhaiMap as ToRhaiMapDerive, FromRhaiMap as FromRhaiMapDerive};
use rhai_macros_derive::{ToRhaiMap as ToRhaiMapDerive, FromRhaiMap as FromRhaiMapDerive, export_fn};
#[export_fn(rhai_name = "add_rhai")]
fn add(a: INT, b: INT) -> INT { a + b }
#[export_fn(rhai_name = "mul_rhai")]
fn mul(a: INT, b: INT) -> INT { a * b }
#[export_fn(rhai_name = "greet_rhai")]
fn greet(name: String) -> String { format!("Hello, {name}!") }
#[export_fn(rhai_name = "get_forty_two_rhai")]
fn get_forty_two() -> INT { 42 }
#[export_fn(rhai_name = "shout_rhai")]
fn shout() -> String { "HEY!".to_string() }
#[export_fn(rhai_name = "add_float_rhai")]
fn add_float(a: FLOAT, b: FLOAT) -> FLOAT { a + b }
#[export_fn(rhai_name = "is_even_rhai")]
fn is_even(n: INT) -> bool { n % 2 == 0 }
#[export_fn(rhai_name = "maybe_add_rhai")]
fn maybe_add(a: INT, b: INT, do_add: bool) -> Option<INT> { if do_add { Some(a + b) } else { None } }
// Renamed from sum_vec, takes rhai::Array
@@ -110,69 +118,83 @@ fn get_polygon_id_and_num_vertices(poly: Polygon) -> String {
#[test]
fn test_add() {
let mut engine = Engine::new();
engine.register_fn("add", wrap_for_rhai!(add));
let result = engine.eval::<INT>("add(2, 3)").unwrap();
engine.register_fn("add_rhai", add_rhai_wrapper);
let result = engine.eval::<INT>("add_rhai(2, 3)").unwrap();
assert_eq!(result, 5);
}
#[test]
fn test_mul() {
let mut engine = Engine::new();
engine.register_fn("mul", wrap_for_rhai!(mul));
let result = engine.eval::<INT>("mul(4, 5)").unwrap();
engine.register_fn("mul_rhai", mul_rhai_wrapper);
let result = engine.eval::<INT>("mul_rhai(4, 5)").unwrap();
assert_eq!(result, 20);
}
#[test]
fn test_greet() {
let mut engine = Engine::new();
engine.register_fn("greet", wrap_for_rhai!(greet));
let result = engine.eval::<String>(r#"greet("Alice")"#).unwrap();
engine.register_fn("greet_rhai", greet_rhai_wrapper);
let result = engine.eval::<String>(r#"greet_rhai("Alice")"#).unwrap();
assert_eq!(result, "Hello, Alice!");
}
#[test]
fn test_get_forty_two() {
let mut engine = Engine::new();
engine.register_fn("get_forty_two", wrap_for_rhai!(get_forty_two));
let result = engine.eval::<INT>("get_forty_two()").unwrap();
engine.register_fn("get_forty_two_rhai", get_forty_two_rhai_wrapper);
let result = engine.eval::<INT>("get_forty_two_rhai()").unwrap();
assert_eq!(result, 42);
}
#[test]
fn test_shout() {
let mut engine = Engine::new();
engine.register_fn("shout", wrap_for_rhai!(shout));
let result = engine.eval::<String>("shout()").unwrap();
engine.register_fn("shout_rhai", shout_rhai_wrapper);
let result = engine.eval::<String>("shout_rhai()").unwrap();
assert_eq!(result, "HEY!");
}
#[test]
fn test_add_float() {
let mut engine = Engine::new();
engine.register_fn("add_float", wrap_for_rhai!(add_float));
let result = engine.eval::<FLOAT>("add_float(1.5, 2.25)").unwrap();
assert!((result - 3.75).abs() < 1e-8);
engine.register_fn("add_float_rhai", add_float_rhai_wrapper);
let result = engine.eval::<FLOAT>("add_float_rhai(2.5, 3.5)").unwrap();
assert_eq!(result, 6.0);
}
#[test]
fn test_is_even() {
let mut engine = Engine::new();
engine.register_fn("is_even", wrap_for_rhai!(is_even));
let result = engine.eval::<bool>("is_even(4)").unwrap();
assert!(result);
let result = engine.eval::<bool>("is_even(5)").unwrap();
assert!(!result);
engine.register_fn("is_even_rhai", is_even_rhai_wrapper);
let result_true = engine.eval::<bool>("is_even_rhai(4)").unwrap();
assert_eq!(result_true, true);
let result_false = engine.eval::<bool>("is_even_rhai(3)").unwrap();
assert_eq!(result_false, false);
}
#[test]
fn test_maybe_add() {
let mut engine = Engine::new();
engine.register_fn("maybe_add", wrap_for_rhai!(maybe_add));
let result = engine.eval::<Option<INT>>("maybe_add(2, 3, true)").unwrap();
assert_eq!(result, Some(5));
let result = engine.eval::<Option<INT>>("maybe_add(2, 3, false)").unwrap();
assert_eq!(result, None);
engine.register_fn("maybe_add_rhai", maybe_add_rhai_wrapper);
// Test case where None is returned (expecting an error or specific handling in Rhai)
// Rhai treats Option::None as an empty Dynamic, which can lead to type mismatch if not handled.
// For now, let's check if the script produces a specific type or if it can be evaluated to Dynamic.
// If the function returns None, eval might return an error if trying to cast to INT.
// Let's eval to Dynamic and check if it's empty (Rhai's representation of None).
let result_none = engine.eval::<rhai::Dynamic>("maybe_add_rhai(2, 3, false)").unwrap();
// Debug prints
println!("Debug [test_maybe_add]: result_none = {:?}", result_none);
println!("Debug [test_maybe_add]: result_none.type_name() = {}", result_none.type_name());
println!("Debug [test_maybe_add]: result_none.is::<()>() = {}", result_none.is::<()>());
assert!(result_none.is_unit(), "Expected Rhai None (unit Dynamic)");
// Test case where Some is returned
let result_some = engine.eval::<INT>("maybe_add_rhai(2, 3, true)").unwrap();
assert_eq!(result_some, 5);
}
#[test]
@@ -502,21 +524,20 @@ mod new_export_fn_tests {
assert_eq!(result, 15);
}
// #[test]
// fn test_export_fn_custom_type_arg_return() { // This test was commented out, keeping as is for now
// let mut engine = Engine::new();
// engine.build_type::<Point>();
// // engine.register_fn("offset_simple_point", offset_simple_point_rhai_wrapper);
#[test]
fn test_export_fn_custom_type_arg_return_new() {
let mut engine = Engine::new();
engine.build_type::<Point>();
engine.register_fn("offset_simple_point", offset_simple_point_rhai_wrapper);
// // let script = r#"
// // let p = #{ x: 10, y: 20 };
// // let p_offset = offset_simple_point(p, 5);
// // p_offset.x
// // "#;
// // let result = engine.eval::<INT>(script).unwrap();
// // assert_eq!(result, 15);
// }
let script = r#"
let p = #{ x: 10, y: 20 };
let p_offset = offset_simple_point(p, 5);
p_offset.x
"#;
let result = engine.eval::<INT>(script).unwrap();
assert_eq!(result, 15);
}
#[derive(Debug, Clone, PartialEq, FromRhaiMapDerive, ToRhaiMapDerive, CustomType)]
@@ -556,17 +577,4 @@ mod new_export_fn_tests {
assert_eq!(result_struct.optional_nested_vec.as_ref().unwrap().len(), 1);
assert_eq!(result_struct.optional_nested_vec.as_ref().unwrap()[0], SampleStruct { value: 3, name: "n3".to_string() });
}
#[test]
fn test_export_fn_custom_type_arg_return_new() {
let mut engine = Engine::new();
engine.build_type::<Point>();
engine.register_fn("offset_simple_point", offset_simple_point_rhai_wrapper);
let script = r#"
42
"#;
let result = engine.eval::<INT>(script).unwrap();
assert_eq!(result, 42);
}
}