Avoid copying arguments for function calls.
This commit is contained in:
parent
fc66a7ecef
commit
d83b829810
33
README.md
33
README.md
@ -374,19 +374,19 @@ engine.load_package(package.get()); // load the package manually
|
||||
|
||||
The follow packages are available:
|
||||
|
||||
| Package | Description | In `CorePackage` | In `StandardPackage` |
|
||||
| ------------------------ | ----------------------------------------------- | :--------------: | :------------------: |
|
||||
| `ArithmeticPackage` | Arithmetic operators (e.g. `+`, `-`, `*`, `/`) | Yes | Yes |
|
||||
| `BasicIteratorPackage` | Numeric ranges (e.g. `range(1, 10)`) | Yes | Yes |
|
||||
| `LogicPackage` | Logic and comparison operators (e.g. `==`, `>`) | Yes | Yes |
|
||||
| `BasicStringPackage` | Basic string functions | Yes | Yes |
|
||||
| `BasicTimePackage` | Basic time functions (e.g. [timestamps]) | Yes | Yes |
|
||||
| `MoreStringPackage` | Additional string functions | No | Yes |
|
||||
| `BasicMathPackage` | Basic math functions (e.g. `sin`, `sqrt`) | No | Yes |
|
||||
| `BasicArrayPackage` | Basic [array] functions | No | Yes |
|
||||
| `BasicMapPackage` | Basic [object map] functions | No | Yes |
|
||||
| `CorePackage` | Basic essentials | | |
|
||||
| `StandardPackage` | Standard library | | |
|
||||
| Package | Description | In `CorePackage` | In `StandardPackage` |
|
||||
| ---------------------- | ----------------------------------------------- | :--------------: | :------------------: |
|
||||
| `ArithmeticPackage` | Arithmetic operators (e.g. `+`, `-`, `*`, `/`) | Yes | Yes |
|
||||
| `BasicIteratorPackage` | Numeric ranges (e.g. `range(1, 10)`) | Yes | Yes |
|
||||
| `LogicPackage` | Logic and comparison operators (e.g. `==`, `>`) | Yes | Yes |
|
||||
| `BasicStringPackage` | Basic string functions | Yes | Yes |
|
||||
| `BasicTimePackage` | Basic time functions (e.g. [timestamps]) | Yes | Yes |
|
||||
| `MoreStringPackage` | Additional string functions | No | Yes |
|
||||
| `BasicMathPackage` | Basic math functions (e.g. `sin`, `sqrt`) | No | Yes |
|
||||
| `BasicArrayPackage` | Basic [array] functions | No | Yes |
|
||||
| `BasicMapPackage` | Basic [object map] functions | No | Yes |
|
||||
| `CorePackage` | Basic essentials | | |
|
||||
| `StandardPackage` | Standard library | | |
|
||||
|
||||
Evaluate expressions only
|
||||
-------------------------
|
||||
@ -427,7 +427,7 @@ The following primitive types are supported natively:
|
||||
| **Boolean value** | `bool` | `"bool"` | `"true"` or `"false"` |
|
||||
| **Unicode character** | `char` | `"char"` | `"A"`, `"x"` 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 }` |
|
||||
| **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_ |
|
||||
@ -1372,7 +1372,8 @@ y[2] == 3;
|
||||
y[3] == 4;
|
||||
|
||||
(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
|
||||
|
||||
@ -1494,7 +1495,7 @@ y.a == 42;
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
/// ```
|
||||
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`.
|
||||
|
@ -692,7 +692,7 @@ impl Engine {
|
||||
&self,
|
||||
fn_lib: &FunctionsLib,
|
||||
fn_name: &str,
|
||||
args: &mut [&mut Dynamic],
|
||||
args: &mut FnCallArgs,
|
||||
def_val: Option<&Dynamic>,
|
||||
pos: Position,
|
||||
level: usize,
|
||||
@ -1227,7 +1227,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Expr::Array(contents, _) => Ok(Dynamic(Union::Array(Box::new(
|
||||
contents
|
||||
.into_iter()
|
||||
.iter()
|
||||
.map(|item| self.eval_expr(scope, state, fn_lib, item, level))
|
||||
.collect::<Result<Vec<_>, _>>()?,
|
||||
)))),
|
||||
@ -1235,9 +1235,9 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Expr::Map(contents, _) => Ok(Dynamic(Union::Map(Box::new(
|
||||
contents
|
||||
.into_iter()
|
||||
.iter()
|
||||
.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))
|
||||
})
|
||||
.collect::<Result<HashMap<_, _>, _>>()?,
|
||||
|
@ -22,7 +22,7 @@ macro_rules! impl_args {
|
||||
fn into_vec(self) -> Vec<Dynamic> {
|
||||
let ($($p,)*) = self;
|
||||
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
#[allow(unused_mut)]
|
||||
let mut v = Vec::new();
|
||||
$(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);
|
||||
|
@ -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);
|
||||
|
@ -7,7 +7,7 @@ use crate::engine::{calc_fn_spec, Engine, FnCallArgs};
|
||||
use crate::result::EvalAltResult;
|
||||
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`.
|
||||
pub trait RegisterFn<FN, ARGS, RET> {
|
||||
@ -115,16 +115,19 @@ pub trait RegisterResultFn<FN, ARGS, RET> {
|
||||
pub struct Mut<T>(T);
|
||||
//pub struct Ref<T>(T);
|
||||
|
||||
/// Identity dereferencing function.
|
||||
/// Dereference into &mut.
|
||||
#[inline]
|
||||
pub fn identity<T>(data: &mut T) -> &mut T {
|
||||
data
|
||||
pub fn by_ref<T: Clone + 'static>(data: &mut Dynamic) -> &mut T {
|
||||
// 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]
|
||||
pub fn cloned<T: Clone>(data: &mut T) -> T {
|
||||
data.clone()
|
||||
pub fn by_value<T: Clone + 'static>(data: &mut Dynamic) -> T {
|
||||
// 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.
|
||||
@ -135,7 +138,7 @@ macro_rules! count_args {
|
||||
|
||||
/// This macro creates a closure wrapping a registered function.
|
||||
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 pointer
|
||||
// ^ result mapping function
|
||||
@ -153,14 +156,16 @@ macro_rules! make_func {
|
||||
#[allow(unused_variables, unused_mut)]
|
||||
let mut drain = args.iter_mut();
|
||||
$(
|
||||
// Downcast every element, return in case of a type mismatch
|
||||
let $par: &mut $par = drain.next().unwrap().downcast_mut().unwrap();
|
||||
// Downcast every element, panic in case of a type mismatch (which shouldn't happen).
|
||||
// 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
|
||||
// potentially clone the value, otherwise pass the reference.
|
||||
let r = $fn($(($clone)($par)),*);
|
||||
$map(r, pos)
|
||||
// Call the function with each parameter value
|
||||
let r = $fn($($par),*);
|
||||
|
||||
// Map the result
|
||||
$map(r, pos)
|
||||
};
|
||||
};
|
||||
}
|
||||
@ -259,18 +264,17 @@ macro_rules! def_register {
|
||||
//def_register!(imp_pop $($par => $mark => $param),*);
|
||||
};
|
||||
($p0:ident $(, $p:ident)*) => {
|
||||
def_register!(imp $p0 => $p0 => $p0 => cloned $(, $p => $p => $p => cloned)*);
|
||||
def_register!(imp $p0 => Mut<$p0> => &mut $p0 => identity $(, $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 => by_ref $(, $p => $p => $p => by_value)*);
|
||||
// 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
|
||||
// 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),*);
|
||||
};
|
||||
}
|
||||
|
||||
#[rustfmt::skip]
|
||||
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 => {
|
||||
// Assignment to the same variable - fold
|
||||
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) => Expr::Assignment(
|
||||
|
@ -15,7 +15,7 @@ use crate::stdlib::{
|
||||
format,
|
||||
iter::Peekable,
|
||||
num::NonZeroUsize,
|
||||
ops::Add,
|
||||
ops::{Add, Deref, DerefMut},
|
||||
rc::Rc,
|
||||
string::{String, ToString},
|
||||
sync::Arc,
|
||||
@ -193,18 +193,6 @@ impl Stack {
|
||||
pub fn new() -> Self {
|
||||
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.
|
||||
/// The return value is the offset to be deducted from `Stack::len`,
|
||||
/// 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.
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Stmt {
|
||||
@ -1639,7 +1641,7 @@ fn parse_for<'a>(
|
||||
|
||||
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)))
|
||||
}
|
||||
@ -1747,7 +1749,7 @@ fn parse_block<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
stack.rewind(prev_len);
|
||||
stack.truncate(prev_len);
|
||||
|
||||
Ok(Stmt::Block(statements, pos))
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user