Avoid copying arguments in packages.

This commit is contained in:
Stephen Chung 2020-05-06 23:52:47 +08:00
parent e966f5d49e
commit 34327f6e54
2 changed files with 41 additions and 19 deletions

View File

@ -502,6 +502,12 @@ impl Engine {
}
/// Universal method for calling functions either registered with the `Engine` or written in Rhai.
///
/// ## WARNING
///
/// Function call arguments may be _consumed_ when the function requires them to be passed by value.
/// All function arguments not in the first position are always passed by value and thus consumed.
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
pub(crate) fn call_fn_raw(
&self,
scope: Option<&mut Scope>,
@ -596,6 +602,12 @@ impl Engine {
}
/// Call a script-defined function.
///
/// ## WARNING
///
/// Function call arguments may be _consumed_ when the function requires them to be passed by value.
/// All function arguments not in the first position are always passed by value and thus consumed.
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
pub(crate) fn call_fn_from_lib(
&self,
scope: Option<&mut Scope>,
@ -678,6 +690,12 @@ impl Engine {
}
// Perform an actual function call, taking care of special functions
///
/// ## WARNING
///
/// Function call arguments may be _consumed_ when the function requires them to be passed by value.
/// All function arguments not in the first position are always passed by value and thus consumed.
/// **DO NOT** reuse the argument values unless for the first `&mut` argument - all others are silently replaced by `()`!
fn exec_fn_call(
&self,
fn_lib: &FunctionsLib,
@ -1105,17 +1123,20 @@ impl Engine {
rhs: &Expr,
level: usize,
) -> Result<Dynamic, Box<EvalAltResult>> {
let mut lhs_value = self.eval_expr(scope, state, fn_lib, lhs, level)?;
let lhs_value = self.eval_expr(scope, state, fn_lib, lhs, level)?;
let rhs_value = self.eval_expr(scope, state, fn_lib, rhs, level)?;
match rhs_value {
#[cfg(not(feature = "no_index"))]
Dynamic(Union::Array(mut rhs_value)) => {
Dynamic(Union::Array(rhs_value)) => {
let def_value = false.into();
// Call the '==' operator to compare each value
for value in rhs_value.iter_mut() {
let args = &mut [&mut lhs_value, value];
// Call the `==` operator to compare each value
for value in rhs_value.iter() {
// WARNING - Always clone the values here because they'll be consumed by the function call.
// Do not pass the `&mut` straight through because the `==` implementation
// very likely takes parameters passed by value!
let args = &mut [&mut lhs_value.clone(), &mut value.clone()];
let def_value = Some(&def_value);
let pos = rhs.position();

View File

@ -9,6 +9,7 @@ use crate::token::Position;
use crate::stdlib::{
any::TypeId,
boxed::Box,
mem,
string::{String, ToString},
};
@ -170,9 +171,9 @@ pub fn reg_unary<T: Variant + Clone, R>(
check_num_args(fn_name, 1, args, pos)?;
let mut drain = args.iter_mut();
let x: &mut T = drain.next().unwrap().downcast_mut().unwrap();
let x = mem::take(*drain.next().unwrap()).cast::<T>();
let r = func(x.clone());
let r = func(x);
map_result(r, pos)
});
@ -286,10 +287,10 @@ pub fn reg_binary<A: Variant + Clone, B: Variant + Clone, R>(
check_num_args(fn_name, 2, args, pos)?;
let mut drain = args.iter_mut();
let x: &mut A = drain.next().unwrap().downcast_mut().unwrap();
let y: &mut B = drain.next().unwrap().downcast_mut().unwrap();
let x = mem::take(*drain.next().unwrap()).cast::<A>();
let y = mem::take(*drain.next().unwrap()).cast::<B>();
let r = func(x.clone(), y.clone());
let r = func(x, y);
map_result(r, pos)
});
@ -351,9 +352,9 @@ pub fn reg_binary_mut<A: Variant + Clone, B: Variant + Clone, R>(
let mut drain = args.iter_mut();
let x: &mut A = drain.next().unwrap().downcast_mut().unwrap();
let y: &mut B = drain.next().unwrap().downcast_mut().unwrap();
let y = mem::take(*drain.next().unwrap()).cast::<B>();
let r = func(x, y.clone());
let r = func(x, y);
map_result(r, pos)
});
@ -390,11 +391,11 @@ pub fn reg_trinary<A: Variant + Clone, B: Variant + Clone, C: Variant + Clone, R
check_num_args(fn_name, 3, args, pos)?;
let mut drain = args.iter_mut();
let x: &mut A = drain.next().unwrap().downcast_mut().unwrap();
let y: &mut B = drain.next().unwrap().downcast_mut().unwrap();
let z: &mut C = drain.next().unwrap().downcast_mut().unwrap();
let x = mem::take(*drain.next().unwrap()).cast::<A>();
let y = mem::take(*drain.next().unwrap()).cast::<B>();
let z = mem::take(*drain.next().unwrap()).cast::<C>();
let r = func(x.clone(), y.clone(), z.clone());
let r = func(x, y, z);
map_result(r, pos)
});
@ -432,10 +433,10 @@ pub fn reg_trinary_mut<A: Variant + Clone, B: Variant + Clone, C: Variant + Clon
let mut drain = args.iter_mut();
let x: &mut A = drain.next().unwrap().downcast_mut().unwrap();
let y: &mut B = drain.next().unwrap().downcast_mut().unwrap();
let z: &mut C = drain.next().unwrap().downcast_mut().unwrap();
let y = mem::take(*drain.next().unwrap()).cast::<B>();
let z = mem::take(*drain.next().unwrap()).cast::<C>();
let r = func(x, y.clone(), z.clone());
let r = func(x, y, z);
map_result(r, pos)
});