more efforts to automate rhai bindings
This commit is contained in:
		@@ -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);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										709
									
								
								rhai_wrapper/tests/wrapper_macros_test.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										709
									
								
								rhai_wrapper/tests/wrapper_macros_test.rs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,709 @@
 | 
			
		||||
use rhai::{Engine, INT, FLOAT, Dynamic, Map, Array, EvalAltResult, CustomType, TypeBuilder};
 | 
			
		||||
use rhai_wrapper::{
 | 
			
		||||
    wrap_option_return, wrap_vec_return, wrap_option_vec_return,
 | 
			
		||||
    wrap_option_return_result, wrap_vec_return_result, wrap_option_vec_return_result,
 | 
			
		||||
    wrap_option_method_result, wrap_vec_method_result, wrap_option_vec_method_result,
 | 
			
		||||
    ToRhaiMap, FromRhaiMap
 | 
			
		||||
};
 | 
			
		||||
use rhai_macros_derive::{ToRhaiMap as ToRhaiMapDerive, FromRhaiMap as FromRhaiMapDerive};
 | 
			
		||||
use std::fmt;
 | 
			
		||||
 | 
			
		||||
// Test structs
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, CustomType, ToRhaiMapDerive, FromRhaiMapDerive)]
 | 
			
		||||
struct User {
 | 
			
		||||
    id: INT,
 | 
			
		||||
    name: String,
 | 
			
