Shut up clippy.

This commit is contained in:
Stephen Chung 2022-08-27 16:26:41 +08:00
parent d80184ba14
commit bf5d6ab35a
28 changed files with 313 additions and 205 deletions

View File

@ -134,10 +134,7 @@ impl Expression<'_> {
Expr::CharConstant(x, ..) => reify!(*x => Option<T>), Expr::CharConstant(x, ..) => reify!(*x => Option<T>),
Expr::StringConstant(x, ..) => reify!(x.clone() => Option<T>), Expr::StringConstant(x, ..) => reify!(x.clone() => Option<T>),
Expr::Variable(x, ..) => { Expr::Variable(x, ..) => reify!(x.3.clone() => Option<T>),
let x: ImmutableString = x.3.clone().into();
reify!(x => Option<T>)
}
Expr::BoolConstant(x, ..) => reify!(*x => Option<T>), Expr::BoolConstant(x, ..) => reify!(*x => Option<T>),
Expr::Unit(..) => reify!(() => Option<T>), Expr::Unit(..) => reify!(() => Option<T>),

View File

@ -3,9 +3,8 @@
#![cfg(feature = "metadata")] #![cfg(feature = "metadata")]
use crate::module::FuncInfo; use crate::module::FuncInfo;
use crate::plugin::*;
use crate::tokenizer::{is_valid_function_name, Token}; use crate::tokenizer::{is_valid_function_name, Token};
use crate::{Engine, Module, Scope, INT}; use crate::{Engine, FnAccess, Module, Scope, INT};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -117,19 +116,20 @@ impl Definitions<'_> {
} }
/// Get the [`Engine`]. /// Get the [`Engine`].
#[inline(always)] #[inline(always)]
pub fn engine(&self) -> &Engine { #[must_use]
pub const fn engine(&self) -> &Engine {
self.engine self.engine
} }
/// Get the [`Scope`]. /// Get the [`Scope`].
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn scope(&self) -> Option<&Scope> { pub const fn scope(&self) -> Option<&Scope> {
self.scope self.scope
} }
/// Get the configuration. /// Get the configuration.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn config(&self) -> &DefinitionsConfig { pub(crate) const fn config(&self) -> &DefinitionsConfig {
&self.config &self.config
} }
} }

View File

