rhai/tests/fn_ptr.rs
2022-08-05 23:30:44 +08:00

168 lines
3.6 KiB
Rust

use rhai::{Engine, EvalAltResult, FnPtr, INT};
#[test]
fn test_fn_ptr() -> Result<(), Box<EvalAltResult>> {
let mut engine = Engine::new();
engine.register_fn("bar", |x: &mut INT, y: INT| *x += y);
#[cfg(not(feature = "no_object"))]
assert_eq!(
engine.eval::<INT>(
r#"
let f = Fn("bar");
let x = 40;
f.call(x, 2);
x
"#
)?,
40
);
#[cfg(not(feature = "no_object"))]
assert_eq!(
engine.eval::<INT>(
r#"
let f = Fn("bar");
let x = 40;
x.call(f, 2);
x
"#
)?,
42
);
assert_eq!(
engine.eval::<INT>(
r#"
let f = Fn("bar");
let x = 40;
call(f, x, 2);
x
"#
)?,
42
);
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_object"))]
assert_eq!(
engine.eval::<INT>(
r#"
fn foo(x) { this += x; }
let f = Fn("foo");
let x = 40;
x.call(f, 2);
x
"#
)?,
42
);
#[cfg(not(feature = "no_function"))]
assert!(matches!(
*engine
.eval::<INT>(
r#"
fn foo(x) { this += x; }
let f = Fn("foo");
call(f, 2);
x
"#
)
.expect_err("should error"),
EvalAltResult::ErrorInFunctionCall(fn_name, _, err, ..)
if fn_name == "foo" && matches!(*err, EvalAltResult::ErrorUnboundThis(..))
));
#[cfg(not(feature = "no_function"))]
assert_eq!(
engine.eval::<INT>(
r#"
fn foo(x) { x + 1 }
let f = foo;
let g = 42;
g = foo;
call(f, 39) + call(g, 1)
"#
)?,
42
);
Ok(())
}
#[test]
fn test_fn_ptr_curry() -> Result<(), Box<EvalAltResult>> {
let mut engine = Engine::new();
engine.register_fn("foo", |x: &mut INT, y: INT| *x + y);
#[cfg(not(feature = "no_object"))]
assert_eq!(
engine.eval::<INT>(
r#"
let f = Fn("foo");
let f2 = f.curry(40);
f2.call(2)
"#
)?,
42
);
assert_eq!(
engine.eval::<INT>(
r#"
let f = Fn("foo");
let f2 = curry(f, 40);
call(f2, 2)
"#
)?,
42
);
Ok(())
}
#[test]
#[cfg(not(feature = "no_function"))]
fn test_fn_ptr_call() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new();
let ast = engine.compile("private fn foo(x, y) { len(x) + y }")?;
let mut fn_ptr = FnPtr::new("foo")?;
fn_ptr.set_curry(vec!["abc".into()]);
let result: INT = fn_ptr.call(&engine, &ast, (39 as INT,))?;
assert_eq!(result, 42);
Ok(())
}
#[test]
#[cfg(not(feature = "no_closure"))]
fn test_fn_ptr_make_closure() -> Result<(), Box<EvalAltResult>> {
let f = {
let engine = Engine::new();
let ast = engine.compile(
r#"
let test = "hello";
|x| test + x // this creates a closure
"#,
)?;
let fn_ptr = engine.eval_ast::<FnPtr>(&ast)?;
move |x: INT| -> Result<String, _> { fn_ptr.call(&engine, &ast, (x,)) }
};
// 'f' captures: the Engine, the AST, and the closure
assert_eq!(f(42)?, "hello42");
Ok(())
}