Add fallible functions support and replace most arithmetic operations with checked versions.
This commit is contained in:
@@ -58,6 +58,32 @@ pub trait RegisterDynamicFn<FN, ARGS> {
|
||||
fn register_dynamic_fn(&mut self, name: &str, f: FN);
|
||||
}
|
||||
|
||||
/// A trait to register fallible custom functions returning Result<_, EvalAltResult> with the `Engine`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use rhai::{Engine, RegisterFn};
|
||||
///
|
||||
/// // Normal function
|
||||
/// fn add(x: i64, y: i64) -> i64 {
|
||||
/// x + y
|
||||
/// }
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// // You must use the trait rhai::RegisterFn to get this method.
|
||||
/// engine.register_fn("add", add);
|
||||
///
|
||||
/// if let Ok(result) = engine.eval::<i64>("add(40, 2)") {
|
||||
/// println!("Answer: {}", result); // prints 42
|
||||
/// }
|
||||
/// ```
|
||||
pub trait RegisterResultFn<FN, ARGS, RET> {
|
||||
/// Register a custom function with the `Engine`.
|
||||
fn register_result_fn(&mut self, name: &str, f: FN);
|
||||
}
|
||||
|
||||
pub struct Ref<A>(A);
|
||||
pub struct Mut<A>(A);
|
||||
|
||||
@@ -91,7 +117,7 @@ macro_rules! def_register {
|
||||
let mut drain = args.drain(..);
|
||||
$(
|
||||
// Downcast every element, return in case of a type mismatch
|
||||
let $par = (drain.next().unwrap().downcast_mut() as Option<&mut $par>).unwrap();
|
||||
let $par = drain.next().unwrap().downcast_mut::<$par>().unwrap();
|
||||
)*
|
||||
|
||||
// Call the user-supplied function using ($clone) to
|
||||
@@ -123,7 +149,7 @@ macro_rules! def_register {
|
||||
let mut drain = args.drain(..);
|
||||
$(
|
||||
// Downcast every element, return in case of a type mismatch
|
||||
let $par = (drain.next().unwrap().downcast_mut() as Option<&mut $par>).unwrap();
|
||||
let $par = drain.next().unwrap().downcast_mut::<$par>().unwrap();
|
||||
)*
|
||||
|
||||
// Call the user-supplied function using ($clone) to
|
||||
@@ -135,6 +161,44 @@ macro_rules! def_register {
|
||||
}
|
||||
}
|
||||
|
||||
impl<
|
||||
$($par: Any + Clone,)*
|
||||
FN: Fn($($param),*) -> Result<RET, EvalAltResult> + 'static,
|
||||
RET: Any
|
||||
> RegisterResultFn<FN, ($($mark,)*), RET> for Engine<'_>
|
||||
{
|
||||
fn register_result_fn(&mut self, name: &str, f: FN) {
|
||||
let fn_name = name.to_string();
|
||||
|
||||
let fun = move |mut args: FnCallArgs, pos: Position| {
|
||||
// Check for length at the beginning to avoid per-element bound checks.
|
||||
const NUM_ARGS: usize = count_args!($($par)*);
|
||||
|
||||
if args.len() != NUM_ARGS {
|
||||
Err(EvalAltResult::ErrorFunctionArgsMismatch(fn_name.clone(), NUM_ARGS, args.len(), pos))
|
||||
} else {
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
let mut drain = args.drain(..);
|
||||
$(
|
||||
// Downcast every element, return in case of a type mismatch
|
||||
let $par = drain.next().unwrap().downcast_mut::<$par>().unwrap();
|
||||
)*
|
||||
|
||||
// Call the user-supplied function using ($clone) to
|
||||
// potentially clone the value, otherwise pass the reference.
|
||||
match f($(($clone)($par)),*) {
|
||||
Ok(r) => Ok(Box::new(r) as Dynamic),
|
||||
Err(mut err) => {
|
||||
err.set_position(pos);
|
||||
Err(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
self.register_fn_raw(name, Some(vec![$(TypeId::of::<$par>()),*]), Box::new(fun));
|
||||
}
|
||||
}
|
||||
|
||||
//def_register!(imp_pop $($par => $mark => $param),*);
|
||||
};
|
||||
($p0:ident $(, $p:ident)*) => {
|
||||
|
Reference in New Issue
Block a user