@ -348,7 +348,7 @@ impl Engine {
#[inline(always)] #[inline(always)]
pub fn register_debugger( pub fn register_debugger(
&mut self, &mut self,
init: impl Fn(&Engine) -> Dynamic + SendSync + 'static, init: impl Fn(&Self) -> Dynamic + SendSync + 'static,
callback: impl Fn( callback: impl Fn(
EvalContext, EvalContext,
crate::eval::DebuggerEvent, crate::eval::DebuggerEvent,

View File

@ -102,11 +102,8 @@ fn map_std_type_name(name: &str, shorthands: bool) -> &str {
}; };
} }
if let Some(stripped) = name.strip_prefix("rhai::") { name.strip_prefix("rhai::")
map_std_type_name(stripped, shorthands) .map_or(name, |s| map_std_type_name(s, shorthands))
} else {
name
}
} }
impl Engine { impl Engine {

View File

@ -167,7 +167,7 @@ impl AST {
/// Get a reference to the source. /// Get a reference to the source.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn source_raw(&self) -> &Identifier { pub(crate) const fn source_raw(&self) -> &Identifier {
&self.source &self.source
} }
/// Set the source. /// Set the source.
@ -261,7 +261,7 @@ impl AST {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn shared_lib(&self) -> &crate::Shared<crate::Module> { pub(crate) const fn shared_lib(&self) -> &crate::Shared<crate::Module> {
&self.lib &self.lib
} }
/// _(internals)_ Get the internal shared [`Module`][crate::Module] containing all script-defined functions. /// _(internals)_ Get the internal shared [`Module`][crate::Module] containing all script-defined functions.
@ -272,7 +272,7 @@ impl AST {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn shared_lib(&self) -> &crate::Shared<crate::Module> { pub const fn shared_lib(&self) -> &crate::Shared<crate::Module> {
&self.lib &self.lib
} }
/// Get the embedded [module resolver][crate::ModuleResolver]. /// Get the embedded [module resolver][crate::ModuleResolver].
@ -280,7 +280,7 @@ impl AST {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub(crate) fn resolver( pub(crate) const fn resolver(
&self, &self,
) -> Option<&crate::Shared<crate::module::resolvers::StaticModuleResolver>> { ) -> Option<&crate::Shared<crate::module::resolvers::StaticModuleResolver>> {
self.resolver.as_ref() self.resolver.as_ref()
@ -293,7 +293,7 @@ impl AST {
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn resolver( pub const fn resolver(
&self, &self,
) -> Option<&crate::Shared<crate::module::resolvers::StaticModuleResolver>> { ) -> Option<&crate::Shared<crate::module::resolvers::StaticModuleResolver>> {
self.resolver.as_ref() self.resolver.as_ref()
@ -910,7 +910,7 @@ impl<A: AsRef<AST>> Add<A> for &AST {
} }
} }
impl<A: Into<AST>> AddAssign<A> for AST { impl<A: Into<Self>> AddAssign<A> for AST {
#[inline(always)] #[inline(always)]
fn add_assign(&mut self, rhs: A) { fn add_assign(&mut self, rhs: A) {
self.combine(rhs.into()); self.combine(rhs.into());

View File

@ -338,17 +338,7 @@ impl<F: Float> FloatWrapper<F> {
/// Create a new [`FloatWrapper`]. /// Create a new [`FloatWrapper`].
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn new(value: F) -> Self { pub const fn new(value: F) -> Self {
Self(value)
}
}
#[cfg(not(feature = "no_float"))]
impl FloatWrapper<crate::FLOAT> {
/// Create a new [`FloatWrapper`].
#[inline(always)]
#[must_use]
pub const fn new_const(value: crate::FLOAT) -> Self {
Self(value) Self(value)
} }
} }
@ -600,7 +590,7 @@ impl Expr {
Self::FnCall(ref x, ..) Self::FnCall(ref x, ..)
if !x.is_qualified() && x.args.len() == 1 && x.name == KEYWORD_FN_PTR => if !x.is_qualified() && x.args.len() == 1 && x.name == KEYWORD_FN_PTR =>
{ {
if let Expr::StringConstant(ref s, ..) = x.args[0] { if let Self::StringConstant(ref s, ..) = x.args[0] {
FnPtr::new(s).ok()?.into() FnPtr::new(s).ok()?.into()
} else { } else {
return None; return None;
@ -612,8 +602,8 @@ impl Expr {
match x.name.as_str() { match x.name.as_str() {
// x..y // x..y
OP_EXCLUSIVE_RANGE => { OP_EXCLUSIVE_RANGE => {
if let Expr::IntegerConstant(ref start, ..) = x.args[0] { if let Self::IntegerConstant(ref start, ..) = x.args[0] {
if let Expr::IntegerConstant(ref end, ..) = x.args[1] { if let Self::IntegerConstant(ref end, ..) = x.args[1] {
(*start..*end).into() (*start..*end).into()
} else { } else {
return None; return None;
@ -624,8 +614,8 @@ impl Expr {
} }
// x..=y // x..=y
OP_INCLUSIVE_RANGE => { OP_INCLUSIVE_RANGE => {
if let Expr::IntegerConstant(ref start, ..) = x.args[0] { if let Self::IntegerConstant(ref start, ..) = x.args[0] {
if let Expr::IntegerConstant(ref end, ..) = x.args[1] { if let Self::IntegerConstant(ref end, ..) = x.args[1] {
(*start..=*end).into() (*start..=*end).into()
} else { } else {
return None; return None;
@ -940,9 +930,9 @@ impl Expr {
} }
Self::Index(x, ..) Self::Index(x, ..)
| Self::Dot(x, ..) | Self::Dot(x, ..)
| Expr::And(x, ..) | Self::And(x, ..)
| Expr::Or(x, ..) | Self::Or(x, ..)
| Expr::Coalesce(x, ..) => { | Self::Coalesce(x, ..) => {
if !x.lhs.walk(path, on_node) { if !x.lhs.walk(path, on_node) {
return false; return false;
} }

View File

@ -20,7 +20,7 @@ impl FnAccess {
/// Is this function private? /// Is this function private?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_private(self) -> bool { pub const fn is_private(self) -> bool {
match self { match self {
Self::Private => true, Self::Private => true,
Self::Public => false, Self::Public => false,
@ -29,7 +29,7 @@ impl FnAccess {
/// Is this function public? /// Is this function public?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_public(self) -> bool { pub const fn is_public(self) -> bool {
match self { match self {
Self::Private => false, Self::Private => false,
Self::Public => true, Self::Public => true,

View File

@ -60,7 +60,7 @@ impl OpAssignment {
#[must_use] #[must_use]
#[inline(always)] #[inline(always)]
pub fn new_op_assignment(name: &str, pos: Position) -> Self { pub fn new_op_assignment(name: &str, pos: Position) -> Self {
Self::new_op_assignment_from_token(Token::lookup_from_syntax(name).expect("operator"), pos) Self::new_op_assignment_from_token(&Token::lookup_from_syntax(name).expect("operator"), pos)
} }
/// Create a new [`OpAssignment`] from a [`Token`]. /// Create a new [`OpAssignment`] from a [`Token`].
/// ///
@ -68,7 +68,7 @@ impl OpAssignment {
/// ///
/// Panics if the token is not an op-assignment operator. /// Panics if the token is not an op-assignment operator.
#[must_use] #[must_use]
pub fn new_op_assignment_from_token(op: Token, pos: Position) -> Self { pub fn new_op_assignment_from_token(op: &Token, pos: Position) -> Self {
let op_raw = op let op_raw = op
.get_base_op_from_assignment() .get_base_op_from_assignment()
.expect("op-assignment operator") .expect("op-assignment operator")
@ -90,7 +90,7 @@ impl OpAssignment {
#[inline(always)] #[inline(always)]
pub fn new_op_assignment_from_base(name: &str, pos: Position) -> Self { pub fn new_op_assignment_from_base(name: &str, pos: Position) -> Self {
Self::new_op_assignment_from_base_token( Self::new_op_assignment_from_base_token(
Token::lookup_from_syntax(name).expect("operator"), &Token::lookup_from_syntax(name).expect("operator"),
pos, pos,
) )
} }
@ -101,8 +101,8 @@ impl OpAssignment {
/// Panics if the token is cannot be converted into an op-assignment operator. /// Panics if the token is cannot be converted into an op-assignment operator.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn new_op_assignment_from_base_token(op: Token, pos: Position) -> Self { pub fn new_op_assignment_from_base_token(op: &Token, pos: Position) -> Self {
Self::new_op_assignment_from_token(op.convert_to_op_assignment().expect("operator"), pos) Self::new_op_assignment_from_token(&op.convert_to_op_assignment().expect("operator"), pos)
} }
} }
@ -157,13 +157,13 @@ impl ConditionalExpr {
/// Is the condition always `true`? /// Is the condition always `true`?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_always_true(&self) -> bool { pub const fn is_always_true(&self) -> bool {
matches!(self.condition, Expr::BoolConstant(true, ..)) matches!(self.condition, Expr::BoolConstant(true, ..))
} }
/// Is the condition always `false`? /// Is the condition always `false`?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_always_false(&self) -> bool { pub const fn is_always_false(&self) -> bool {
matches!(self.condition, Expr::BoolConstant(false, ..)) matches!(self.condition, Expr::BoolConstant(false, ..))
} }
} }
@ -228,12 +228,12 @@ impl RangeCase {
/// Size of the range. /// Size of the range.
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn len(&self) -> usize { pub fn len(&self) -> INT {
match self { match self {
Self::ExclusiveInt(r, ..) if r.is_empty() => 0, Self::ExclusiveInt(r, ..) if r.is_empty() => 0,
Self::ExclusiveInt(r, ..) => (r.end - r.start) as usize, Self::ExclusiveInt(r, ..) => r.end - r.start,
Self::InclusiveInt(r, ..) if r.is_empty() => 0, Self::InclusiveInt(r, ..) if r.is_empty() => 0,
Self::InclusiveInt(r, ..) => (*r.end() - *r.start()) as usize, Self::InclusiveInt(r, ..) => *r.end() - *r.start() + 1,
} }
} }
/// Is the specified number within this range? /// Is the specified number within this range?
@ -248,7 +248,7 @@ impl RangeCase {
/// Is the specified range inclusive? /// Is the specified range inclusive?
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn is_inclusive(&self) -> bool { pub const fn is_inclusive(&self) -> bool {
match self { match self {
Self::ExclusiveInt(..) => false, Self::ExclusiveInt(..) => false,
Self::InclusiveInt(..) => true, Self::InclusiveInt(..) => true,
@ -257,7 +257,7 @@ impl RangeCase {
/// Get the index to the [`ConditionalExpr`]. /// Get the index to the [`ConditionalExpr`].
#[inline(always)] #[inline(always)]
#[must_use] #[must_use]
pub fn index(&self) -> usize { pub const fn index(&self) -> usize {
match self { match self {
Self::ExclusiveInt(.., n) | Self::InclusiveInt(.., n) => *n, Self::ExclusiveInt(.., n) | Self::InclusiveInt(.., n) => *n,
} }
@ -611,14 +611,14 @@ impl From<StmtBlock> for Stmt {
} }
} }
impl<T: IntoIterator<Item = Stmt>> From<(T, Position, Position)> for Stmt { impl<T: IntoIterator<Item = Self>> From<(T, Position, Position)> for Stmt {
#[inline(always)] #[inline(always)]
fn from(value: (T, Position, Position)) -> Self { fn from(value: (T, Position, Position)) -> Self {
StmtBlock::new(value.0, value.1, value.2).into() StmtBlock::new(value.0, value.1, value.2).into()
} }
} }
impl<T: IntoIterator<Item = Stmt>> From<(T, Span)> for Stmt { impl<T: IntoIterator<Item = Self>> From<(T, Span)> for Stmt {
#[inline(always)] #[inline(always)]
fn from(value: (T, Span)) -> Self { fn from(value: (T, Span)) -> Self {
StmtBlock::new_with_span(value.0, value.1).into() StmtBlock::new_with_span(value.0, value.1).into()
@ -765,7 +765,7 @@ impl Stmt {
Self::Noop(..) => true, Self::Noop(..) => true,
Self::Expr(expr) => expr.is_pure(), Self::Expr(expr) => expr.is_pure(),
Self::If(x, ..) => { Self::If(x, ..) => {
x.0.is_pure() && x.1.iter().all(Stmt::is_pure) && x.2.iter().all(Stmt::is_pure) x.0.is_pure() && x.1.iter().all(Self::is_pure) && x.2.iter().all(Self::is_pure)
} }
Self::Switch(x, ..) => { Self::Switch(x, ..) => {
let (expr, sw) = &**x; let (expr, sw) = &**x;
@ -786,7 +786,7 @@ impl Stmt {
Self::While(x, ..) if matches!(x.0, Expr::BoolConstant(false, ..)) => true, Self::While(x, ..) if matches!(x.0, Expr::BoolConstant(false, ..)) => true,
Self::Do(x, options, ..) if matches!(x.0, Expr::BoolConstant(..)) => match x.0 { Self::Do(x, options, ..) if matches!(x.0, Expr::BoolConstant(..)) => match x.0 {
Expr::BoolConstant(cond, ..) if cond == options.contains(ASTFlags::NEGATED) => { Expr::BoolConstant(cond, ..) if cond == options.contains(ASTFlags::NEGATED) => {
x.1.iter().all(Stmt::is_pure) x.1.iter().all(Self::is_pure)
} }
_ => false, _ => false,
}, },
@ -796,13 +796,13 @@ impl Stmt {
// For loops can be pure because if the iterable is pure, it is finite, // For loops can be pure because if the iterable is pure, it is finite,
// so infinite loops can never occur. // so infinite loops can never occur.
Self::For(x, ..) => x.2.is_pure() && x.3.iter().all(Stmt::is_pure), Self::For(x, ..) => x.2.is_pure() && x.3.iter().all(Self::is_pure),
Self::Var(..) | Self::Assignment(..) | Self::FnCall(..) => false, Self::Var(..) | Self::Assignment(..) | Self::FnCall(..) => false,
Self::Block(block, ..) => block.iter().all(Stmt::is_pure), Self::Block(block, ..) => block.iter().all(Self::is_pure),
Self::BreakLoop(..) | Self::Return(..) => false, Self::BreakLoop(..) | Self::Return(..) => false,
Self::TryCatch(x, ..) => { Self::TryCatch(x, ..) => {
x.try_block.iter().all(Stmt::is_pure) && x.catch_block.iter().all(Stmt::is_pure) x.try_block.iter().all(Self::is_pure) && x.catch_block.iter().all(Self::is_pure)
} }
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
@ -828,7 +828,7 @@ impl Stmt {
Self::Var(..) => true, Self::Var(..) => true,
Self::Expr(e) => match &**e { Self::Expr(e) => match &**e {
Expr::Stmt(s) => s.iter().all(Stmt::is_block_dependent), Expr::Stmt(s) => s.iter().all(Self::is_block_dependent),
Expr::FnCall(x, ..) => !x.is_qualified() && x.name == KEYWORD_EVAL, Expr::FnCall(x, ..) => !x.is_qualified() && x.name == KEYWORD_EVAL,
_ => false, _ => false,
}, },
@ -854,7 +854,7 @@ impl Stmt {
Self::Var(x, ..) => x.1.is_pure(), Self::Var(x, ..) => x.1.is_pure(),
Self::Expr(e) => match &**e { Self::Expr(e) => match &**e {
Expr::Stmt(s) => s.iter().all(Stmt::is_internally_pure), Expr::Stmt(s) => s.iter().all(Self::is_internally_pure),
_ => self.is_pure(), _ => self.is_pure(),
}, },

View File

@ -237,13 +237,16 @@ impl Engine {
{ {
engine.print = Box::new(|s| println!("{}", s)); engine.print = Box::new(|s| println!("{}", s));
engine.debug = Box::new(|s, source, pos| { engine.debug = Box::new(|s, source, pos| {
if let Some(source) = source { source.map_or_else(
println!("{} @ {:?} | {}", source, pos, s); || {
} else if pos.is_none() { if pos.is_none() {
println!("{}", s); println!("{}", s);
} else { } else {
println!("{:?} | {}", pos, s); println!("{:?} | {}", pos, s);
} }
},
|source| println!("{} @ {:?} | {}", source, pos, s),
)
}); });
} }
@ -316,7 +319,7 @@ impl Engine {
&self, &self,
string: impl AsRef<str> + Into<ImmutableString>, string: impl AsRef<str> + Into<ImmutableString>,
) -> ImmutableString { ) -> ImmutableString {
locked_write(&self.interned_strings).get(string).into() locked_write(&self.interned_strings).get(string)
} }
/// _(internals)_ Get an interned [string][ImmutableString]. /// _(internals)_ Get an interned [string][ImmutableString].
@ -331,7 +334,7 @@ impl Engine {
&self, &self,
string: impl AsRef<str> + Into<ImmutableString>, string: impl AsRef<str> + Into<ImmutableString>,
) -> ImmutableString { ) -> ImmutableString {
locked_write(&self.interned_strings).get(string).into() locked_write(&self.interned_strings).get(string)
} }
/// Get an empty [`ImmutableString`] which refers to a shared instance. /// Get an empty [`ImmutableString`] which refers to a shared instance.

View File

@ -152,14 +152,14 @@ impl Engine {
if let Ok(val) = if let Ok(val) =
self.call_indexer_get(global, caches, lib, target, idx, level) self.call_indexer_get(global, caches, lib, target, idx, level)
{ {
let mut res = val.into(); let mut val = val.into();
// Run the op-assignment // Run the op-assignment
self.eval_op_assignment( self.eval_op_assignment(
global, caches, lib, op_info, &mut res, root, new_val, global, caches, lib, op_info, &mut val, root, new_val,
level, level,
)?; )?;
// Replace new value // Replace new value
new_val = res.take_or_clone(); new_val = val.take_or_clone();
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
self.check_data_size(&new_val, op_info.pos)?; self.check_data_size(&new_val, op_info.pos)?;
} }
@ -864,13 +864,16 @@ impl Engine {
map.insert(index.clone().into(), Dynamic::UNIT); map.insert(index.clone().into(), Dynamic::UNIT);
} }
if let Some(value) = map.get_mut(index.as_str()) { map.get_mut(index.as_str()).map_or_else(
Ok(Target::from(value)) || {
} else if self.fail_on_invalid_map_property() { if self.fail_on_invalid_map_property() {
Err(ERR::ErrorPropertyNotFound(index.to_string(), idx_pos).into()) Err(ERR::ErrorPropertyNotFound(index.to_string(), idx_pos).into())
} else { } else {
Ok(Target::from(Dynamic::UNIT)) Ok(Target::from(Dynamic::UNIT))
} }
},
|value| Ok(Target::from(value)),
)
} }
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
@ -970,21 +973,33 @@ impl Engine {
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, idx_pos))?; .map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, idx_pos))?;
let (ch, offset) = if index >= 0 { let (ch, offset) = if index >= 0 {
if index >= crate::MAX_USIZE_INT {
return Err(
ERR::ErrorStringBounds(s.chars().count(), index, idx_pos).into()
);
}
let offset = index as usize; let offset = index as usize;
( (
s.chars().nth(offset).ok_or_else(|| { s.chars().nth(offset).ok_or_else(|| {
let chars_len = s.chars().count(); ERR::ErrorStringBounds(s.chars().count(), index, idx_pos)
ERR::ErrorStringBounds(chars_len, index, idx_pos)
})?, })?,
offset, offset,
) )
} else { } else {
let offset = index.unsigned_abs() as usize; let abs_index = index.unsigned_abs();
if abs_index as u64 >= usize::MAX as u64 {
return Err(
ERR::ErrorStringBounds(s.chars().count(), index, idx_pos).into()
);
}
let offset = abs_index as usize;
( (
// Count from end if negative // Count from end if negative
s.chars().rev().nth(offset - 1).ok_or_else(|| { s.chars().rev().nth(offset - 1).ok_or_else(|| {
let chars_len = s.chars().count(); ERR::ErrorStringBounds(s.chars().count(), index, idx_pos)
ERR::ErrorStringBounds(chars_len, index, idx_pos)
})?, })?,
offset, offset,
) )

View File

@ -72,7 +72,7 @@ impl Engine {
/// Is there a data size limit set? /// Is there a data size limit set?
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
pub(crate) fn has_data_size_limit(&self) -> bool { pub(crate) const fn has_data_size_limit(&self) -> bool {
let mut _limited = self.limits.max_string_size.is_some(); let mut _limited = self.limits.max_string_size.is_some();
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]

View File

@ -74,11 +74,8 @@ impl Engine {
(_, namespace, hash_var, var_name) => { (_, namespace, hash_var, var_name) => {
// foo:bar::baz::VARIABLE // foo:bar::baz::VARIABLE
if let Some(module) = self.search_imports(global, namespace) { if let Some(module) = self.search_imports(global, namespace) {
return if let Some(mut target) = module.get_qualified_var(*hash_var) { return module.get_qualified_var(*hash_var).map_or_else(
// Module variables are constant || {
target.set_access_mode(AccessMode::ReadOnly);
Ok((target.into(), *_var_pos))
} else {
let sep = crate::tokenizer::Token::DoubleColon.literal_syntax(); let sep = crate::tokenizer::Token::DoubleColon.literal_syntax();
Err(ERR::ErrorVariableNotFound( Err(ERR::ErrorVariableNotFound(
@ -86,7 +83,13 @@ impl Engine {
namespace.position(), namespace.position(),
) )
.into()) .into())
}; },
|mut target| {
// Module variables are constant
target.set_access_mode(AccessMode::ReadOnly);
Ok((target.into(), *_var_pos))
},
);
} }
// global::VARIABLE // global::VARIABLE
@ -363,7 +366,7 @@ impl Engine {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Expr::Array(x, ..) => { Expr::Array(x, ..) => {
let mut arr = crate::Array::with_capacity(x.len()); let mut array = crate::Array::with_capacity(x.len());
let mut result = Ok(Dynamic::UNIT); let mut result = Ok(Dynamic::UNIT);
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
@ -383,7 +386,7 @@ impl Engine {
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
let val_sizes = Self::calc_data_sizes(&value, true); let val_sizes = Self::calc_data_sizes(&value, true);
arr.push(value); array.push(value);
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if self.has_data_size_limit() { if self.has_data_size_limit() {
@ -396,7 +399,7 @@ impl Engine {
} }
} }
result.map(|_| arr.into()) result.map(|_| array.into())
} }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]

View File

@ -631,8 +631,12 @@ impl Engine {
for (x, iter_value) in func(iter_obj).enumerate() { for (x, iter_value) in func(iter_obj).enumerate() {
// Increment counter // Increment counter
if counter_index < usize::MAX { if counter_index < usize::MAX {
// As the variable increments from 0, this should always work
// since any overflow will first be caught below.
let index_value = x as INT;
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if x > INT::MAX as usize { if index_value > crate::MAX_USIZE_INT {
loop_result = Err(ERR::ErrorArithmetic( loop_result = Err(ERR::ErrorArithmetic(
format!("for-loop counter overflow: {x}"), format!("for-loop counter overflow: {x}"),
counter.pos, counter.pos,
@ -641,10 +645,8 @@ impl Engine {
break; break;
} }
let index_value = Dynamic::from(x as INT);
*scope.get_mut_by_index(counter_index).write_lock().unwrap() = *scope.get_mut_by_index(counter_index).write_lock().unwrap() =
index_value; Dynamic::from_int(index_value);
} }
let value = match iter_value { let value = match iter_value {

View File

@ -16,7 +16,7 @@ use std::prelude::v1::*;
pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (usize, usize) { pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (usize, usize) {
let start = if start < 0 { let start = if start < 0 {
length - usize::min(start.unsigned_abs() as usize, length) length - usize::min(start.unsigned_abs() as usize, length)
} else if start as usize >= length { } else if start > crate::MAX_USIZE_INT || start as usize >= length {
return (length, 0); return (length, 0);
} else { } else {
start as usize start as usize
@ -24,7 +24,7 @@ pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (us
let len = if len <= 0 { let len = if len <= 0 {
0 0
} else if len as usize > length - start { } else if len > crate::MAX_USIZE_INT || len as usize > length - start {
length - start length - start
} else { } else {
len as usize len as usize
@ -59,7 +59,7 @@ pub fn calc_index<E>(
} else { } else {
err() err()
} }
} else if start as usize >= length { } else if start > crate::MAX_USIZE_INT || start as usize >= length {
err() err()
} else { } else {
Ok(start as usize) Ok(start as usize)

View File

@ -700,7 +700,7 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
}), }),
_ => None, _ => None,
}; };
} else { }
return match op { return match op {
"+=" => Some(|_, args| { "+=" => Some(|_, args| {
let x = std::mem::take(args[1]); let x = std::mem::take(args[1]);
@ -710,7 +710,6 @@ pub fn get_builtin_op_assignment_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Optio
_ => None, _ => None,
}; };
} }
}
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
{ {

View File

@ -68,7 +68,7 @@ impl<'a> ArgBackup<'a> {
// Replace the first reference with a reference to the clone, force-casting the lifetime. // Replace the first reference with a reference to the clone, force-casting the lifetime.
// Must remember to restore it later with `restore_first_arg`. // Must remember to restore it later with `restore_first_arg`.
// //
// # Safety // SAFETY:
// //
// Blindly casting a reference to another lifetime saves allocation and string cloning, // Blindly casting a reference to another lifetime saves allocation and string cloning,
// but must be used with the utmost care. // but must be used with the utmost care.
@ -608,7 +608,7 @@ impl Engine {
let num_params = args[1].as_int().expect("`INT`"); let num_params = args[1].as_int().expect("`INT`");
return Ok(( return Ok((
if num_params < 0 { if num_params < 0 || num_params > crate::MAX_USIZE_INT {
false false
} else { } else {
let hash_script = calc_fn_hash(fn_name.as_str(), num_params as usize); let hash_script = calc_fn_hash(fn_name.as_str(), num_params as usize);
@ -1100,7 +1100,7 @@ impl Engine {
.as_int() .as_int()
.map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, arg_pos))?; .map_err(|typ| self.make_type_mismatch_err::<crate::INT>(typ, arg_pos))?;
return Ok(if num_params < 0 { return Ok(if num_params < 0 || num_params > crate::MAX_USIZE_INT {
false false
} else { } else {
let hash_script = calc_fn_hash(&fn_name, num_params as usize); let hash_script = calc_fn_hash(&fn_name, num_params as usize);

View File

@ -47,9 +47,7 @@ pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
// If T is `&str`, data must be `ImmutableString`, so map directly to it // If T is `&str`, data must be `ImmutableString`, so map directly to it
data.flatten_in_place(); data.flatten_in_place();
let ref_str = data.as_str_ref().expect("&str"); let ref_str = data.as_str_ref().expect("&str");
// # Safety // SAFETY: We already checked that `T` is `&str`, so it is safe to cast here.
//
// We already checked that `T` is `&str`, so it is safe to cast here.
return unsafe { mem::transmute_copy::<_, T>(&ref_str) }; return unsafe { mem::transmute_copy::<_, T>(&ref_str) };
} }
if TypeId::of::<T>() == TypeId::of::<String>() { if TypeId::of::<T>() == TypeId::of::<String>() {

View File

@ -58,7 +58,18 @@
#![cfg_attr(feature = "no_std", no_std)] #![cfg_attr(feature = "no_std", no_std)]
#![deny(missing_docs)] #![deny(missing_docs)]
#![warn(clippy::all)]
#![warn(clippy::pedantic)]
#![warn(clippy::nursery)]
#![warn(clippy::cargo)]
#![warn(clippy::undocumented_unsafe_blocks)]
#![allow(clippy::unit_arg)] #![allow(clippy::unit_arg)]
#![allow(clippy::missing_errors_doc)]
#![allow(clippy::used_underscore_binding)]
#![allow(clippy::inline_always)]
#![allow(clippy::module_name_repetitions)]
#![allow(clippy::negative_feature_names)]
#![allow(clippy::module_inception)]
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
extern crate alloc; extern crate alloc;
@ -123,6 +134,20 @@ type UNSIGNED_INT = u64;
#[allow(non_camel_case_types)] #[allow(non_camel_case_types)]
type UNSIGNED_INT = u32; type UNSIGNED_INT = u32;
/// The maximum integer that can fit into a [`usize`].
#[cfg(not(target_pointer_width = "32"))]
const MAX_USIZE_INT: INT = INT::MAX;
/// The maximum integer that can fit into a [`usize`].
#[cfg(not(feature = "only_i32"))]
#[cfg(target_pointer_width = "32")]
const MAX_USIZE_INT: INT = usize::MAX as INT;
/// The maximum integer that can fit into a [`usize`].
#[cfg(feature = "only_i32")]
#[cfg(target_pointer_width = "32")]
const MAX_USIZE_INT: INT = INT::MAX;
/// Number of bits in [`INT`]. /// Number of bits in [`INT`].
/// ///
/// It is 64 unless the `only_i32` feature is enabled when it will be 32. /// It is 64 unless the `only_i32` feature is enabled when it will be 32.

View File

@ -301,7 +301,7 @@ fn optimize_stmt_block(
while index < statements.len() { while index < statements.len() {
if preserve_result && index >= statements.len() - 1 { if preserve_result && index >= statements.len() - 1 {
break; break;
} else { }
match statements[index] { match statements[index] {
ref stmt if is_pure(stmt) && index >= first_non_constant => { ref stmt if is_pure(stmt) && index >= first_non_constant => {
state.set_dirty(); state.set_dirty();
@ -317,7 +317,6 @@ fn optimize_stmt_block(
_ => index += 1, _ => index += 1,
} }
} }
}
// Remove all pure statements that do not return values at the end of a block. // Remove all pure statements that do not return values at the end of a block.
// We cannot remove anything for non-pure statements due to potential side-effects. // We cannot remove anything for non-pure statements due to potential side-effects.

View File

@ -5,7 +5,7 @@ use crate::eval::{calc_index, calc_offset_len};
use crate::plugin::*; use crate::plugin::*;
use crate::{ use crate::{
def_package, Array, Dynamic, ExclusiveRange, FnPtr, InclusiveRange, NativeCallContext, def_package, Array, Dynamic, ExclusiveRange, FnPtr, InclusiveRange, NativeCallContext,
Position, RhaiResultOf, StaticVec, ERR, INT, Position, RhaiResultOf, StaticVec, ERR, INT, MAX_USIZE_INT,
}; };
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -217,6 +217,8 @@ pub mod array_functions {
len: INT, len: INT,
item: Dynamic, item: Dynamic,
) -> RhaiResultOf<()> { ) -> RhaiResultOf<()> {
let len = len.min(MAX_USIZE_INT);
if len <= 0 || (len as usize) <= array.len() { if len <= 0 || (len as usize) <= array.len() {
return Ok(()); return Ok(());
} }
@ -369,6 +371,8 @@ pub mod array_functions {
/// ``` /// ```
pub fn truncate(array: &mut Array, len: INT) { pub fn truncate(array: &mut Array, len: INT) {
if !array.is_empty() { if !array.is_empty() {
let len = len.min(MAX_USIZE_INT);
if len > 0 { if len > 0 {
array.truncate(len as usize); array.truncate(len as usize);
} else { } else {
@ -396,6 +400,8 @@ pub mod array_functions {
/// ``` /// ```
pub fn chop(array: &mut Array, len: INT) { pub fn chop(array: &mut Array, len: INT) {
if !array.is_empty() { if !array.is_empty() {
let len = len.min(MAX_USIZE_INT);
if len <= 0 { if len <= 0 {
array.clear(); array.clear();
} else if (len as usize) < array.len() { } else if (len as usize) < array.len() {

View File

@ -4,7 +4,7 @@ use crate::eval::{calc_index, calc_offset_len};
use crate::plugin::*; use crate::plugin::*;
use crate::{ use crate::{
def_package, Array, Blob, Dynamic, ExclusiveRange, InclusiveRange, NativeCallContext, Position, def_package, Array, Blob, Dynamic, ExclusiveRange, InclusiveRange, NativeCallContext, Position,
RhaiResultOf, INT, INT_BYTES, RhaiResultOf, INT, INT_BYTES, MAX_USIZE_INT,
}; };
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -74,6 +74,7 @@ pub mod blob_functions {
len: INT, len: INT,
value: INT, value: INT,
) -> RhaiResultOf<Blob> { ) -> RhaiResultOf<Blob> {
let len = len.min(MAX_USIZE_INT);
let len = if len < 0 { 0 } else { len as usize }; let len = if len < 0 { 0 } else { len as usize };
let _ctx = ctx; let _ctx = ctx;
@ -342,20 +343,21 @@ pub mod blob_functions {
if len <= 0 { if len <= 0 {
return Ok(()); return Ok(());
} }
let len = len.min(MAX_USIZE_INT) as usize;
let value = (value & 0x0000_00ff) as u8; let value = (value & 0x0000_00ff) as u8;
let _ctx = ctx; let _ctx = ctx;
// Check if blob will be over max size limit // Check if blob will be over max size limit
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if _ctx.engine().max_array_size() > 0 && (len as usize) > _ctx.engine().max_array_size() { if _ctx.engine().max_array_size() > 0 && len > _ctx.engine().max_array_size() {
return Err( return Err(
crate::ERR::ErrorDataTooLarge("Size of BLOB".to_string(), Position::NONE).into(), crate::ERR::ErrorDataTooLarge("Size of BLOB".to_string(), Position::NONE).into(),
); );
} }
if len as usize > blob.len() { if len > blob.len() {
blob.resize(len as usize, value); blob.resize(len, value);
} }
Ok(()) Ok(())
@ -461,7 +463,9 @@ pub mod blob_functions {
/// ``` /// ```
pub fn truncate(blob: &mut Blob, len: INT) { pub fn truncate(blob: &mut Blob, len: INT) {
if !blob.is_empty() { if !blob.is_empty() {
if len >= 0 { let len = len.min(MAX_USIZE_INT);
if len > 0 {
blob.truncate(len as usize); blob.truncate(len as usize);
} else { } else {
blob.clear(); blob.clear();

View File

@ -1,6 +1,8 @@
use crate::eval::calc_index; use crate::eval::calc_index;
use crate::plugin::*; use crate::plugin::*;
use crate::{def_package, ExclusiveRange, InclusiveRange, RhaiResultOf, INT, INT_BITS}; use crate::{
def_package, ExclusiveRange, InclusiveRange, RhaiResultOf, INT, INT_BITS, MAX_USIZE_INT,
};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
use std::{ use std::{
@ -173,18 +175,13 @@ pub struct CharsStream(Vec<char>, usize);
impl CharsStream { impl CharsStream {
pub fn new(string: &str, from: INT, len: INT) -> Self { pub fn new(string: &str, from: INT, len: INT) -> Self {
if len <= 0 { if len <= 0 || from > MAX_USIZE_INT {
return Self(Vec::new(), 0); return Self(Vec::new(), 0);
} }
let len = len.min(MAX_USIZE_INT) as usize;
if from >= 0 { if from >= 0 {
return Self( return Self(string.chars().skip(from as usize).take(len).collect(), 0);
string
.chars()
.skip(from as usize)
.take(len as usize)
.collect(),
0,
);
} }
let abs_from = from.unsigned_abs() as usize; let abs_from = from.unsigned_abs() as usize;
@ -194,7 +191,7 @@ impl CharsStream {
} else { } else {
num_chars - abs_from num_chars - abs_from
}; };
Self(string.chars().skip(offset).take(len as usize).collect(), 0) Self(string.chars().skip(offset).take(len).collect(), 0)
} }
} }

View File

@ -1,7 +1,7 @@
use crate::def_package; use crate::def_package;
use crate::plugin::*; use crate::plugin::*;
use crate::types::dynamic::Tag; use crate::types::dynamic::Tag;
use crate::{Dynamic, RhaiResultOf, ERR, INT}; use crate::{Dynamic, RhaiResultOf, ERR, INT, MAX_USIZE_INT};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -113,7 +113,7 @@ mod reflection_functions {
} }
#[rhai_fn(name = "get_fn_metadata_list")] #[rhai_fn(name = "get_fn_metadata_list")]
pub fn get_fn_metadata2(ctx: NativeCallContext, name: &str, params: INT) -> crate::Array { pub fn get_fn_metadata2(ctx: NativeCallContext, name: &str, params: INT) -> crate::Array {
if params < 0 { if params < 0 || params > MAX_USIZE_INT {
crate::Array::new() crate::Array::new()
} else { } else {
collect_fn_metadata(ctx, |_, _, n, p, _| p == (params as usize) && n == name) collect_fn_metadata(ctx, |_, _, n, p, _| p == (params as usize) && n == name)

View File

@ -1,5 +1,8 @@
use crate::plugin::*; use crate::plugin::*;
use crate::{def_package, Dynamic, ExclusiveRange, InclusiveRange, RhaiResultOf, StaticVec, INT}; use crate::{
def_package, Dynamic, ExclusiveRange, InclusiveRange, RhaiResultOf, StaticVec, INT,
MAX_USIZE_INT,
};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
use std::{any::TypeId, mem}; use std::{any::TypeId, mem};
@ -263,10 +266,11 @@ mod string_functions {
/// ``` /// ```
pub fn truncate(string: &mut ImmutableString, len: INT) { pub fn truncate(string: &mut ImmutableString, len: INT) {
if len > 0 { if len > 0 {
let len = len.min(MAX_USIZE_INT) as usize;
let chars: StaticVec<_> = string.chars().collect(); let chars: StaticVec<_> = string.chars().collect();
let copy = string.make_mut(); let copy = string.make_mut();
copy.clear(); copy.clear();
copy.extend(chars.into_iter().take(len as usize)); copy.extend(chars.into_iter().take(len));
} else { } else {
clear(string); clear(string);
} }
@ -344,8 +348,9 @@ mod string_functions {
if string.is_empty() || len <= 0 { if string.is_empty() || len <= 0 {
return ctx.engine().get_interned_string(""); return ctx.engine().get_interned_string("");
} }
let len = len.min(MAX_USIZE_INT) as usize;
let mut chars = StaticVec::<char>::with_capacity(len as usize); let mut chars = StaticVec::<char>::with_capacity(len);
for _ in 0..len { for _ in 0..len {
match string.make_mut().pop() { match string.make_mut().pop() {
@ -556,7 +561,13 @@ mod string_functions {
} }
let start = if start < 0 { let start = if start < 0 {
let abs_start = start.unsigned_abs() as usize; let abs_start = start.unsigned_abs();
if abs_start as u64 > MAX_USIZE_INT as u64 {
return -1 as INT;
}
let abs_start = abs_start as usize;
let chars: Vec<_> = string.chars().collect(); let chars: Vec<_> = string.chars().collect();
let num_chars = chars.len(); let num_chars = chars.len();
if abs_start > num_chars { if abs_start > num_chars {
@ -570,7 +581,7 @@ mod string_functions {
} }
} else if start == 0 { } else if start == 0 {
0 0
} else if start as usize >= string.chars().count() { } else if start > MAX_USIZE_INT || start as usize >= string.chars().count() {
return -1 as INT; return -1 as INT;
} else { } else {
string string
@ -632,7 +643,13 @@ mod string_functions {
} }
let start = if start < 0 { let start = if start < 0 {
let abs_start = start.unsigned_abs() as usize; let abs_start = start.unsigned_abs();
if abs_start as u64 > MAX_USIZE_INT as u64 {
return -1 as INT;
}
let abs_start = abs_start as usize;
let chars = string.chars().collect::<Vec<_>>(); let chars = string.chars().collect::<Vec<_>>();
let num_chars = chars.len(); let num_chars = chars.len();
if abs_start > num_chars { if abs_start > num_chars {
@ -646,7 +663,7 @@ mod string_functions {
} }
} else if start == 0 { } else if start == 0 {
0 0
} else if start as usize >= string.chars().count() { } else if start > MAX_USIZE_INT || start as usize >= string.chars().count() {
return -1 as INT; return -1 as INT;
} else { } else {
string string
@ -704,16 +721,26 @@ mod string_functions {
/// ``` /// ```
pub fn get(string: &str, index: INT) -> Dynamic { pub fn get(string: &str, index: INT) -> Dynamic {
if index >= 0 { if index >= 0 {
if index > MAX_USIZE_INT {
return Dynamic::UNIT;
}
string string
.chars() .chars()
.nth(index as usize) .nth(index as usize)
.map_or_else(|| Dynamic::UNIT, Into::into) .map_or_else(|| Dynamic::UNIT, Into::into)
} else { } else {
// Count from end if negative // Count from end if negative
let abs_index = index.unsigned_abs();
if abs_index as u64 > MAX_USIZE_INT as u64 {
return Dynamic::UNIT;
}
string string
.chars() .chars()
.rev() .rev()
.nth((index.unsigned_abs() as usize) - 1) .nth((abs_index as usize) - 1)
.map_or_else(|| Dynamic::UNIT, Into::into) .map_or_else(|| Dynamic::UNIT, Into::into)
} }
} }
@ -742,14 +769,25 @@ mod string_functions {
/// ``` /// ```
pub fn set(string: &mut ImmutableString, index: INT, character: char) { pub fn set(string: &mut ImmutableString, index: INT, character: char) {
if index >= 0 { if index >= 0 {
if index > MAX_USIZE_INT {
return;
}
let index = index as usize; let index = index as usize;
*string = string *string = string
.chars() .chars()
.enumerate() .enumerate()
.map(|(i, ch)| if i == index { character } else { ch }) .map(|(i, ch)| if i == index { character } else { ch })
.collect(); .collect();
} else { } else {
let abs_index = index.unsigned_abs() as usize; let abs_index = index.unsigned_abs();
if abs_index as u64 > MAX_USIZE_INT as u64 {
return;
}
let abs_index = abs_index as usize;
let string_len = string.chars().count(); let string_len = string.chars().count();
if abs_index <= string_len { if abs_index <= string_len {
@ -833,14 +871,20 @@ mod string_functions {
let offset = if string.is_empty() || len <= 0 { let offset = if string.is_empty() || len <= 0 {
return ctx.engine().get_interned_string(""); return ctx.engine().get_interned_string("");
} else if start < 0 { } else if start < 0 {
let abs_start = start.unsigned_abs() as usize; let abs_start = start.unsigned_abs();
if abs_start as u64 > MAX_USIZE_INT as u64 {
return ctx.engine().get_interned_string("");
}
let abs_start = abs_start as usize;
chars.extend(string.chars()); chars.extend(string.chars());
if abs_start > chars.len() { if abs_start > chars.len() {
0 0
} else { } else {
chars.len() - abs_start chars.len() - abs_start
} }
} else if start as usize >= string.chars().count() { } else if start > MAX_USIZE_INT || start as usize >= string.chars().count() {
return ctx.engine().get_interned_string(""); return ctx.engine().get_interned_string("");
} else { } else {
start as usize start as usize
@ -962,14 +1006,20 @@ mod string_functions {
string.make_mut().clear(); string.make_mut().clear();
return; return;
} else if start < 0 { } else if start < 0 {
let abs_start = start.unsigned_abs() as usize; let abs_start = start.unsigned_abs();
if abs_start as u64 > MAX_USIZE_INT as u64 {
return;
}
let abs_start = abs_start as usize;
chars.extend(string.chars()); chars.extend(string.chars());
if abs_start > chars.len() { if abs_start > chars.len() {
0 0
} else { } else {
chars.len() - abs_start chars.len() - abs_start
} }
} else if start as usize >= string.chars().count() { } else if start > MAX_USIZE_INT || start as usize >= string.chars().count() {
string.make_mut().clear(); string.make_mut().clear();
return; return;
} else { } else {
@ -1131,11 +1181,12 @@ mod string_functions {
if len <= 0 { if len <= 0 {
return Ok(()); return Ok(());
} }
let len = len.min(MAX_USIZE_INT) as usize;
let _ctx = ctx; let _ctx = ctx;
// Check if string will be over max size limit // Check if string will be over max size limit
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() { if _ctx.engine().max_string_size() > 0 && len > _ctx.engine().max_string_size() {
return Err(crate::ERR::ErrorDataTooLarge( return Err(crate::ERR::ErrorDataTooLarge(
"Length of string".to_string(), "Length of string".to_string(),
crate::Position::NONE, crate::Position::NONE,
@ -1145,10 +1196,10 @@ mod string_functions {
let orig_len = string.chars().count(); let orig_len = string.chars().count();
if len as usize > orig_len { if len > orig_len {
let p = string.make_mut(); let p = string.make_mut();
for _ in 0..(len as usize - orig_len) { for _ in 0..(len - orig_len) {
p.push(character); p.push(character);
} }
@ -1192,11 +1243,12 @@ mod string_functions {
if len <= 0 { if len <= 0 {
return Ok(()); return Ok(());
} }
let len = len.min(MAX_USIZE_INT) as usize;
let _ctx = ctx; let _ctx = ctx;
// Check if string will be over max size limit // Check if string will be over max size limit
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if _ctx.engine().max_string_size() > 0 && len as usize > _ctx.engine().max_string_size() { if _ctx.engine().max_string_size() > 0 && len > _ctx.engine().max_string_size() {
return Err(crate::ERR::ErrorDataTooLarge( return Err(crate::ERR::ErrorDataTooLarge(
"Length of string".to_string(), "Length of string".to_string(),
crate::Position::NONE, crate::Position::NONE,
@ -1207,16 +1259,16 @@ mod string_functions {
let mut str_len = string.chars().count(); let mut str_len = string.chars().count();
let padding_len = padding.chars().count(); let padding_len = padding.chars().count();
if len as usize > str_len { if len > str_len {
let p = string.make_mut(); let p = string.make_mut();
while str_len < len as usize { while str_len < len {
if str_len + padding_len <= len as usize { if str_len + padding_len <= len {
p.push_str(padding); p.push_str(padding);
str_len += padding_len; str_len += padding_len;
} else { } else {
p.extend(padding.chars().take(len as usize - str_len)); p.extend(padding.chars().take(len - str_len));
str_len = len as usize; str_len = len;
} }
} }
@ -1263,7 +1315,16 @@ mod string_functions {
#[rhai_fn(name = "split")] #[rhai_fn(name = "split")]
pub fn split_at(ctx: NativeCallContext, string: &mut ImmutableString, index: INT) -> Array { pub fn split_at(ctx: NativeCallContext, string: &mut ImmutableString, index: INT) -> Array {
if index <= 0 { if index <= 0 {
let abs_index = index.unsigned_abs() as usize; let abs_index = index.unsigned_abs();
if abs_index as u64 > MAX_USIZE_INT as u64 {
return vec![
ctx.engine().get_interned_string("").into(),
string.as_str().into(),
];
}
let abs_index = abs_index as usize;
let num_chars = string.chars().count(); let num_chars = string.chars().count();
if abs_index > num_chars { if abs_index > num_chars {
vec![ vec![
@ -1275,6 +1336,11 @@ mod string_functions {
let prefix_len = prefix.len(); let prefix_len = prefix.len();
vec![prefix.into(), string[prefix_len..].into()] vec![prefix.into(), string[prefix_len..].into()]
} }
} else if index > MAX_USIZE_INT {
vec![
string.as_str().into(),
ctx.engine().get_interned_string("").into(),
]
} else { } else {
let prefix: String = string.chars().take(index as usize).collect(); let prefix: String = string.chars().take(index as usize).collect();
let prefix_len = prefix.len(); let prefix_len = prefix.len();
@ -1341,7 +1407,8 @@ mod string_functions {
/// ``` /// ```
#[rhai_fn(name = "split")] #[rhai_fn(name = "split")]
pub fn splitn(string: &str, delimiter: &str, segments: INT) -> Array { pub fn splitn(string: &str, delimiter: &str, segments: INT) -> Array {
let pieces: usize = if segments < 1 { 1 } else { segments as usize }; let segments = segments.min(MAX_USIZE_INT) as usize;
let pieces: usize = if segments < 1 { 1 } else { segments };
string.splitn(pieces, delimiter).map(Into::into).collect() string.splitn(pieces, delimiter).map(Into::into).collect()
} }
/// Split the string into segments based on a `delimiter` character, returning an array of the segments. /// Split the string into segments based on a `delimiter` character, returning an array of the segments.
@ -1371,7 +1438,8 @@ mod string_functions {
/// ``` /// ```
#[rhai_fn(name = "split")] #[rhai_fn(name = "split")]
pub fn splitn_char(string: &str, delimiter: char, segments: INT) -> Array { pub fn splitn_char(string: &str, delimiter: char, segments: INT) -> Array {
let pieces: usize = if segments < 1 { 1 } else { segments as usize }; let segments = segments.min(MAX_USIZE_INT) as usize;
let pieces: usize = if segments < 1 { 1 } else { segments };
string.splitn(pieces, delimiter).map(Into::into).collect() string.splitn(pieces, delimiter).map(Into::into).collect()
} }
/// Split the string into segments based on a `delimiter` string, returning an array of the /// Split the string into segments based on a `delimiter` string, returning an array of the
@ -1402,7 +1470,8 @@ mod string_functions {
/// ``` /// ```
#[rhai_fn(name = "split_rev")] #[rhai_fn(name = "split_rev")]
pub fn rsplitn(string: &str, delimiter: &str, segments: INT) -> Array { pub fn rsplitn(string: &str, delimiter: &str, segments: INT) -> Array {
let pieces: usize = if segments < 1 { 1 } else { segments as usize }; let segments = segments.min(MAX_USIZE_INT) as usize;
let pieces: usize = if segments < 1 { 1 } else { segments };
string.rsplitn(pieces, delimiter).map(Into::into).collect() string.rsplitn(pieces, delimiter).map(Into::into).collect()
} }
/// Split the string into segments based on a `delimiter` character, returning an array of /// Split the string into segments based on a `delimiter` character, returning an array of
@ -1433,7 +1502,8 @@ mod string_functions {
/// ``` /// ```
#[rhai_fn(name = "split_rev")] #[rhai_fn(name = "split_rev")]
pub fn rsplitn_char(string: &str, delimiter: char, segments: INT) -> Array { pub fn rsplitn_char(string: &str, delimiter: char, segments: INT) -> Array {
let pieces: usize = if segments < 1 { 1 } else { segments as usize }; let segments = segments.min(MAX_USIZE_INT) as usize;
let pieces: usize = if segments < 1 { 1 } else { segments };
string.rsplitn(pieces, delimiter).map(Into::into).collect() string.rsplitn(pieces, delimiter).map(Into::into).collect()
} }
} }

View File

@ -34,6 +34,10 @@ pub type ParseResult<T> = Result<T, ParseError>;
type FnLib = BTreeMap<u64, Shared<ScriptFnDef>>; type FnLib = BTreeMap<u64, Shared<ScriptFnDef>>;
const KEYWORD_SEMICOLON: &str = Token::SemiColon.literal_syntax();
const KEYWORD_CLOSE_BRACE: &str = Token::RightBrace.literal_syntax();
/// Invalid variable name that acts as a search barrier in a [`Scope`]. /// Invalid variable name that acts as a search barrier in a [`Scope`].
const SCOPE_SEARCH_BARRIER_MARKER: &str = "$ BARRIER $"; const SCOPE_SEARCH_BARRIER_MARKER: &str = "$ BARRIER $";
@ -41,8 +45,9 @@ const SCOPE_SEARCH_BARRIER_MARKER: &str = "$ BARRIER $";
const NEVER_ENDS: &str = "`Token`"; const NEVER_ENDS: &str = "`Token`";
/// Unroll `switch` ranges no larger than this. /// Unroll `switch` ranges no larger than this.
const SMALL_SWITCH_RANGE: usize = 16; const SMALL_SWITCH_RANGE: INT = 16;
/// Number of string interners used: two additional for property getters/setters if not `no_object`
const NUM_INTERNERS: usize = if cfg!(feature = "no_object") { 1 } else { 3 }; const NUM_INTERNERS: usize = if cfg!(feature = "no_object") { 1 } else { 3 };
/// _(internals)_ A type that encapsulates the current state of the parser. /// _(internals)_ A type that encapsulates the current state of the parser.
@ -899,13 +904,13 @@ impl Engine {
let mut settings = settings; let mut settings = settings;
settings.pos = eat_token(input, Token::LeftBracket); settings.pos = eat_token(input, Token::LeftBracket);
let mut arr = StaticVec::new_const(); let mut array = StaticVec::new_const();
loop { loop {
const MISSING_RBRACKET: &str = "to end this array literal"; const MISSING_RBRACKET: &str = "to end this array literal";
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
if self.max_array_size() > 0 && arr.len() >= self.max_array_size() { if self.max_array_size() > 0 && array.len() >= self.max_array_size() {
return Err(PERR::LiteralTooLarge( return Err(PERR::LiteralTooLarge(
"Size of array literal".to_string(), "Size of array literal".to_string(),
self.max_array_size(), self.max_array_size(),
@ -927,7 +932,7 @@ impl Engine {
} }
_ => { _ => {
let expr = self.parse_expr(input, state, lib, settings.level_up())?; let expr = self.parse_expr(input, state, lib, settings.level_up())?;
arr.push(expr); array.push(expr);
} }
} }
@ -954,9 +959,9 @@ impl Engine {
}; };
} }
arr.shrink_to_fit(); array.shrink_to_fit();
Ok(Expr::Array(arr.into(), settings.pos)) Ok(Expr::Array(array.into(), settings.pos))
} }
/// Parse a map literal. /// Parse a map literal.
@ -2010,7 +2015,7 @@ impl Engine {
} }
} }
let op_info = if let Some(op) = op { let op_info = if let Some(ref op) = op {
OpAssignment::new_op_assignment_from_token(op, op_pos) OpAssignment::new_op_assignment_from_token(op, op_pos)
} else { } else {
OpAssignment::new_assignment(op_pos) OpAssignment::new_assignment(op_pos)
@ -2605,9 +2610,6 @@ impl Engine {
inputs.shrink_to_fit(); inputs.shrink_to_fit();
tokens.shrink_to_fit(); tokens.shrink_to_fit();
const KEYWORD_SEMICOLON: &str = Token::SemiColon.literal_syntax();
const KEYWORD_CLOSE_BRACE: &str = Token::RightBrace.literal_syntax();
let self_terminated = matches!( let self_terminated = matches!(
required_token.as_str(), required_token.as_str(),
// It is self-terminating if the last symbol is a block // It is self-terminating if the last symbol is a block
@ -2912,7 +2914,7 @@ impl Engine {
Ok(true) => (), Ok(true) => (),
Ok(false) => return Err(PERR::ForbiddenVariable(name.to_string()).into_err(pos)), Ok(false) => return Err(PERR::ForbiddenVariable(name.to_string()).into_err(pos)),
Err(err) => match *err { Err(err) => match *err {
EvalAltResult::ErrorParsing(perr, pos) => return Err(perr.into_err(pos)), EvalAltResult::ErrorParsing(e, pos) => return Err(e.into_err(pos)),
_ => return Err(PERR::ForbiddenVariable(name.to_string()).into_err(pos)), _ => return Err(PERR::ForbiddenVariable(name.to_string()).into_err(pos)),
}, },
} }

View File

@ -11,6 +11,7 @@
#[macro_export] #[macro_export]
macro_rules! reify { macro_rules! reify {
($old:ident, |$new:ident : $t:ty| $code:expr, || $fallback:expr) => {{ ($old:ident, |$new:ident : $t:ty| $code:expr, || $fallback:expr) => {{
#[allow(clippy::redundant_else)]
if std::any::TypeId::of::<$t>() == std::any::Any::type_id(&$old) { if std::any::TypeId::of::<$t>() == std::any::Any::type_id(&$old) {
// SAFETY: This is safe because we already checked to make sure the two types // SAFETY: This is safe because we already checked to make sure the two types
// are actually the same. // are actually the same.

View File

@ -2315,15 +2315,15 @@ impl InputStream for MultiInputsStream<'_> {
if self.index >= self.streams.len() { if self.index >= self.streams.len() {
// No more streams // No more streams
return None; return None;
} else if let Some(ch) = self.streams[self.index].next() { }
if let Some(ch) = self.streams[self.index].next() {
// Next character in current stream // Next character in current stream
return Some(ch); return Some(ch);
} else { }
// Jump to the next stream // Jump to the next stream
self.index += 1; self.index += 1;
} }
} }
}
fn peek_next(&mut self) -> Option<char> { fn peek_next(&mut self) -> Option<char> {
if let Some(ch) = self.buf { if let Some(ch) = self.buf {
return Some(ch); return Some(ch);
@ -2333,16 +2333,16 @@ impl InputStream for MultiInputsStream<'_> {
if self.index >= self.streams.len() { if self.index >= self.streams.len() {
// No more streams // No more streams
return None; return None;
} else if let Some(&ch) = self.streams[self.index].peek() { }
if let Some(&ch) = self.streams[self.index].peek() {
// Next character in current stream // Next character in current stream
return Some(ch); return Some(ch);
} else { }
// Jump to the next stream // Jump to the next stream
self.index += 1; self.index += 1;
} }
} }
} }
}
/// _(internals)_ An iterator on a [`Token`] stream. /// _(internals)_ An iterator on a [`Token`] stream.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.

View File

@ -936,7 +936,7 @@ impl Dynamic {
#[must_use] #[must_use]
pub const fn from_float(value: crate::FLOAT) -> Self { pub const fn from_float(value: crate::FLOAT) -> Self {
Self(Union::Float( Self(Union::Float(
crate::ast::FloatWrapper::new_const(value), crate::ast::FloatWrapper::new(value),
DEFAULT_TAG_VALUE, DEFAULT_TAG_VALUE,
ReadWrite, ReadWrite,
)) ))