		||||
    age: INT,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl User {
 | 
			
		||||
    fn to_rhai_map(&self) -> Map {
 | 
			
		||||
        let mut map = Map::new();
 | 
			
		||||
        map.insert("id".into(), self.id.into());
 | 
			
		||||
        map.insert("name".into(), self.name.clone().into());
 | 
			
		||||
        map.insert("age".into(), self.age.into());
 | 
			
		||||
        map
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn from_rhai_map(map: Map) -> Result<Self, String> {
 | 
			
		||||
        let id = map.get("id")
 | 
			
		||||
            .and_then(|d| d.as_int().ok())
 | 
			
		||||
            .ok_or_else(|| "Field 'id' not found or not an INT".to_string())?;
 | 
			
		||||
        
 | 
			
		||||
        let name = map.get("name")
 | 
			
		||||
            .and_then(|d| d.clone().into_string().ok())
 | 
			
		||||
            .ok_or_else(|| "Field 'name' not found or not a String".to_string())?;
 | 
			
		||||
        
 | 
			
		||||
        let age = map.get("age")
 | 
			
		||||
            .and_then(|d| d.as_int().ok())
 | 
			
		||||
            .ok_or_else(|| "Field 'age' not found or not an INT".to_string())?;
 | 
			
		||||
        
 | 
			
		||||
        Ok(User { id, name, age })
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Mock DB connection type
 | 
			
		||||
struct OurDB {
 | 
			
		||||
    // Some mock state
 | 
			
		||||
    error_mode: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl OurDB {
 | 
			
		||||
    fn new(error_mode: bool) -> Self {
 | 
			
		||||
        OurDB { error_mode }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Custom error type for testing
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct DBError {
 | 
			
		||||
    message: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl fmt::Display for DBError {
 | 
			
		||||
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        write!(f, "DB Error: {}", self.message)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Test functions for wrap_option_return
 | 
			
		||||
fn get_user_by_id(_db: &OurDB, id: INT) -> Option<User> {
 | 
			
		||||
    if id > 0 {
 | 
			
		||||
        Some(User { id, name: format!("User {}", id), age: 30 })
 | 
			
		||||
    } else {
 | 
			
		||||
        None
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Test functions for wrap_vec_return
 | 
			
		||||
fn get_all_users(_db: &OurDB) -> Vec<User> {
 | 
			
		||||
    vec![
 | 
			
		||||
        User { id: 1, name: "User 1".to_string(), age: 30 },
 | 
			
		||||
        User { id: 2, name: "User 2".to_string(), age: 25 },
 | 
			
		||||
    ]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get_users_by_age(_db: &OurDB, min_age: INT) -> Vec<User> {
 | 
			
		||||
    vec![
 | 
			
		||||
        User { id: 1, name: "User 1".to_string(), age: 30 },
 | 
			
		||||
        User { id: 2, name: "User 2".to_string(), age: 25 },
 | 
			
		||||
    ].into_iter().filter(|u| u.age >= min_age).collect()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get_all_user_ids() -> Vec<INT> {
 | 
			
		||||
    vec![1, 2, 3]
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Test functions for wrap_option_vec_return
 | 
			
		||||
fn find_users_by_name(_db: &OurDB, name_part: String) -> Option<Vec<User>> {
 | 
			
		||||
    if name_part.is_empty() {
 | 
			
		||||
        None
 | 
			
		||||
    } else {
 | 
			
		||||
        Some(vec![
 | 
			
		||||
            User { id: 1, name: format!("{} One", name_part), age: 30 },
 | 
			
		||||
            User { id: 2, name: format!("{} Two", name_part), age: 25 },
 | 
			
		||||
        ])
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Test functions for result-returning wrappers
 | 
			
		||||
fn get_user_by_id_result(db: &OurDB, id: INT) -> Result<Option<User>, DBError> {
 | 
			
		||||
    if db.error_mode {
 | 
			
		||||
        Err(DBError { message: "DB connection error".to_string() })
 | 
			
		||||
    } else if id > 0 {
 | 
			
		||||
        Ok(Some(User { id, name: format!("User {}", id), age: 30 }))
 | 
			
		||||
    } else {
 | 
			
		||||
        Ok(None)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn get_all_users_result(db: &OurDB) -> Result<Vec<User>, DBError> {
 | 
			
		||||
    if db.error_mode {
 | 
			
		||||
        Err(DBError { message: "DB connection error".to_string() })
 | 
			
		||||
    } else {
 | 
			
		||||
        Ok(vec![
 | 
			
		||||
            User { id: 1, name: "User 1".to_string(), age: 30 },
 | 
			
		||||
            User { id: 2, name: "User 2".to_string(), age: 25 },
 | 
			
		||||
        ])
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn find_users_by_name_result(db: &OurDB, name_part: String) -> Result<Option<Vec<User>>, DBError> {
 | 
			
		||||
    if db.error_mode {
 | 
			
		||||
        Err(DBError { message: "DB connection error".to_string() })
 | 
			
		||||
    } else if name_part.is_empty() {
 | 
			
		||||
        Ok(None)
 | 
			
		||||
    } else {
 | 
			
		||||
        Ok(Some(vec![
 | 
			
		||||
            User { id: 1, name: format!("{} One", name_part), age: 30 },
 | 
			
		||||
            User { id: 2, name: format!("{} Two", name_part), age: 25 },
 | 
			
		||||
        ]))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Test methods for method wrappers
 | 
			
		||||
struct UserCollection {
 | 
			
		||||
    users: Vec<User>,
 | 
			
		||||
    error_mode: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl UserCollection {
 | 
			
		||||
    fn new(error_mode: bool) -> Self {
 | 
			
		||||
        UserCollection {
 | 
			
		||||
            users: vec![
 | 
			
		||||
                User { id: 1, name: "User 1".to_string(), age: 30 },
 | 
			
		||||
                User { id: 2, name: "User 2".to_string(), age: 25 },
 | 
			
		||||
            ],
 | 
			
		||||
            error_mode,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_by_id(&self, id: INT) -> Result<Option<User>, DBError> {
 | 
			
		||||
        if self.error_mode {
 | 
			
		||||
            Err(DBError { message: "Collection error".to_string() })
 | 
			
		||||
        } else {
 | 
			
		||||
            Ok(self.users.iter().find(|u| u.id == id).cloned())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn get_all(&self) -> Result<Vec<User>, DBError> {
 | 
			
		||||
        if self.error_mode {
 | 
			
		||||
            Err(DBError { message: "Collection error".to_string() })
 | 
			
		||||
        } else {
 | 
			
		||||
            Ok(self.users.clone())
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn find_by_name(&self, name_part: String) -> Result<Option<Vec<User>>, DBError> {
 | 
			
		||||
        if self.error_mode {
 | 
			
		||||
            Err(DBError { message: "Collection error".to_string() })
 | 
			
		||||
        } else if name_part.is_empty() {
 | 
			
		||||
            Ok(None)
 | 
			
		||||
        } else {
 | 
			
		||||
            Ok(Some(self.users.iter()
 | 
			
		||||
                .filter(|u| u.name.contains(&name_part))
 | 
			
		||||
                .cloned()
 | 
			
		||||
                .collect()))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_wrap_option_return() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    let db = OurDB::new(false);
 | 
			
		||||
    
 | 
			
		||||
    // Register the wrapped function
 | 
			
		||||
    engine.register_fn(
 | 
			
		||||
        "get_user_by_id_rhai",
 | 
			
		||||
        wrap_option_return!(get_user_by_id, &OurDB, INT => User)
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    // Register the User type
 | 
			
		||||
    engine.build_type::<User>();
 | 
			
		||||
    
 | 
			
		||||
    // Test with existing user
 | 
			
		||||
    let script1 = r#"
 | 
			
		||||
        let user = get_user_by_id_rhai(db, 1);
 | 
			
		||||
        user.id
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result1 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script1, 
 | 
			
		||||
        "user.id", 
 | 
			
		||||
        (db.clone(), )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result1, 1);
 | 
			
		||||
    
 | 
			
		||||
    // Test with non-existing user
 | 
			
		||||
    let script2 = r#"
 | 
			
		||||
        let user = get_user_by_id_rhai(db, 0);
 | 
			
		||||
        if user == () { 42 } else { 0 }
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result2 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script2, 
 | 
			
		||||
        "if user == () { 42 } else { 0 }", 
 | 
			
		||||
        (db, )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result2, 42);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_wrap_vec_return() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    let db = OurDB::new(false);
 | 
			
		||||
    
 | 
			
		||||
    // Register the wrapped functions
 | 
			
		||||
    engine.register_fn(
 | 
			
		||||
        "get_all_users_rhai",
 | 
			
		||||
        wrap_vec_return!(get_all_users, &OurDB => User)
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    engine.register_fn(
 | 
			
		||||
        "get_users_by_age_rhai",
 | 
			
		||||
        wrap_vec_return!(get_users_by_age, &OurDB, INT => User)
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    engine.register_fn(
 | 
			
		||||
        "get_all_user_ids_rhai",
 | 
			
		||||
        wrap_vec_return!(get_all_user_ids, () => INT)
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    // Register the User type
 | 
			
		||||
    engine.build_type::<User>();
 | 
			
		||||
    
 | 
			
		||||
    // Test get_all_users
 | 
			
		||||
    let script1 = r#"
 | 
			
		||||
        let users = get_all_users_rhai(db);
 | 
			
		||||
        users.len()
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result1 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script1, 
 | 
			
		||||
        "users.len()", 
 | 
			
		||||
        (db.clone(), )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result1, 2);
 | 
			
		||||
    
 | 
			
		||||
    // Test get_users_by_age
 | 
			
		||||
    let script2 = r#"
 | 
			
		||||
        let users = get_users_by_age_rhai(db, 30);
 | 
			
		||||
        users.len()
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result2 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script2, 
 | 
			
		||||
        "users.len()", 
 | 
			
		||||
        (db, )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result2, 1);
 | 
			
		||||
    
 | 
			
		||||
    // Test get_all_user_ids
 | 
			
		||||
    let script3 = r#"
 | 
			
		||||
        let ids = get_all_user_ids_rhai();
 | 
			
		||||
        ids.len()
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result3 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script3, 
 | 
			
		||||
        "ids.len()", 
 | 
			
		||||
        ()
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result3, 3);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_wrap_option_vec_return() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    let db = OurDB::new(false);
 | 
			
		||||
    
 | 
			
		||||
    // Register the wrapped function
 | 
			
		||||
    engine.register_fn(
 | 
			
		||||
        "find_users_by_name_rhai",
 | 
			
		||||
        wrap_option_vec_return!(find_users_by_name, &OurDB, String => User)
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    // Register the User type
 | 
			
		||||
    engine.build_type::<User>();
 | 
			
		||||
    
 | 
			
		||||
    // Test with found users
 | 
			
		||||
    let script1 = r#"
 | 
			
		||||
        let users = find_users_by_name_rhai(db, "User");
 | 
			
		||||
        users.len()
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result1 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script1, 
 | 
			
		||||
        "users.len()", 
 | 
			
		||||
        (db.clone(), )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result1, 2);
 | 
			
		||||
    
 | 
			
		||||
    // Test with no users found
 | 
			
		||||
    let script2 = r#"
 | 
			
		||||
        let users = find_users_by_name_rhai(db, "");
 | 
			
		||||
        if users == () { 42 } else { 0 }
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result2 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script2, 
 | 
			
		||||
        "if users == () { 42 } else { 0 }", 
 | 
			
		||||
        (db, )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result2, 42);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_wrap_option_return_result() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    let db_ok = OurDB::new(false);
 | 
			
		||||
    let db_err = OurDB::new(true);
 | 
			
		||||
    
 | 
			
		||||
    // Register the wrapped function
 | 
			
		||||
    engine.register_result_fn(
 | 
			
		||||
        "get_user_by_id_result_rhai",
 | 
			
		||||
        wrap_option_return_result!(get_user_by_id_result, &OurDB, INT => User, DBError)
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    // Register the User type
 | 
			
		||||
    engine.build_type::<User>();
 | 
			
		||||
    
 | 
			
		||||
    // Test with existing user
 | 
			
		||||
    let script1 = r#"
 | 
			
		||||
        let user = get_user_by_id_result_rhai(db, 1);
 | 
			
		||||
        user.id
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result1 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script1, 
 | 
			
		||||
        "user.id", 
 | 
			
		||||
        (db_ok.clone(), )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result1, 1);
 | 
			
		||||
    
 | 
			
		||||
    // Test with non-existing user
 | 
			
		||||
    let script2 = r#"
 | 
			
		||||
        let user = get_user_by_id_result_rhai(db, 0);
 | 
			
		||||
        if user == () { 42 } else { 0 }
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result2 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script2, 
 | 
			
		||||
        "if user == () { 42 } else { 0 }", 
 | 
			
		||||
        (db_ok.clone(), )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result2, 42);
 | 
			
		||||
    
 | 
			
		||||
    // Test with error
 | 
			
		||||
    let script3 = r#"
 | 
			
		||||
        try {
 | 
			
		||||
            let user = get_user_by_id_result_rhai(db, 1);
 | 
			
		||||
            0
 | 
			
		||||
        } catch(err) {
 | 
			
		||||
            if err.contains("DB connection error") { 99 } else { 0 }
 | 
			
		||||
        }
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result3 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script3, 
 | 
			
		||||
        "try_catch_block", 
 | 
			
		||||
        (db_err, )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result3, 99);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_wrap_vec_return_result() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    let db_ok = OurDB::new(false);
 | 
			
		||||
    let db_err = OurDB::new(true);
 | 
			
		||||
    
 | 
			
		||||
    // Register the wrapped function
 | 
			
		||||
    engine.register_result_fn(
 | 
			
		||||
        "get_all_users_result_rhai",
 | 
			
		||||
        wrap_vec_return_result!(get_all_users_result, &OurDB => User, DBError)
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    // Register the User type
 | 
			
		||||
    engine.build_type::<User>();
 | 
			
		||||
    
 | 
			
		||||
    // Test with successful result
 | 
			
		||||
    let script1 = r#"
 | 
			
		||||
        let users = get_all_users_result_rhai(db);
 | 
			
		||||
        users.len()
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result1 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script1, 
 | 
			
		||||
        "users.len()", 
 | 
			
		||||
        (db_ok.clone(), )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result1, 2);
 | 
			
		||||
    
 | 
			
		||||
    // Test with error
 | 
			
		||||
    let script2 = r#"
 | 
			
		||||
        try {
 | 
			
		||||
            let users = get_all_users_result_rhai(db);
 | 
			
		||||
            0
 | 
			
		||||
        } catch(err) {
 | 
			
		||||
            if err.contains("DB connection error") { 99 } else { 0 }
 | 
			
		||||
        }
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result2 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script2, 
 | 
			
		||||
        "try_catch_block", 
 | 
			
		||||
        (db_err, )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result2, 99);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_wrap_option_vec_return_result() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    let db_ok = OurDB::new(false);
 | 
			
		||||
    let db_err = OurDB::new(true);
 | 
			
		||||
    
 | 
			
		||||
    // Register the wrapped function
 | 
			
		||||
    engine.register_result_fn(
 | 
			
		||||
        "find_users_by_name_result_rhai",
 | 
			
		||||
        wrap_option_vec_return_result!(find_users_by_name_result, &OurDB, String => User, DBError)
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    // Register the User type
 | 
			
		||||
    engine.build_type::<User>();
 | 
			
		||||
    
 | 
			
		||||
    // Test with found users
 | 
			
		||||
    let script1 = r#"
 | 
			
		||||
        let users = find_users_by_name_result_rhai(db, "User");
 | 
			
		||||
        users.len()
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result1 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script1, 
 | 
			
		||||
        "users.len()", 
 | 
			
		||||
        (db_ok.clone(), )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result1, 2);
 | 
			
		||||
    
 | 
			
		||||
    // Test with no users found
 | 
			
		||||
    let script2 = r#"
 | 
			
		||||
        let users = find_users_by_name_result_rhai(db, "");
 | 
			
		||||
        if users == () { 42 } else { 0 }
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result2 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script2, 
 | 
			
		||||
        "if users == () { 42 } else { 0 }", 
 | 
			
		||||
        (db_ok.clone(), )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result2, 42);
 | 
			
		||||
    
 | 
			
		||||
    // Test with error
 | 
			
		||||
    let script3 = r#"
 | 
			
		||||
        try {
 | 
			
		||||
            let users = find_users_by_name_result_rhai(db, "User");
 | 
			
		||||
            0
 | 
			
		||||
        } catch(err) {
 | 
			
		||||
            if err.contains("DB connection error") { 99 } else { 0 }
 | 
			
		||||
        }
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result3 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script3, 
 | 
			
		||||
        "try_catch_block", 
 | 
			
		||||
        (db_err, )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result3, 99);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_wrap_option_method_result() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    let collection_ok = UserCollection::new(false);
 | 
			
		||||
    let collection_err = UserCollection::new(true);
 | 
			
		||||
    
 | 
			
		||||
    // Register the wrapped method
 | 
			
		||||
    engine.register_result_fn(
 | 
			
		||||
        "get_by_id_rhai",
 | 
			
		||||
        wrap_option_method_result!(get_by_id, &UserCollection, INT => User, DBError)
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    // Register the User type
 | 
			
		||||
    engine.build_type::<User>();
 | 
			
		||||
    
 | 
			
		||||
    // Test with existing user
 | 
			
		||||
    let script1 = r#"
 | 
			
		||||
        let user = get_by_id_rhai(collection, 1);
 | 
			
		||||
        user.id
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result1 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script1, 
 | 
			
		||||
        "user.id", 
 | 
			
		||||
        (collection_ok.clone(), )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result1, 1);
 | 
			
		||||
    
 | 
			
		||||
    // Test with non-existing user
 | 
			
		||||
    let script2 = r#"
 | 
			
		||||
        let user = get_by_id_rhai(collection, 999);
 | 
			
		||||
        if user == () { 42 } else { 0 }
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result2 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script2, 
 | 
			
		||||
        "if user == () { 42 } else { 0 }", 
 | 
			
		||||
        (collection_ok.clone(), )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result2, 42);
 | 
			
		||||
    
 | 
			
		||||
    // Test with error
 | 
			
		||||
    let script3 = r#"
 | 
			
		||||
        try {
 | 
			
		||||
            let user = get_by_id_rhai(collection, 1);
 | 
			
		||||
            0
 | 
			
		||||
        } catch(err) {
 | 
			
		||||
            if err.contains("Collection error") { 99 } else { 0 }
 | 
			
		||||
        }
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result3 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script3, 
 | 
			
		||||
        "try_catch_block", 
 | 
			
		||||
        (collection_err, )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result3, 99);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_wrap_vec_method_result() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    let collection_ok = UserCollection::new(false);
 | 
			
		||||
    let collection_err = UserCollection::new(true);
 | 
			
		||||
    
 | 
			
		||||
    // Register the wrapped method
 | 
			
		||||
    engine.register_result_fn(
 | 
			
		||||
        "get_all_rhai",
 | 
			
		||||
        wrap_vec_method_result!(get_all, &UserCollection => User, DBError)
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    // Register the User type
 | 
			
		||||
    engine.build_type::<User>();
 | 
			
		||||
    
 | 
			
		||||
    // Test with successful result
 | 
			
		||||
    let script1 = r#"
 | 
			
		||||
        let users = get_all_rhai(collection);
 | 
			
		||||
        users.len()
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result1 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script1, 
 | 
			
		||||
        "users.len()", 
 | 
			
		||||
        (collection_ok.clone(), )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result1, 2);
 | 
			
		||||
    
 | 
			
		||||
    // Test with error
 | 
			
		||||
    let script2 = r#"
 | 
			
		||||
        try {
 | 
			
		||||
            let users = get_all_rhai(collection);
 | 
			
		||||
            0
 | 
			
		||||
        } catch(err) {
 | 
			
		||||
            if err.contains("Collection error") { 99 } else { 0 }
 | 
			
		||||
        }
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result2 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script2, 
 | 
			
		||||
        "try_catch_block", 
 | 
			
		||||
        (collection_err, )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result2, 99);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[test]
 | 
			
		||||
fn test_wrap_option_vec_method_result() {
 | 
			
		||||
    let mut engine = Engine::new();
 | 
			
		||||
    let collection_ok = UserCollection::new(false);
 | 
			
		||||
    let collection_err = UserCollection::new(true);
 | 
			
		||||
    
 | 
			
		||||
    // Register the wrapped method
 | 
			
		||||
    engine.register_result_fn(
 | 
			
		||||
        "find_by_name_rhai",
 | 
			
		||||
        wrap_option_vec_method_result!(find_by_name, &UserCollection, String => User, DBError)
 | 
			
		||||
    );
 | 
			
		||||
    
 | 
			
		||||
    // Register the User type
 | 
			
		||||
    engine.build_type::<User>();
 | 
			
		||||
    
 | 
			
		||||
    // Test with found users
 | 
			
		||||
    let script1 = r#"
 | 
			
		||||
        let users = find_by_name_rhai(collection, "User");
 | 
			
		||||
        users.len()
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result1 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script1, 
 | 
			
		||||
        "users.len()", 
 | 
			
		||||
        (collection_ok.clone(), )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result1, 2);
 | 
			
		||||
    
 | 
			
		||||
    // Test with no users found
 | 
			
		||||
    let script2 = r#"
 | 
			
		||||
        let users = find_by_name_rhai(collection, "");
 | 
			
		||||
        if users == () { 42 } else { 0 }
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result2 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script2, 
 | 
			
		||||
        "if users == () { 42 } else { 0 }", 
 | 
			
		||||
        (collection_ok.clone(), )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result2, 42);
 | 
			
		||||
    
 | 
			
		||||
    // Test with error
 | 
			
		||||
    let script3 = r#"
 | 
			
		||||
        try {
 | 
			
		||||
            let users = find_by_name_rhai(collection, "User");
 | 
			
		||||
            0
 | 
			
		||||
        } catch(err) {
 | 
			
		||||
            if err.contains("Collection error") { 99 } else { 0 }
 | 
			
		||||
        }
 | 
			
		||||
    "#;
 | 
			
		||||
    
 | 
			
		||||
    let result3 = engine.call_fn::<INT>(
 | 
			
		||||
        &mut rhai::Scope::new(), 
 | 
			
		||||
        script3, 
 | 
			
		||||
        "try_catch_block", 
 | 
			
		||||
        (collection_err, )
 | 
			
		||||
    ).unwrap();
 | 
			
		||||
    
 | 
			
		||||
    assert_eq!(result3, 99);
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user