Avoid warnings.
This commit is contained in:
199
src/engine.rs
199
src/engine.rs
@@ -4,10 +4,10 @@ use crate::any::{map_std_type_name, Dynamic, Union, Variant};
|
||||
use crate::calc_fn_hash;
|
||||
use crate::fn_call::run_builtin_op_assignment;
|
||||
use crate::fn_native::{CallableFunction, Callback, FnPtr};
|
||||
use crate::module::{resolvers, Module, ModuleRef, ModuleResolver};
|
||||
use crate::module::{Module, ModuleRef};
|
||||
use crate::optimize::OptimizationLevel;
|
||||
use crate::packages::{Package, PackagesCollection, StandardPackage};
|
||||
use crate::parser::{Expr, FnAccess, ImmutableString, ReturnType, ScriptFnDef, Stmt};
|
||||
use crate::parser::{Expr, ImmutableString, ReturnType, Stmt};
|
||||
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
||||
use crate::result::EvalAltResult;
|
||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||
@@ -15,8 +15,13 @@ use crate::syntax::{CustomSyntax, EvalContext};
|
||||
use crate::token::Position;
|
||||
use crate::utils::StaticVec;
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
use crate::parser::{FnAccess, ScriptFnDef};
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
use crate::module::{resolvers, ModuleResolver};
|
||||
|
||||
use crate::stdlib::{
|
||||
any::TypeId,
|
||||
borrow::Cow,
|
||||
boxed::Box,
|
||||
collections::{HashMap, HashSet},
|
||||
@@ -26,6 +31,9 @@ use crate::stdlib::{
|
||||
vec::Vec,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::stdlib::any::TypeId;
|
||||
|
||||
/// Variable-sized array of `Dynamic` values.
|
||||
///
|
||||
/// Not available under the `no_index` feature.
|
||||
@@ -66,13 +74,6 @@ pub const MAX_EXPR_DEPTH: usize = 128;
|
||||
#[cfg(not(debug_assertions))]
|
||||
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 32;
|
||||
|
||||
#[cfg(feature = "unchecked")]
|
||||
pub const MAX_CALL_STACK_DEPTH: usize = usize::MAX;
|
||||
#[cfg(feature = "unchecked")]
|
||||
pub const MAX_EXPR_DEPTH: usize = 0;
|
||||
#[cfg(feature = "unchecked")]
|
||||
pub const MAX_FUNCTION_EXPR_DEPTH: usize = 0;
|
||||
|
||||
pub const KEYWORD_PRINT: &str = "print";
|
||||
pub const KEYWORD_DEBUG: &str = "debug";
|
||||
pub const KEYWORD_TYPE_OF: &str = "type_of";
|
||||
@@ -86,6 +87,7 @@ pub const FN_GET: &str = "get$";
|
||||
pub const FN_SET: &str = "set$";
|
||||
pub const FN_IDX_GET: &str = "index$get$";
|
||||
pub const FN_IDX_SET: &str = "index$set$";
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
pub const FN_ANONYMOUS: &str = "anon$";
|
||||
pub const MARKER_EXPR: &str = "$expr$";
|
||||
pub const MARKER_BLOCK: &str = "$block$";
|
||||
@@ -108,6 +110,7 @@ pub enum Target<'a> {
|
||||
Value(Dynamic),
|
||||
/// The target is a character inside a String.
|
||||
/// This is necessary because directly pointing to a char inside a String is impossible.
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
StringChar(&'a mut Dynamic, usize, Dynamic),
|
||||
}
|
||||
|
||||
@@ -116,7 +119,9 @@ impl Target<'_> {
|
||||
pub fn is_ref(&self) -> bool {
|
||||
match self {
|
||||
Self::Ref(_) => true,
|
||||
Self::Value(_) | Self::StringChar(_, _, _) => false,
|
||||
Self::Value(_) => false,
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::StringChar(_, _, _) => false,
|
||||
}
|
||||
}
|
||||
/// Is the `Target` an owned value?
|
||||
@@ -124,6 +129,7 @@ impl Target<'_> {
|
||||
match self {
|
||||
Self::Ref(_) => false,
|
||||
Self::Value(_) => true,
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::StringChar(_, _, _) => false,
|
||||
}
|
||||
}
|
||||
@@ -132,14 +138,16 @@ impl Target<'_> {
|
||||
match self {
|
||||
Target::Ref(r) => r.is::<T>(),
|
||||
Target::Value(r) => r.is::<T>(),
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Target::StringChar(_, _, _) => TypeId::of::<T>() == TypeId::of::<char>(),
|
||||
}
|
||||
}
|
||||
/// Get the value of the `Target` as a `Dynamic`, cloning a referenced value if necessary.
|
||||
pub fn clone_into_dynamic(self) -> Dynamic {
|
||||
match self {
|
||||
Self::Ref(r) => r.clone(), // Referenced value is cloned
|
||||
Self::Value(v) => v, // Owned value is simply taken
|
||||
Self::Ref(r) => r.clone(), // Referenced value is cloned
|
||||
Self::Value(v) => v, // Owned value is simply taken
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::StringChar(_, _, ch) => ch, // Character is taken
|
||||
}
|
||||
}
|
||||
@@ -148,6 +156,7 @@ impl Target<'_> {
|
||||
match self {
|
||||
Self::Ref(r) => *r,
|
||||
Self::Value(ref mut r) => r,
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::StringChar(_, _, ref mut r) => r,
|
||||
}
|
||||
}
|
||||
@@ -161,6 +170,7 @@ impl Target<'_> {
|
||||
Position::none(),
|
||||
)))
|
||||
}
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::StringChar(Dynamic(Union::Str(ref mut s)), index, _) => {
|
||||
// Replace the character at the specified index position
|
||||
let new_ch = new_val
|
||||
@@ -176,7 +186,8 @@ impl Target<'_> {
|
||||
*s = chars.iter().collect::<String>().into();
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::StringChar(_, _, _) => unreachable!(),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -249,6 +260,34 @@ pub fn get_script_function_by_signature<'a>(
|
||||
}
|
||||
}
|
||||
|
||||
/// [INTERNALS] A type containing all the limits imposed by the `Engine`.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// ## WARNING
|
||||
///
|
||||
/// This type is volatile and may change.
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
pub struct Limits {
|
||||
/// Maximum levels of call-stack to prevent infinite recursion.
|
||||
///
|
||||
/// Defaults to 16 for debug builds and 128 for non-debug builds.
|
||||
pub max_call_stack_depth: usize,
|
||||
/// Maximum depth of statements/expressions at global level.
|
||||
pub max_expr_depth: usize,
|
||||
/// Maximum depth of statements/expressions in functions.
|
||||
pub max_function_expr_depth: usize,
|
||||
/// Maximum number of operations allowed to run.
|
||||
pub max_operations: u64,
|
||||
/// Maximum number of modules allowed to load.
|
||||
pub max_modules: usize,
|
||||
/// Maximum length of a string.
|
||||
pub max_string_size: usize,
|
||||
/// Maximum length of an array.
|
||||
pub max_array_size: usize,
|
||||
/// Maximum number of properties in a map.
|
||||
pub max_map_size: usize,
|
||||
}
|
||||
|
||||
/// Rhai main scripting engine.
|
||||
///
|
||||
/// ```
|
||||
@@ -275,6 +314,7 @@ pub struct Engine {
|
||||
pub(crate) packages: PackagesCollection,
|
||||
|
||||
/// A module resolution service.
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
pub(crate) module_resolver: Option<Box<dyn ModuleResolver>>,
|
||||
|
||||
/// A hashmap mapping type names to pretty-print names.
|
||||
@@ -296,24 +336,10 @@ pub struct Engine {
|
||||
|
||||
/// Optimize the AST after compilation.
|
||||
pub(crate) optimization_level: OptimizationLevel,
|
||||
/// Maximum levels of call-stack to prevent infinite recursion.
|
||||
///
|
||||
/// Defaults to 16 for debug builds and 128 for non-debug builds.
|
||||
pub(crate) max_call_stack_depth: usize,
|
||||
/// Maximum depth of statements/expressions at global level.
|
||||
pub(crate) max_expr_depth: usize,
|
||||
/// Maximum depth of statements/expressions in functions.
|
||||
pub(crate) max_function_expr_depth: usize,
|
||||
/// Maximum number of operations allowed to run.
|
||||
pub(crate) max_operations: u64,
|
||||
/// Maximum number of modules allowed to load.
|
||||
pub(crate) max_modules: usize,
|
||||
/// Maximum length of a string.
|
||||
pub(crate) max_string_size: usize,
|
||||
/// Maximum length of an array.
|
||||
pub(crate) max_array_size: usize,
|
||||
/// Maximum number of properties in a map.
|
||||
pub(crate) max_map_size: usize,
|
||||
|
||||
/// Max limits.
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
pub(crate) limits: Limits,
|
||||
}
|
||||
|
||||
impl fmt::Debug for Engine {
|
||||
@@ -338,7 +364,8 @@ impl Default for Engine {
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
module_resolver: Some(Box::new(resolvers::FileModuleResolver::new())),
|
||||
#[cfg(any(feature = "no_module", feature = "no_std", target_arch = "wasm32",))]
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
#[cfg(any(feature = "no_std", target_arch = "wasm32",))]
|
||||
module_resolver: None,
|
||||
|
||||
type_names: None,
|
||||
@@ -360,14 +387,17 @@ impl Default for Engine {
|
||||
#[cfg(not(feature = "no_optimize"))]
|
||||
optimization_level: OptimizationLevel::Simple,
|
||||
|
||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||
max_expr_depth: MAX_EXPR_DEPTH,
|
||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
||||
max_operations: 0,
|
||||
max_modules: usize::MAX,
|
||||
max_string_size: 0,
|
||||
max_array_size: 0,
|
||||
max_map_size: 0,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
limits: Limits {
|
||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||
max_expr_depth: MAX_EXPR_DEPTH,
|
||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
||||
max_operations: 0,
|
||||
max_modules: usize::MAX,
|
||||
max_string_size: 0,
|
||||
max_array_size: 0,
|
||||
max_map_size: 0,
|
||||
},
|
||||
};
|
||||
|
||||
engine.load_package(StandardPackage::new().get());
|
||||
@@ -546,6 +576,8 @@ impl Engine {
|
||||
|
||||
packages: Default::default(),
|
||||
global_module: Default::default(),
|
||||
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
module_resolver: None,
|
||||
|
||||
type_names: None,
|
||||
@@ -563,14 +595,17 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_optimize"))]
|
||||
optimization_level: OptimizationLevel::Simple,
|
||||
|
||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||
max_expr_depth: MAX_EXPR_DEPTH,
|
||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
||||
max_operations: 0,
|
||||
max_modules: usize::MAX,
|
||||
max_string_size: 0,
|
||||
max_array_size: 0,
|
||||
max_map_size: 0,
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
limits: Limits {
|
||||
max_call_stack_depth: MAX_CALL_STACK_DEPTH,
|
||||
max_expr_depth: MAX_EXPR_DEPTH,
|
||||
max_function_expr_depth: MAX_FUNCTION_EXPR_DEPTH,
|
||||
max_operations: 0,
|
||||
max_modules: usize::MAX,
|
||||
max_string_size: 0,
|
||||
max_array_size: 0,
|
||||
max_map_size: 0,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -982,23 +1017,25 @@ impl Engine {
|
||||
fn get_indexed_mut<'a>(
|
||||
&self,
|
||||
state: &mut State,
|
||||
lib: &Module,
|
||||
_lib: &Module,
|
||||
target: &'a mut Target,
|
||||
mut idx: Dynamic,
|
||||
mut _idx: Dynamic,
|
||||
idx_pos: Position,
|
||||
create: bool,
|
||||
level: usize,
|
||||
_level: usize,
|
||||
) -> Result<Target<'a>, Box<EvalAltResult>> {
|
||||
self.inc_operations(state)?;
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
let is_ref = target.is_ref();
|
||||
|
||||
let val = target.as_mut();
|
||||
|
||||
match val {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Dynamic(Union::Array(arr)) => {
|
||||
// val_array[idx]
|
||||
let index = idx
|
||||
let index = _idx
|
||||
.as_int()
|
||||
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?;
|
||||
|
||||
@@ -1021,13 +1058,13 @@ impl Engine {
|
||||
Dynamic(Union::Map(map)) => {
|
||||
// val_map[idx]
|
||||
Ok(if create {
|
||||
let index = idx
|
||||
let index = _idx
|
||||
.take_immutable_string()
|
||||
.map_err(|_| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
|
||||
|
||||
map.entry(index).or_insert(Default::default()).into()
|
||||
} else {
|
||||
let index = idx
|
||||
let index = _idx
|
||||
.downcast_ref::<ImmutableString>()
|
||||
.ok_or_else(|| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
|
||||
|
||||
@@ -1041,7 +1078,7 @@ impl Engine {
|
||||
Dynamic(Union::Str(s)) => {
|
||||
// val_string[idx]
|
||||
let chars_len = s.chars().count();
|
||||
let index = idx
|
||||
let index = _idx
|
||||
.as_int()
|
||||
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?;
|
||||
|
||||
@@ -1062,9 +1099,9 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
_ => {
|
||||
let type_name = val.type_name();
|
||||
let args = &mut [val, &mut idx];
|
||||
let args = &mut [val, &mut _idx];
|
||||
self.exec_fn_call(
|
||||
state, lib, FN_IDX_GET, true, 0, args, is_ref, true, None, level,
|
||||
state, _lib, FN_IDX_GET, true, 0, args, is_ref, true, None, _level,
|
||||
)
|
||||
.map(|(v, _)| v.into())
|
||||
.map_err(|err| match *err {
|
||||
@@ -1639,19 +1676,20 @@ impl Engine {
|
||||
Stmt::Const(_) => unreachable!(),
|
||||
|
||||
// Import statement
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
Stmt::Import(x) => {
|
||||
let (expr, (name, pos)) = x.as_ref();
|
||||
let (expr, (name, _pos)) = x.as_ref();
|
||||
|
||||
// Guard against too many modules
|
||||
if state.modules >= self.max_modules {
|
||||
return Err(Box::new(EvalAltResult::ErrorTooManyModules(*pos)));
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
if state.modules >= self.limits.max_modules {
|
||||
return Err(Box::new(EvalAltResult::ErrorTooManyModules(*_pos)));
|
||||
}
|
||||
|
||||
if let Some(path) = self
|
||||
.eval_expr(scope, mods, state, lib, this_ptr, &expr, level)?
|
||||
.try_cast::<ImmutableString>()
|
||||
{
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
if let Some(resolver) = &self.module_resolver {
|
||||
let mut module = resolver.resolve(self, &path, expr.position())?;
|
||||
module.index_all_sub_modules();
|
||||
@@ -1666,15 +1704,13 @@ impl Engine {
|
||||
expr.position(),
|
||||
)))
|
||||
}
|
||||
|
||||
#[cfg(feature = "no_module")]
|
||||
Ok(Default::default())
|
||||
} else {
|
||||
Err(Box::new(EvalAltResult::ErrorImportExpr(expr.position())))
|
||||
}
|
||||
}
|
||||
|
||||
// Export statement
|
||||
#[cfg(not(feature = "no_module"))]
|
||||
Stmt::Export(list) => {
|
||||
for ((id, id_pos), rename) in list.iter() {
|
||||
// Mark scope variables as public
|
||||
@@ -1696,8 +1732,18 @@ impl Engine {
|
||||
.map_err(|err| err.new_position(stmt.position()))
|
||||
}
|
||||
|
||||
#[cfg(feature = "unchecked")]
|
||||
#[inline(always)]
|
||||
fn check_data_size(
|
||||
&self,
|
||||
result: Result<Dynamic, Box<EvalAltResult>>,
|
||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
return result;
|
||||
}
|
||||
|
||||
/// Check a result to ensure that the data size is within allowable limit.
|
||||
/// Position in `EvalAltResult` may be None and should be set afterwards.
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
fn check_data_size(
|
||||
&self,
|
||||
result: Result<Dynamic, Box<EvalAltResult>>,
|
||||
@@ -1706,7 +1752,8 @@ impl Engine {
|
||||
return result;
|
||||
|
||||
// If no data size limits, just return
|
||||
if self.max_string_size + self.max_array_size + self.max_map_size == 0 {
|
||||
if self.limits.max_string_size + self.limits.max_array_size + self.limits.max_map_size == 0
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -1766,37 +1813,37 @@ impl Engine {
|
||||
// Simply return all errors
|
||||
Err(_) => return result,
|
||||
// String with limit
|
||||
Ok(Dynamic(Union::Str(_))) if self.max_string_size > 0 => (),
|
||||
Ok(Dynamic(Union::Str(_))) if self.limits.max_string_size > 0 => (),
|
||||
// Array with limit
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Ok(Dynamic(Union::Array(_))) if self.max_array_size > 0 => (),
|
||||
Ok(Dynamic(Union::Array(_))) if self.limits.max_array_size > 0 => (),
|
||||
// Map with limit
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Ok(Dynamic(Union::Map(_))) if self.max_map_size > 0 => (),
|
||||
Ok(Dynamic(Union::Map(_))) if self.limits.max_map_size > 0 => (),
|
||||
// Everything else is simply returned
|
||||
Ok(_) => return result,
|
||||
};
|
||||
|
||||
let (arr, map, s) = calc_size(result.as_ref().unwrap());
|
||||
|
||||
if s > self.max_string_size {
|
||||
if s > self.limits.max_string_size {
|
||||
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
||||
"Length of string".to_string(),
|
||||
self.max_string_size,
|
||||
self.limits.max_string_size,
|
||||
s,
|
||||
Position::none(),
|
||||
)))
|
||||
} else if arr > self.max_array_size {
|
||||
} else if arr > self.limits.max_array_size {
|
||||
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
||||
"Size of array".to_string(),
|
||||
self.max_array_size,
|
||||
self.limits.max_array_size,
|
||||
arr,
|
||||
Position::none(),
|
||||
)))
|
||||
} else if map > self.max_map_size {
|
||||
} else if map > self.limits.max_map_size {
|
||||
Err(Box::new(EvalAltResult::ErrorDataTooLarge(
|
||||
"Number of properties in object map".to_string(),
|
||||
self.max_map_size,
|
||||
self.limits.max_map_size,
|
||||
map,
|
||||
Position::none(),
|
||||
)))
|
||||
@@ -1812,7 +1859,7 @@ impl Engine {
|
||||
|
||||
#[cfg(not(feature = "unchecked"))]
|
||||
// Guard against too many operations
|
||||
if self.max_operations > 0 && state.operations > self.max_operations {
|
||||
if self.limits.max_operations > 0 && state.operations > self.limits.max_operations {
|
||||
return Err(Box::new(EvalAltResult::ErrorTooManyOperations(
|
||||
Position::none(),
|
||||
)));
|
||||
|
Reference in New Issue
Block a user