Avoid copying arguments for function calls.
This commit is contained in:
parent
fc66a7ecef
commit
d83b829810
@ -375,7 +375,7 @@ engine.load_package(package.get()); // load the package manually
|
|||||||
The follow packages are available:
|
The follow packages are available:
|
||||||
|
|
||||||
| Package | Description | In `CorePackage` | In `StandardPackage` |
|
| Package | Description | In `CorePackage` | In `StandardPackage` |
|
||||||
| ------------------------ | ----------------------------------------------- | :--------------: | :------------------: |
|
| ---------------------- | ----------------------------------------------- | :--------------: | :------------------: |
|
||||||
| `ArithmeticPackage` | Arithmetic operators (e.g. `+`, `-`, `*`, `/`) | Yes | Yes |
|
| `ArithmeticPackage` | Arithmetic operators (e.g. `+`, `-`, `*`, `/`) | Yes | Yes |
|
||||||
| `BasicIteratorPackage` | Numeric ranges (e.g. `range(1, 10)`) | Yes | Yes |
|
| `BasicIteratorPackage` | Numeric ranges (e.g. `range(1, 10)`) | Yes | Yes |
|
||||||
| `LogicPackage` | Logic and comparison operators (e.g. `==`, `>`) | Yes | Yes |
|
| `LogicPackage` | Logic and comparison operators (e.g. `==`, `>`) | Yes | Yes |
|
||||||
@ -427,7 +427,7 @@ The following primitive types are supported natively:
|
|||||||
| **Boolean value** | `bool` | `"bool"` | `"true"` or `"false"` |
|
| **Boolean value** | `bool` | `"bool"` | `"true"` or `"false"` |
|
||||||
| **Unicode character** | `char` | `"char"` | `"A"`, `"x"` etc. |
|
| **Unicode character** | `char` | `"char"` | `"A"`, `"x"` etc. |
|
||||||
| **Unicode string** | `String` (_not_ `&str`) | `"string"` | `"hello"` etc. |
|
| **Unicode string** | `String` (_not_ `&str`) | `"string"` | `"hello"` etc. |
|
||||||
| **Array** (disabled with [`no_index`]) | `rhai::Array` | `"array"` | `"[ ? ? ? ]"` |
|
| **Array** (disabled with [`no_index`]) | `rhai::Array` | `"array"` | `"[ ?, ?, ? ]"` |
|
||||||
| **Object map** (disabled with [`no_object`]) | `rhai::Map` | `"map"` | `#{ "a": 1, "b": 2 }` |
|
| **Object map** (disabled with [`no_object`]) | `rhai::Map` | `"map"` | `#{ "a": 1, "b": 2 }` |
|
||||||
| **Timestamp** (implemented in the [`BasicTimePackage`](#packages)) | `std::time::Instant` | `"timestamp"` | _not supported_ |
|
| **Timestamp** (implemented in the [`BasicTimePackage`](#packages)) | `std::time::Instant` | `"timestamp"` | _not supported_ |
|
||||||
| **Dynamic value** (i.e. can be anything) | `rhai::Dynamic` | _the actual type_ | _actual value_ |
|
| **Dynamic value** (i.e. can be anything) | `rhai::Dynamic` | _the actual type_ | _actual value_ |
|
||||||
@ -1372,7 +1372,8 @@ y[2] == 3;
|
|||||||
y[3] == 4;
|
y[3] == 4;
|
||||||
|
|
||||||
(1 in y) == true; // use 'in' to test if an item exists in the array
|
(1 in y) == true; // use 'in' to test if an item exists in the array
|
||||||
(42 in y) == false;
|
(42 in y) == false; // 'in' uses the '==' operator (which users can override)
|
||||||
|
// to check if the target item exists in the array
|
||||||
|
|
||||||
y[1] = 42; // array elements can be reassigned
|
y[1] = 42; // array elements can be reassigned
|
||||||
|
|
||||||
@ -1494,7 +1495,7 @@ y.a == 42;
|
|||||||
|
|
||||||
y["baz!$@"] == 123.456; // access via index notation
|
y["baz!$@"] == 123.456; // access via index notation
|
||||||
|
|
||||||
"baz!$@" in y == true; // use 'in' to test if a property exists in the object map, prints true
|
"baz!$@" in y == true; // use 'in' to test if a property exists in the object map
|
||||||
("z" in y) == false;
|
("z" in y) == false;
|
||||||
|
|
||||||
ts.obj = y; // object maps can be assigned completely (by value copy)
|
ts.obj = y; // object maps can be assigned completely (by value copy)
|
||||||
|
19
src/any.rs
19
src/any.rs
@ -396,7 +396,24 @@ impl Dynamic {
|
|||||||
/// assert_eq!(x.cast::<u32>(), 42);
|
/// assert_eq!(x.cast::<u32>(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
pub fn cast<T: Variant + Clone>(self) -> T {
|
pub fn cast<T: Variant + Clone>(self) -> T {
|
||||||
self.try_cast::<T>().unwrap()
|
//self.try_cast::<T>().unwrap()
|
||||||
|
|
||||||
|
if TypeId::of::<T>() == TypeId::of::<Dynamic>() {
|
||||||
|
return cast_box::<_, T>(Box::new(self)).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
match self.0 {
|
||||||
|
Union::Unit(ref value) => (value as &dyn Variant).downcast_ref::<T>().unwrap().clone(),
|
||||||
|
Union::Bool(ref value) => (value as &dyn Variant).downcast_ref::<T>().unwrap().clone(),
|
||||||
|
Union::Str(value) => cast_box::<_, T>(value).unwrap(),
|
||||||
|
Union::Char(ref value) => (value as &dyn Variant).downcast_ref::<T>().unwrap().clone(),
|
||||||
|
Union::Int(ref value) => (value as &dyn Variant).downcast_ref::<T>().unwrap().clone(),
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
Union::Float(ref value) => (value as &dyn Variant).downcast_ref::<T>().unwrap().clone(),
|
||||||
|
Union::Array(value) => cast_box::<_, T>(value).unwrap(),
|
||||||
|
Union::Map(value) => cast_box::<_, T>(value).unwrap(),
|
||||||
|
Union::Variant(value) => value.as_ref().as_ref().downcast_ref::<T>().unwrap().clone(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a reference of a specific type to the `Dynamic`.
|
/// Get a reference of a specific type to the `Dynamic`.
|
||||||
|
@ -692,7 +692,7 @@ impl Engine {
|
|||||||
&self,
|
&self,
|
||||||
fn_lib: &FunctionsLib,
|
fn_lib: &FunctionsLib,
|
||||||
fn_name: &str,
|
fn_name: &str,
|
||||||
args: &mut [&mut Dynamic],
|
args: &mut FnCallArgs,
|
||||||
def_val: Option<&Dynamic>,
|
def_val: Option<&Dynamic>,
|
||||||
pos: Position,
|
pos: Position,
|
||||||
level: usize,
|
level: usize,
|
||||||
@ -1227,7 +1227,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Array(contents, _) => Ok(Dynamic(Union::Array(Box::new(
|
Expr::Array(contents, _) => Ok(Dynamic(Union::Array(Box::new(
|
||||||
contents
|
contents
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|item| self.eval_expr(scope, state, fn_lib, item, level))
|
.map(|item| self.eval_expr(scope, state, fn_lib, item, level))
|
||||||
.collect::<Result<Vec<_>, _>>()?,
|
.collect::<Result<Vec<_>, _>>()?,
|
||||||
)))),
|
)))),
|
||||||
@ -1235,9 +1235,9 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Map(contents, _) => Ok(Dynamic(Union::Map(Box::new(
|
Expr::Map(contents, _) => Ok(Dynamic(Union::Map(Box::new(
|
||||||
contents
|
contents
|
||||||
.into_iter()
|
.iter()
|
||||||
.map(|(key, expr, _)| {
|
.map(|(key, expr, _)| {
|
||||||
self.eval_expr(scope, state, fn_lib, &expr, level)
|
self.eval_expr(scope, state, fn_lib, expr, level)
|
||||||
.map(|val| (key.clone(), val))
|
.map(|val| (key.clone(), val))
|
||||||
})
|
})
|
||||||
.collect::<Result<HashMap<_, _>, _>>()?,
|
.collect::<Result<HashMap<_, _>, _>>()?,
|
||||||
|
@ -22,7 +22,7 @@ macro_rules! impl_args {
|
|||||||
fn into_vec(self) -> Vec<Dynamic> {
|
fn into_vec(self) -> Vec<Dynamic> {
|
||||||
let ($($p,)*) = self;
|
let ($($p,)*) = self;
|
||||||
|
|
||||||
#[allow(unused_variables, unused_mut)]
|
#[allow(unused_mut)]
|
||||||
let mut v = Vec::new();
|
let mut v = Vec::new();
|
||||||
$(v.push($p.into_dynamic());)*
|
$(v.push($p.into_dynamic());)*
|
||||||
|
|
||||||
@ -42,5 +42,4 @@ macro_rules! impl_args {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
impl_args!(A, B, C, D, E, F, G, H, J, K, L, M, N, P, Q, R, S, T, U, V);
|
impl_args!(A, B, C, D, E, F, G, H, J, K, L, M, N, P, Q, R, S, T, U, V);
|
||||||
|
@ -116,5 +116,4 @@ macro_rules! def_anonymous_fn {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
def_anonymous_fn!(A, B, C, D, E, F, G, H, J, K, L, M, N, P, Q, R, S, T, U, V);
|
def_anonymous_fn!(A, B, C, D, E, F, G, H, J, K, L, M, N, P, Q, R, S, T, U, V);
|
||||||
|
@ -7,7 +7,7 @@ use crate::engine::{calc_fn_spec, Engine, FnCallArgs};
|
|||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
|
|
||||||
use crate::stdlib::{any::TypeId, boxed::Box, string::ToString};
|
use crate::stdlib::{any::TypeId, boxed::Box, mem, string::ToString};
|
||||||
|
|
||||||
/// A trait to register custom functions with the `Engine`.
|
/// A trait to register custom functions with the `Engine`.
|
||||||
pub trait RegisterFn<FN, ARGS, RET> {
|
pub trait RegisterFn<FN, ARGS, RET> {
|
||||||
@ -115,16 +115,19 @@ pub trait RegisterResultFn<FN, ARGS, RET> {
|
|||||||
pub struct Mut<T>(T);
|
pub struct Mut<T>(T);
|
||||||
//pub struct Ref<T>(T);
|
//pub struct Ref<T>(T);
|
||||||
|
|
||||||
/// Identity dereferencing function.
|
/// Dereference into &mut.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn identity<T>(data: &mut T) -> &mut T {
|
pub fn by_ref<T: Clone + 'static>(data: &mut Dynamic) -> &mut T {
|
||||||
data
|
// Directly cast the &mut Dynamic into &mut T to access the underlying data.
|
||||||
|
data.downcast_mut::<T>().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Clone dereferencing function.
|
/// Dereference into value.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn cloned<T: Clone>(data: &mut T) -> T {
|
pub fn by_value<T: Clone + 'static>(data: &mut Dynamic) -> T {
|
||||||
data.clone()
|
// We consume the argument and then replace it with () - the argument is not supposed to be used again.
|
||||||
|
// This way, we avoid having to clone the argument again, because it is already a clone when passed here.
|
||||||
|
mem::replace(data, Default::default()).cast::<T>()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This macro counts the number of arguments via recursion.
|
/// This macro counts the number of arguments via recursion.
|
||||||
@ -135,7 +138,7 @@ macro_rules! count_args {
|
|||||||
|
|
||||||
/// This macro creates a closure wrapping a registered function.
|
/// This macro creates a closure wrapping a registered function.
|
||||||
macro_rules! make_func {
|
macro_rules! make_func {
|
||||||
($fn_name:ident : $fn:ident : $map:expr ; $($par:ident => $clone:expr),*) => {
|
($fn_name:ident : $fn:ident : $map:expr ; $($par:ident => $convert:expr),*) => {
|
||||||
// ^ function name
|
// ^ function name
|
||||||
// ^ function pointer
|
// ^ function pointer
|
||||||
// ^ result mapping function
|
// ^ result mapping function
|
||||||
@ -153,13 +156,15 @@ macro_rules! make_func {
|
|||||||
#[allow(unused_variables, unused_mut)]
|
#[allow(unused_variables, unused_mut)]
|
||||||
let mut drain = args.iter_mut();
|
let mut drain = args.iter_mut();
|
||||||
$(
|
$(
|
||||||
// Downcast every element, return in case of a type mismatch
|
// Downcast every element, panic in case of a type mismatch (which shouldn't happen).
|
||||||
let $par: &mut $par = drain.next().unwrap().downcast_mut().unwrap();
|
// Call the user-supplied function using ($convert) to access it either by value or by reference.
|
||||||
|
let $par = ($convert)(drain.next().unwrap());
|
||||||
)*
|
)*
|
||||||
|
|
||||||
// Call the user-supplied function using ($clone) to
|
// Call the function with each parameter value
|
||||||
// potentially clone the value, otherwise pass the reference.
|
let r = $fn($($par),*);
|
||||||
let r = $fn($(($clone)($par)),*);
|
|
||||||
|
// Map the result
|
||||||
$map(r, pos)
|
$map(r, pos)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@ -259,18 +264,17 @@ macro_rules! def_register {
|
|||||||
//def_register!(imp_pop $($par => $mark => $param),*);
|
//def_register!(imp_pop $($par => $mark => $param),*);
|
||||||
};
|
};
|
||||||
($p0:ident $(, $p:ident)*) => {
|
($p0:ident $(, $p:ident)*) => {
|
||||||
def_register!(imp $p0 => $p0 => $p0 => cloned $(, $p => $p => $p => cloned)*);
|
def_register!(imp $p0 => $p0 => $p0 => by_value $(, $p => $p => $p => by_value)*);
|
||||||
def_register!(imp $p0 => Mut<$p0> => &mut $p0 => identity $(, $p => $p => $p => cloned)*);
|
def_register!(imp $p0 => Mut<$p0> => &mut $p0 => by_ref $(, $p => $p => $p => by_value)*);
|
||||||
// handle the first parameter ^ first parameter passed through
|
// handle the first parameter ^ first parameter passed through
|
||||||
// ^ others passed by value (cloned)
|
// ^ others passed by value (by_value)
|
||||||
|
|
||||||
// Currently does not support first argument which is a reference, as there will be
|
// Currently does not support first argument which is a reference, as there will be
|
||||||
// conflicting implementations since &T: Any and T: Any cannot be distinguished
|
// conflicting implementations since &T: Any and T: Any cannot be distinguished
|
||||||
//def_register!(imp $p0 => Ref<$p0> => &$p0 => identity $(, $p => $p => $p => Clone::clone)*);
|
//def_register!(imp $p0 => Ref<$p0> => &$p0 => by_ref $(, $p => $p => $p => by_value)*);
|
||||||
|
|
||||||
def_register!($($p),*);
|
def_register!($($p),*);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rustfmt::skip]
|
|
||||||
def_register!(A, B, C, D, E, F, G, H, J, K, L, M, N, P, Q, R, S, T, U, V);
|
def_register!(A, B, C, D, E, F, G, H, J, K, L, M, N, P, Q, R, S, T, U, V);
|
||||||
|
@ -371,12 +371,7 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
(Expr::Variable(var, sp, _), Expr::Variable(var2, sp2, _)) if var == var2 && sp == sp2 => {
|
(Expr::Variable(var, sp, _), Expr::Variable(var2, sp2, _)) if var == var2 && sp == sp2 => {
|
||||||
// Assignment to the same variable - fold
|
// Assignment to the same variable - fold
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
|
Expr::Assignment(Box::new(Expr::Variable(var, sp, pos)), Box::new(optimize_expr(*expr2, state)), pos)
|
||||||
Expr::Assignment(
|
|
||||||
Box::new(Expr::Variable(var, sp, pos)),
|
|
||||||
Box::new(optimize_expr(*expr2, state)),
|
|
||||||
pos,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
// id1 = id2 = expr2
|
// id1 = id2 = expr2
|
||||||
(id1, id2) => Expr::Assignment(
|
(id1, id2) => Expr::Assignment(
|
||||||
|
@ -15,7 +15,7 @@ use crate::stdlib::{
|
|||||||
format,
|
format,
|
||||||
iter::Peekable,
|
iter::Peekable,
|
||||||
num::NonZeroUsize,
|
num::NonZeroUsize,
|
||||||
ops::Add,
|
ops::{Add, Deref, DerefMut},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
@ -193,18 +193,6 @@ impl Stack {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self(Vec::new())
|
Self(Vec::new())
|
||||||
}
|
}
|
||||||
/// Get the number of variables in the `Stack`.
|
|
||||||
pub fn len(&self) -> usize {
|
|
||||||
self.0.len()
|
|
||||||
}
|
|
||||||
/// Push (add) a new variable onto the `Stack`.
|
|
||||||
pub fn push(&mut self, name: String) {
|
|
||||||
self.0.push(name);
|
|
||||||
}
|
|
||||||
/// Rewind the stack to a previous size.
|
|
||||||
pub fn rewind(&mut self, len: usize) {
|
|
||||||
self.0.truncate(len);
|
|
||||||
}
|
|
||||||
/// Find a variable by name in the `Stack`, searching in reverse.
|
/// Find a variable by name in the `Stack`, searching in reverse.
|
||||||
/// The return value is the offset to be deducted from `Stack::len`,
|
/// The return value is the offset to be deducted from `Stack::len`,
|
||||||
/// i.e. the top element of the `Stack` is offset 1.
|
/// i.e. the top element of the `Stack` is offset 1.
|
||||||
@ -219,6 +207,20 @@ impl Stack {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Deref for Stack {
|
||||||
|
type Target = Vec<String>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DerefMut for Stack {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
&mut self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A statement.
|
/// A statement.
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Stmt {
|
pub enum Stmt {
|
||||||
@ -1639,7 +1641,7 @@ fn parse_for<'a>(
|
|||||||
|
|
||||||
let body = parse_block(input, stack, true, allow_stmt_expr)?;
|
let body = parse_block(input, stack, true, allow_stmt_expr)?;
|
||||||
|
|
||||||
stack.rewind(prev_len);
|
stack.truncate(prev_len);
|
||||||
|
|
||||||
Ok(Stmt::For(Box::new(name), Box::new(expr), Box::new(body)))
|
Ok(Stmt::For(Box::new(name), Box::new(expr), Box::new(body)))
|
||||||
}
|
}
|
||||||
@ -1747,7 +1749,7 @@ fn parse_block<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stack.rewind(prev_len);
|
stack.truncate(prev_len);
|
||||||
|
|
||||||
Ok(Stmt::Block(statements, pos))
|
Ok(Stmt::Block(statements, pos))
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user