#![cfg(not(feature = "no_function"))] use rhai::{Engine, EvalAltResult, FnNamespace, Module, NativeCallContext, Shared, INT}; #[cfg(not(feature = "no_object"))] #[test] fn test_functions_trait_object() -> Result<(), Box> { trait TestTrait { fn greet(&self) -> INT; } #[allow(clippy::upper_case_acronyms)] #[derive(Debug, Clone)] struct ABC(INT); impl TestTrait for ABC { fn greet(&self) -> INT { self.0 } } #[cfg(not(feature = "sync"))] type MySharedTestTrait = Shared; #[cfg(feature = "sync")] type MySharedTestTrait = Shared; let mut engine = Engine::new(); engine .register_type_with_name::("MySharedTestTrait") .register_fn("new_ts", || Shared::new(ABC(42)) as MySharedTestTrait) .register_fn("greet", |x: MySharedTestTrait| x.greet()); assert_eq!( engine.eval::("type_of(new_ts())")?, "MySharedTestTrait" ); assert_eq!(engine.eval::("let x = new_ts(); greet(x)")?, 42); Ok(()) } #[test] fn test_functions_namespaces() -> Result<(), Box> { let mut engine = Engine::new(); #[cfg(not(feature = "no_module"))] { let mut m = Module::new(); let hash = m.set_native_fn("test", || Ok(999 as INT)); m.update_fn_namespace(hash, FnNamespace::Global); engine.register_static_module("hello", m.into()); let mut m = Module::new(); m.set_var("ANSWER", 123 as INT); assert_eq!(engine.eval::("test()")?, 999); assert_eq!(engine.eval::("fn test() { 123 } test()")?, 123); } engine.register_fn("test", || 42 as INT); assert_eq!(engine.eval::("fn test() { 123 } test()")?, 123); assert_eq!(engine.eval::("test()")?, 42); Ok(()) } #[cfg(not(feature = "no_module"))] #[test] fn test_functions_global_module() -> Result<(), Box> { let mut engine = Engine::new(); assert_eq!( engine.eval::( " const ANSWER = 42; fn foo() { global::ANSWER } foo() " )?, 42 ); assert!(matches!(*engine.run( " fn foo() { global::ANSWER } { const ANSWER = 42; foo() } ").unwrap_err(), EvalAltResult::ErrorInFunctionCall(.., err, _) if matches!(&*err, EvalAltResult::ErrorVariableNotFound(v, ..) if v == "global::ANSWER") )); engine.register_fn( "do_stuff", |context: NativeCallContext, callback: rhai::FnPtr| -> Result { callback.call_within_context(&context, ()) }, ); #[cfg(not(feature = "no_closure"))] assert!(matches!(*engine.run( " do_stuff(|| { const LOCAL_VALUE = 42; global::LOCAL_VALUE }); ").unwrap_err(), EvalAltResult::ErrorInFunctionCall(.., err, _) if matches!(&*err, EvalAltResult::ErrorVariableNotFound(v, ..) if v == "global::LOCAL_VALUE") )); #[cfg(not(feature = "no_closure"))] assert_eq!( engine.eval::( " const GLOBAL_VALUE = 42; do_stuff(|| global::GLOBAL_VALUE); " )?, 42 ); // Override global let mut module = Module::new(); module.set_var("ANSWER", 123 as INT); engine.register_static_module("global", module.into()); assert_eq!( engine.eval::( " const ANSWER = 42; fn foo() { global::ANSWER } foo() " )?, 123 ); // Other globals let mut module = Module::new(); module.set_var("ANSWER", 123 as INT); engine.register_global_module(module.into()); assert_eq!( engine.eval::( " fn foo() { global::ANSWER } foo() " )?, 123 ); Ok(()) } #[test] fn test_functions_bang() -> Result<(), Box> { let engine = Engine::new(); assert_eq!( engine.eval::( " fn foo() { hello + bar } let hello = 42; let bar = 123; foo!() ", )?, 165 ); assert_eq!( engine.eval::( " fn foo() { hello = 0; hello + bar } let hello = 42; let bar = 123; foo!() ", )?, 123 ); assert_eq!( engine.eval::( " fn foo() { let hello = bar + 42; } let bar = 999; let hello = 123; foo!(); hello ", )?, 123 ); assert_eq!( engine.eval::( r#" fn foo(x) { let hello = bar + 42 + x; } let bar = 999; let hello = 123; let f = Fn("foo"); call!(f, 1); hello "#, )?, 123 ); Ok(()) }