Refine no_function feature.
This commit is contained in:
parent
467b109c23
commit
d626bf9f5b
@ -21,7 +21,7 @@ num-traits = { version = "0.2.11", default-features = false }
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
#default = ["unchecked", "sync", "no_optimize", "no_float", "only_i32", "no_index", "no_object", "no_function", "no_module"]
|
#default = ["unchecked", "sync", "no_optimize", "no_float", "only_i32", "no_index", "no_object", "no_function", "no_module"]
|
||||||
default = ["serde"]
|
default = []
|
||||||
plugins = []
|
plugins = []
|
||||||
unchecked = [] # unchecked arithmetic
|
unchecked = [] # unchecked arithmetic
|
||||||
sync = [] # restrict to only types that implement Send + Sync
|
sync = [] # restrict to only types that implement Send + Sync
|
||||||
|
@ -29,7 +29,7 @@ Features
|
|||||||
* Fairly efficient evaluation (1 million iterations in 0.4 sec on a single core, 2.3 GHz Linux VM).
|
* Fairly efficient evaluation (1 million iterations in 0.4 sec on a single core, 2.3 GHz Linux VM).
|
||||||
* Relatively little `unsafe` code (yes there are some for performance reasons, and most `unsafe` code is limited to
|
* Relatively little `unsafe` code (yes there are some for performance reasons, and most `unsafe` code is limited to
|
||||||
one single source file, all with names starting with `"unsafe_"`).
|
one single source file, all with names starting with `"unsafe_"`).
|
||||||
* Re-entrant scripting engine can be made `Send + Sync` (via the [`sync`] feature).
|
* Re-entrant scripting engine can be made `Send + Sync` (via the `sync` feature).
|
||||||
* Sand-boxed - the scripting engine, if declared immutable, cannot mutate the containing environment unless explicitly permitted (e.g. via a `RefCell`).
|
* Sand-boxed - the scripting engine, if declared immutable, cannot mutate the containing environment unless explicitly permitted (e.g. via a `RefCell`).
|
||||||
* Rugged - protected against malicious attacks (such as [stack-overflow](https://schungx.github.io/rhai/safety/max-call-stack.html), [over-sized data](https://schungx.github.io/rhai/safety/max-string-size.html), and [runaway scripts](https://schungx.github.io/rhai/safety/max-operations.html) etc.) that may come from untrusted third-party user-land scripts.
|
* Rugged - protected against malicious attacks (such as [stack-overflow](https://schungx.github.io/rhai/safety/max-call-stack.html), [over-sized data](https://schungx.github.io/rhai/safety/max-string-size.html), and [runaway scripts](https://schungx.github.io/rhai/safety/max-operations.html) etc.) that may come from untrusted third-party user-land scripts.
|
||||||
* Track script evaluation [progress](https://schungx.github.io/rhai/safety/progress.html) and manually terminate a script run.
|
* Track script evaluation [progress](https://schungx.github.io/rhai/safety/progress.html) and manually terminate a script run.
|
||||||
@ -38,7 +38,7 @@ Features
|
|||||||
* Dynamic dispatch via [function pointers](https://schungx.github.io/rhai/language/fn-ptr.html).
|
* Dynamic dispatch via [function pointers](https://schungx.github.io/rhai/language/fn-ptr.html).
|
||||||
* Some support for [object-oriented programming (OOP)](https://schungx.github.io/rhai/language/oop.html).
|
* Some support for [object-oriented programming (OOP)](https://schungx.github.io/rhai/language/oop.html).
|
||||||
* Organize code base with dynamically-loadable [modules](https://schungx.github.io/rhai/language/modules.html).
|
* Organize code base with dynamically-loadable [modules](https://schungx.github.io/rhai/language/modules.html).
|
||||||
* Serialization/deserialization support via [serde](https://crates.io/crates/serde)
|
* Serialization/deserialization support via [serde](https://crates.io/crates/serde) (requires the `serde` feature).
|
||||||
* Scripts are [optimized](https://schungx.github.io/rhai/engine/optimize.html) (useful for template-based machine-generated scripts) for repeated evaluations.
|
* Scripts are [optimized](https://schungx.github.io/rhai/engine/optimize.html) (useful for template-based machine-generated scripts) for repeated evaluations.
|
||||||
* Support for [minimal builds](https://schungx.github.io/rhai/start/builds/minimal.html) by excluding unneeded language [features](https://schungx.github.io/rhai/start/features.html).
|
* Support for [minimal builds](https://schungx.github.io/rhai/start/builds/minimal.html) by excluding unneeded language [features](https://schungx.github.io/rhai/start/features.html).
|
||||||
|
|
||||||
|
13
src/api.rs
13
src/api.rs
@ -1,10 +1,7 @@
|
|||||||
//! Module that defines the extern API of `Engine`.
|
//! Module that defines the extern API of `Engine`.
|
||||||
|
|
||||||
use crate::any::{Dynamic, Variant};
|
use crate::any::{Dynamic, Variant};
|
||||||
use crate::engine::{
|
use crate::engine::{make_getter, make_setter, Engine, Imports, State, FN_IDX_GET, FN_IDX_SET};
|
||||||
get_script_function_by_signature, make_getter, make_setter, Engine, Imports, State, FN_IDX_GET,
|
|
||||||
FN_IDX_SET,
|
|
||||||
};
|
|
||||||
use crate::error::ParseError;
|
use crate::error::ParseError;
|
||||||
use crate::fn_call::FuncArgs;
|
use crate::fn_call::FuncArgs;
|
||||||
use crate::fn_native::{IteratorFn, SendSync};
|
use crate::fn_native::{IteratorFn, SendSync};
|
||||||
@ -19,6 +16,9 @@ use crate::utils::StaticVec;
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::engine::Map;
|
use crate::engine::Map;
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
use crate::engine::get_script_function_by_signature;
|
||||||
|
|
||||||
use crate::stdlib::{
|
use crate::stdlib::{
|
||||||
any::{type_name, TypeId},
|
any::{type_name, TypeId},
|
||||||
boxed::Box,
|
boxed::Box,
|
||||||
@ -1189,6 +1189,7 @@ impl Engine {
|
|||||||
/// This is to avoid unnecessarily cloning the arguments.
|
/// This is to avoid unnecessarily cloning the arguments.
|
||||||
/// Do not use the arguments after this call. If they are needed afterwards,
|
/// Do not use the arguments after this call. If they are needed afterwards,
|
||||||
/// clone them _before_ calling this function.
|
/// clone them _before_ calling this function.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub(crate) fn call_fn_dynamic_raw(
|
pub(crate) fn call_fn_dynamic_raw(
|
||||||
&self,
|
&self,
|
||||||
scope: &mut Scope,
|
scope: &mut Scope,
|
||||||
@ -1240,6 +1241,7 @@ impl Engine {
|
|||||||
mut ast: AST,
|
mut ast: AST,
|
||||||
optimization_level: OptimizationLevel,
|
optimization_level: OptimizationLevel,
|
||||||
) -> AST {
|
) -> AST {
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
let lib = ast
|
let lib = ast
|
||||||
.lib()
|
.lib()
|
||||||
.iter_fn()
|
.iter_fn()
|
||||||
@ -1247,6 +1249,9 @@ impl Engine {
|
|||||||
.map(|(_, _, _, f)| f.get_fn_def().clone())
|
.map(|(_, _, _, f)| f.get_fn_def().clone())
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
#[cfg(feature = "no_function")]
|
||||||
|
let lib = Default::default();
|
||||||
|
|
||||||
let stmt = mem::take(ast.statements_mut());
|
let stmt = mem::take(ast.statements_mut());
|
||||||
optimize_into_ast(self, scope, stmt, lib, optimization_level)
|
optimize_into_ast(self, scope, stmt, lib, optimization_level)
|
||||||
}
|
}
|
||||||
|
@ -216,6 +216,7 @@ impl State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get a script-defined function definition from a module.
|
/// Get a script-defined function definition from a module.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub fn get_script_function_by_signature<'a>(
|
pub fn get_script_function_by_signature<'a>(
|
||||||
module: &'a Module,
|
module: &'a Module,
|
||||||
name: &str,
|
name: &str,
|
||||||
@ -767,22 +768,23 @@ impl Engine {
|
|||||||
.or_else(|| self.packages.get_fn(hash_fn));
|
.or_else(|| self.packages.get_fn(hash_fn));
|
||||||
|
|
||||||
if let Some(func) = func {
|
if let Some(func) = func {
|
||||||
// Calling pure function but the first argument is a reference?
|
#[cfg(not(feature = "no_function"))]
|
||||||
normalize_first_arg(
|
let need_normalize = is_ref && (func.is_pure() || (func.is_script() && !is_method));
|
||||||
is_ref && (func.is_pure() || (func.is_script() && !is_method)),
|
#[cfg(feature = "no_function")]
|
||||||
&mut this_copy,
|
let need_normalize = is_ref && func.is_pure();
|
||||||
&mut old_this_ptr,
|
|
||||||
args,
|
|
||||||
);
|
|
||||||
|
|
||||||
|
// Calling pure function but the first argument is a reference?
|
||||||
|
normalize_first_arg(need_normalize, &mut this_copy, &mut old_this_ptr, args);
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
if func.is_script() {
|
if func.is_script() {
|
||||||
// Run scripted function
|
// Run scripted function
|
||||||
let fn_def = func.get_fn_def();
|
let fn_def = func.get_fn_def();
|
||||||
|
|
||||||
// Method call of script function - map first argument to `this`
|
// Method call of script function - map first argument to `this`
|
||||||
if is_method {
|
return if is_method {
|
||||||
let (first, rest) = args.split_at_mut(1);
|
let (first, rest) = args.split_at_mut(1);
|
||||||
return Ok((
|
Ok((
|
||||||
self.call_script_fn(
|
self.call_script_fn(
|
||||||
scope,
|
scope,
|
||||||
mods,
|
mods,
|
||||||
@ -795,7 +797,7 @@ impl Engine {
|
|||||||
level,
|
level,
|
||||||
)?,
|
)?,
|
||||||
false,
|
false,
|
||||||
));
|
))
|
||||||
} else {
|
} else {
|
||||||
let result = self.call_script_fn(
|
let result = self.call_script_fn(
|
||||||
scope, mods, state, lib, &mut None, fn_name, fn_def, args, level,
|
scope, mods, state, lib, &mut None, fn_name, fn_def, args, level,
|
||||||
@ -804,42 +806,42 @@ impl Engine {
|
|||||||
// Restore the original reference
|
// Restore the original reference
|
||||||
restore_first_arg(old_this_ptr, args);
|
restore_first_arg(old_this_ptr, args);
|
||||||
|
|
||||||
return Ok((result, false));
|
Ok((result, false))
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
// Run external function
|
|
||||||
let result = func.get_native_fn()(self, args)?;
|
|
||||||
|
|
||||||
// Restore the original reference
|
|
||||||
restore_first_arg(old_this_ptr, args);
|
|
||||||
|
|
||||||
// See if the function match print/debug (which requires special processing)
|
|
||||||
return Ok(match fn_name {
|
|
||||||
KEYWORD_PRINT => (
|
|
||||||
(self.print)(result.as_str().map_err(|typ| {
|
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
|
||||||
self.map_type_name(type_name::<ImmutableString>()).into(),
|
|
||||||
typ.into(),
|
|
||||||
Position::none(),
|
|
||||||
))
|
|
||||||
})?)
|
|
||||||
.into(),
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
KEYWORD_DEBUG => (
|
|
||||||
(self.debug)(result.as_str().map_err(|typ| {
|
|
||||||
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
|
||||||
self.map_type_name(type_name::<ImmutableString>()).into(),
|
|
||||||
typ.into(),
|
|
||||||
Position::none(),
|
|
||||||
))
|
|
||||||
})?)
|
|
||||||
.into(),
|
|
||||||
false,
|
|
||||||
),
|
|
||||||
_ => (result, func.is_method()),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Run external function
|
||||||
|
let result = func.get_native_fn()(self, args)?;
|
||||||
|
|
||||||
|
// Restore the original reference
|
||||||
|
restore_first_arg(old_this_ptr, args);
|
||||||
|
|
||||||
|
// See if the function match print/debug (which requires special processing)
|
||||||
|
return Ok(match fn_name {
|
||||||
|
KEYWORD_PRINT => (
|
||||||
|
(self.print)(result.as_str().map_err(|typ| {
|
||||||
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
|
self.map_type_name(type_name::<ImmutableString>()).into(),
|
||||||
|
typ.into(),
|
||||||
|
Position::none(),
|
||||||
|
))
|
||||||
|
})?)
|
||||||
|
.into(),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
KEYWORD_DEBUG => (
|
||||||
|
(self.debug)(result.as_str().map_err(|typ| {
|
||||||
|
Box::new(EvalAltResult::ErrorMismatchOutputType(
|
||||||
|
self.map_type_name(type_name::<ImmutableString>()).into(),
|
||||||
|
typ.into(),
|
||||||
|
Position::none(),
|
||||||
|
))
|
||||||
|
})?)
|
||||||
|
.into(),
|
||||||
|
false,
|
||||||
|
),
|
||||||
|
_ => (result, func.is_method()),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// See if it is built in.
|
// See if it is built in.
|
||||||
@ -2016,6 +2018,7 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
match func {
|
match func {
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
Ok(f) if f.is_script() => {
|
Ok(f) if f.is_script() => {
|
||||||
let args = args.as_mut();
|
let args = args.as_mut();
|
||||||
let fn_def = f.get_fn_def();
|
let fn_def = f.get_fn_def();
|
||||||
|
@ -114,6 +114,7 @@ pub enum CallableFunction {
|
|||||||
/// An iterator function.
|
/// An iterator function.
|
||||||
Iterator(IteratorFn),
|
Iterator(IteratorFn),
|
||||||
/// A script-defined function.
|
/// A script-defined function.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
Script(Shared<ScriptFnDef>),
|
Script(Shared<ScriptFnDef>),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -123,6 +124,8 @@ impl fmt::Debug for CallableFunction {
|
|||||||
Self::Pure(_) => write!(f, "NativePureFunction"),
|
Self::Pure(_) => write!(f, "NativePureFunction"),
|
||||||
Self::Method(_) => write!(f, "NativeMethod"),
|
Self::Method(_) => write!(f, "NativeMethod"),
|
||||||
Self::Iterator(_) => write!(f, "NativeIterator"),
|
Self::Iterator(_) => write!(f, "NativeIterator"),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(fn_def) => fmt::Debug::fmt(fn_def, f),
|
Self::Script(fn_def) => fmt::Debug::fmt(fn_def, f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,6 +137,8 @@ impl fmt::Display for CallableFunction {
|
|||||||
Self::Pure(_) => write!(f, "NativePureFunction"),
|
Self::Pure(_) => write!(f, "NativePureFunction"),
|
||||||
Self::Method(_) => write!(f, "NativeMethod"),
|
Self::Method(_) => write!(f, "NativeMethod"),
|
||||||
Self::Iterator(_) => write!(f, "NativeIterator"),
|
Self::Iterator(_) => write!(f, "NativeIterator"),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
CallableFunction::Script(s) => fmt::Display::fmt(s, f),
|
CallableFunction::Script(s) => fmt::Display::fmt(s, f),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,24 +149,34 @@ impl CallableFunction {
|
|||||||
pub fn is_pure(&self) -> bool {
|
pub fn is_pure(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(_) => true,
|
Self::Pure(_) => true,
|
||||||
Self::Method(_) | Self::Iterator(_) | Self::Script(_) => false,
|
Self::Method(_) | Self::Iterator(_) => false,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
Self::Script(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this a native Rust method function?
|
/// Is this a native Rust method function?
|
||||||
pub fn is_method(&self) -> bool {
|
pub fn is_method(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Method(_) => true,
|
Self::Method(_) => true,
|
||||||
Self::Pure(_) | Self::Iterator(_) | Self::Script(_) => false,
|
Self::Pure(_) | Self::Iterator(_) => false,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
Self::Script(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this an iterator function?
|
/// Is this an iterator function?
|
||||||
pub fn is_iter(&self) -> bool {
|
pub fn is_iter(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Iterator(_) => true,
|
Self::Iterator(_) => true,
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Script(_) => false,
|
Self::Pure(_) | Self::Method(_) => false,
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
Self::Script(_) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this a Rhai-scripted function?
|
/// Is this a Rhai-scripted function?
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub fn is_script(&self) -> bool {
|
pub fn is_script(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Script(_) => true,
|
Self::Script(_) => true,
|
||||||
@ -176,7 +191,10 @@ impl CallableFunction {
|
|||||||
pub fn get_native_fn(&self) -> &FnAny {
|
pub fn get_native_fn(&self) -> &FnAny {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(f) | Self::Method(f) => f.as_ref(),
|
Self::Pure(f) | Self::Method(f) => f.as_ref(),
|
||||||
Self::Iterator(_) | Self::Script(_) => unreachable!(),
|
Self::Iterator(_) => unreachable!(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
Self::Script(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Get a shared reference to a script-defined function definition.
|
/// Get a shared reference to a script-defined function definition.
|
||||||
@ -184,6 +202,7 @@ impl CallableFunction {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the `CallableFunction` is not `Script`.
|
/// Panics if the `CallableFunction` is not `Script`.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub fn get_shared_fn_def(&self) -> Shared<ScriptFnDef> {
|
pub fn get_shared_fn_def(&self) -> Shared<ScriptFnDef> {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => unreachable!(),
|
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => unreachable!(),
|
||||||
@ -195,6 +214,7 @@ impl CallableFunction {
|
|||||||
/// # Panics
|
/// # Panics
|
||||||
///
|
///
|
||||||
/// Panics if the `CallableFunction` is not `Script`.
|
/// Panics if the `CallableFunction` is not `Script`.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub fn get_fn_def(&self) -> &ScriptFnDef {
|
pub fn get_fn_def(&self) -> &ScriptFnDef {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => unreachable!(),
|
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => unreachable!(),
|
||||||
@ -209,7 +229,10 @@ impl CallableFunction {
|
|||||||
pub fn get_iter_fn(&self) -> IteratorFn {
|
pub fn get_iter_fn(&self) -> IteratorFn {
|
||||||
match self {
|
match self {
|
||||||
Self::Iterator(f) => *f,
|
Self::Iterator(f) => *f,
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Script(_) => unreachable!(),
|
Self::Pure(_) | Self::Method(_) => unreachable!(),
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
Self::Script(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Create a new `CallableFunction::Pure`.
|
/// Create a new `CallableFunction::Pure`.
|
||||||
@ -228,12 +251,14 @@ impl From<IteratorFn> for CallableFunction {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
impl From<ScriptFnDef> for CallableFunction {
|
impl From<ScriptFnDef> for CallableFunction {
|
||||||
fn from(func: ScriptFnDef) -> Self {
|
fn from(func: ScriptFnDef) -> Self {
|
||||||
Self::Script(func.into())
|
Self::Script(func.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
impl From<Shared<ScriptFnDef>> for CallableFunction {
|
impl From<Shared<ScriptFnDef>> for CallableFunction {
|
||||||
fn from(func: Shared<ScriptFnDef>) -> Self {
|
fn from(func: Shared<ScriptFnDef>) -> Self {
|
||||||
Self::Script(func)
|
Self::Script(func)
|
||||||
|
@ -125,17 +125,23 @@ pub use parser::FLOAT;
|
|||||||
pub use module::ModuleResolver;
|
pub use module::ModuleResolver;
|
||||||
|
|
||||||
/// Module containing all built-in _module resolvers_ available to Rhai.
|
/// Module containing all built-in _module resolvers_ available to Rhai.
|
||||||
|
///
|
||||||
|
/// Not available under the `no_module` feature.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
pub mod module_resolvers {
|
pub mod module_resolvers {
|
||||||
pub use crate::module::resolvers::*;
|
pub use crate::module::resolvers::*;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Serialization support for [`serde`](https://crates.io/crates/serde).
|
/// Serialization support for [`serde`](https://crates.io/crates/serde).
|
||||||
|
///
|
||||||
|
/// Requires the `serde` feature.
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
pub mod ser {
|
pub mod ser {
|
||||||
pub use crate::serde::ser::to_dynamic;
|
pub use crate::serde::ser::to_dynamic;
|
||||||
}
|
}
|
||||||
/// Deserialization support for [`serde`](https://crates.io/crates/serde).
|
/// Deserialization support for [`serde`](https://crates.io/crates/serde).
|
||||||
|
///
|
||||||
|
/// Requires the `serde` feature.
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
pub mod de {
|
pub mod de {
|
||||||
pub use crate::serde::de::from_dynamic;
|
pub use crate::serde::de::from_dynamic;
|
||||||
|
@ -236,6 +236,7 @@ impl Module {
|
|||||||
/// Set a script-defined function into the module.
|
/// Set a script-defined function into the module.
|
||||||
///
|
///
|
||||||
/// If there is an existing function of the same name and number of arguments, it is replaced.
|
/// If there is an existing function of the same name and number of arguments, it is replaced.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub(crate) fn set_script_fn(&mut self, fn_def: ScriptFnDef) {
|
pub(crate) fn set_script_fn(&mut self, fn_def: ScriptFnDef) {
|
||||||
// None + function name + number of arguments.
|
// None + function name + number of arguments.
|
||||||
let hash_script = calc_fn_hash(empty(), &fn_def.name, fn_def.params.len(), empty());
|
let hash_script = calc_fn_hash(empty(), &fn_def.name, fn_def.params.len(), empty());
|
||||||
@ -876,6 +877,7 @@ impl Module {
|
|||||||
.functions
|
.functions
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(_, (_, _, _, v))| match v {
|
.filter(|(_, (_, _, _, v))| match v {
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
CallableFunction::Script(ref f) => {
|
CallableFunction::Script(ref f) => {
|
||||||
filter(f.access, f.name.as_str(), f.params.len())
|
filter(f.access, f.name.as_str(), f.params.len())
|
||||||
}
|
}
|
||||||
@ -893,6 +895,7 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Filter out the functions, retaining only some based on a filter predicate.
|
/// Filter out the functions, retaining only some based on a filter predicate.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub(crate) fn retain_functions(&mut self, filter: impl Fn(FnAccess, &str, usize) -> bool) {
|
pub(crate) fn retain_functions(&mut self, filter: impl Fn(FnAccess, &str, usize) -> bool) {
|
||||||
self.functions.retain(|_, (_, _, _, v)| match v {
|
self.functions.retain(|_, (_, _, _, v)| match v {
|
||||||
CallableFunction::Script(ref f) => filter(f.access, f.name.as_str(), f.params.len()),
|
CallableFunction::Script(ref f) => filter(f.access, f.name.as_str(), f.params.len()),
|
||||||
@ -930,6 +933,7 @@ impl Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Get an iterator over all script-defined functions in the module.
|
/// Get an iterator over all script-defined functions in the module.
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub fn iter_script_fn<'a>(&'a self) -> impl Iterator<Item = Shared<ScriptFnDef>> + 'a {
|
pub fn iter_script_fn<'a>(&'a self) -> impl Iterator<Item = Shared<ScriptFnDef>> + 'a {
|
||||||
self.functions
|
self.functions
|
||||||
.values()
|
.values()
|
||||||
@ -1014,6 +1018,7 @@ impl Module {
|
|||||||
Public => (),
|
Public => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_function"))]
|
||||||
if func.is_script() {
|
if func.is_script() {
|
||||||
let fn_def = func.get_shared_fn_def();
|
let fn_def = func.get_shared_fn_def();
|
||||||
// Qualifiers + function name + number of arguments.
|
// Qualifiers + function name + number of arguments.
|
||||||
@ -1024,20 +1029,21 @@ impl Module {
|
|||||||
empty(),
|
empty(),
|
||||||
);
|
);
|
||||||
functions.push((hash_qualified_script, fn_def.into()));
|
functions.push((hash_qualified_script, fn_def.into()));
|
||||||
} else {
|
continue;
|
||||||
// Qualified Rust functions are indexed in two steps:
|
|
||||||
// 1) Calculate a hash in a similar manner to script-defined functions,
|
|
||||||
// i.e. qualifiers + function name + number of arguments.
|
|
||||||
let hash_qualified_script =
|
|
||||||
calc_fn_hash(qualifiers.iter().map(|&v| v), name, params.len(), empty());
|
|
||||||
// 2) Calculate a second hash with no qualifiers, empty function name,
|
|
||||||
// zero number of arguments, and the actual list of argument `TypeId`'.s
|
|
||||||
let hash_fn_args = calc_fn_hash(empty(), "", 0, params.iter().cloned());
|
|
||||||
// 3) The final hash is the XOR of the two hashes.
|
|
||||||
let hash_qualified_fn = hash_qualified_script ^ hash_fn_args;
|
|
||||||
|
|
||||||
functions.push((hash_qualified_fn, func.clone()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Qualified Rust functions are indexed in two steps:
|
||||||
|
// 1) Calculate a hash in a similar manner to script-defined functions,
|
||||||
|
// i.e. qualifiers + function name + number of arguments.
|
||||||
|
let hash_qualified_script =
|
||||||
|
calc_fn_hash(qualifiers.iter().map(|&v| v), name, params.len(), empty());
|
||||||
|
// 2) Calculate a second hash with no qualifiers, empty function name,
|
||||||
|
// zero number of arguments, and the actual list of argument `TypeId`'.s
|
||||||
|
let hash_fn_args = calc_fn_hash(empty(), "", 0, params.iter().cloned());
|
||||||
|
// 3) The final hash is the XOR of the two hashes.
|
||||||
|
let hash_qualified_fn = hash_qualified_script ^ hash_fn_args;
|
||||||
|
|
||||||
|
functions.push((hash_qualified_fn, func.clone()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -551,11 +551,17 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
|
|||||||
|
|
||||||
// First search in functions lib (can override built-in)
|
// First search in functions lib (can override built-in)
|
||||||
// Cater for both normal function call style and method call style (one additional arguments)
|
// Cater for both normal function call style and method call style (one additional arguments)
|
||||||
if state.lib.iter_fn().find(|(_, _, _, f)| {
|
#[cfg(not(feature = "no_function"))]
|
||||||
|
let has_script_fn = state.lib.iter_fn().find(|(_, _, _, f)| {
|
||||||
if !f.is_script() { return false; }
|
if !f.is_script() { return false; }
|
||||||
let fn_def = f.get_fn_def();
|
let fn_def = f.get_fn_def();
|
||||||
&fn_def.name == name && (args.len()..=args.len() + 1).contains(&fn_def.params.len())
|
&fn_def.name == name && (args.len()..=args.len() + 1).contains(&fn_def.params.len())
|
||||||
}).is_some() {
|
}).is_some();
|
||||||
|
|
||||||
|
#[cfg(feature = "no_function")]
|
||||||
|
const has_script_fn: bool = false;
|
||||||
|
|
||||||
|
if has_script_fn {
|
||||||
// A script-defined function overrides the built-in function - do not make the call
|
// A script-defined function overrides the built-in function - do not make the call
|
||||||
x.3 = x.3.into_iter().map(|a| optimize_expr(a, state)).collect();
|
x.3 = x.3.into_iter().map(|a| optimize_expr(a, state)).collect();
|
||||||
return Expr::FnCall(x);
|
return Expr::FnCall(x);
|
||||||
|
Loading…
Reference in New Issue
Block a user