Clean up clippy.

This commit is contained in:
Stephen Chung 2022-07-27 16:04:24 +08:00
parent 21f822020f
commit 39dee556c4
36 changed files with 271 additions and 369 deletions

1
.gitignore vendored
View File

@ -6,3 +6,4 @@ benches/results
before*
after*
.rhai-repl-history.txt
clippy.toml

View File

@ -46,6 +46,7 @@ Enhancements
* `FnAccess::is_private`, `FnAccess::is_public`, `FnNamespace::is_module_namespace` and `FnNameSpace::is_global_namespace` are added for convenience.
* `Iterator<Item=T>` type for functions metadata is simplified to `Iterator<T>`.
* `Scope::remove` is added to remove a variable from a `Scope`, returning its value.
* The code base is cleaner by running it through Clippy.
Version 1.8.0

View File

@ -149,25 +149,23 @@ pub fn doc_attributes(attrs: &[syn::Attribute]) -> syn::Result<Vec<String>> {
for attr in attrs {
if let Some(i) = attr.path.get_ident() {
if *i == "doc" {
match attr.parse_meta()? {
syn::Meta::NameValue(syn::MetaNameValue {
lit: syn::Lit::Str(s),
..
}) => {
let mut line = s.value();
if let syn::Meta::NameValue(syn::MetaNameValue {
lit: syn::Lit::Str(s),
..
}) = attr.parse_meta()?
{
let mut line = s.value();
if line.contains('\n') {
// Must be a block comment `/** ... */`
line.insert_str(0, "/**");
line.push_str("*/");
} else {
// Single line - assume it is `///`
line.insert_str(0, "///");
}
comments.push(line);
if line.contains('\n') {
// Must be a block comment `/** ... */`
line.insert_str(0, "/**");
line.push_str("*/");
} else {
// Single line - assume it is `///`
line.insert_str(0, "///");
}
_ => (),
comments.push(line);
}
}
}

View File

@ -302,18 +302,15 @@ impl Parse for ExportedFn {
let visibility = fn_all.vis;
// Determine if the function requires a call context
match fn_all.sig.inputs.first() {
Some(syn::FnArg::Typed(syn::PatType { ref ty, .. })) => {
match flatten_type_groups(ty.as_ref()) {
syn::Type::Path(p)
if p.path == context_type_path1 || p.path == context_type_path2 =>
{
pass_context = true;
}
_ => {}
if let Some(syn::FnArg::Typed(syn::PatType { ref ty, .. })) = fn_all.sig.inputs.first() {
match flatten_type_groups(ty.as_ref()) {
syn::Type::Path(p)
if p.path == context_type_path1 || p.path == context_type_path2 =>
{
pass_context = true;
}
_ => {}
}
_ => {}
}
let skip_slots = if pass_context { 1 } else { 0 };
@ -378,25 +375,22 @@ impl Parse for ExportedFn {
}
// Check return type.
match fn_all.sig.output {
syn::ReturnType::Type(.., ref ret_type) => {
match flatten_type_groups(ret_type.as_ref()) {
syn::Type::Ptr(..) => {
return Err(syn::Error::new(
fn_all.sig.output.span(),
"Rhai functions cannot return pointers",
))
}
syn::Type::Reference(..) => {
return Err(syn::Error::new(
fn_all.sig.output.span(),
"Rhai functions cannot return references",
))
}
_ => {}
if let syn::ReturnType::Type(.., ref ret_type) = fn_all.sig.output {
match flatten_type_groups(ret_type.as_ref()) {
syn::Type::Ptr(..) => {
return Err(syn::Error::new(
fn_all.sig.output.span(),
"Rhai functions cannot return pointers",
))
}
syn::Type::Reference(..) => {
return Err(syn::Error::new(
fn_all.sig.output.span(),
"Rhai functions cannot return references",
))
}
_ => {}
}
_ => {}
}
Ok(ExportedFn {
entire_span,

View File

@ -138,38 +138,38 @@ impl Parse for Module {
})?;
// Gather and parse constants definitions.
for item in &*content {
match item {
syn::Item::Const(syn::ItemConst {
vis: syn::Visibility::Public(..),
ref expr,
ident,
attrs,
ty,
..
}) => consts.push(ExportedConst {
if let syn::Item::Const(syn::ItemConst {
vis: syn::Visibility::Public(..),
ref expr,
ident,
attrs,
ty,
..
}) = item
{
consts.push(ExportedConst {
name: ident.to_string(),
typ: ty.clone(),
expr: expr.as_ref().clone(),
cfg_attrs: crate::attrs::collect_cfg_attr(attrs),
}),
_ => {}
})
}
}
// Gather and parse type definitions.
for item in &*content {
match item {
syn::Item::Type(syn::ItemType {
vis: syn::Visibility::Public(..),
ident,
attrs,
ty,
..
}) => custom_types.push(ExportedType {
if let syn::Item::Type(syn::ItemType {
vis: syn::Visibility::Public(..),
ident,
attrs,
ty,
..
}) = item
{
custom_types.push(ExportedType {
name: ident.to_string(),
typ: ty.clone(),
cfg_attrs: crate::attrs::collect_cfg_attr(attrs),
}),
_ => {}
})
}
}
// Gather and parse sub-module definitions.

View File

@ -270,11 +270,10 @@ impl Engine {
// Make it a custom keyword/symbol if it is disabled or reserved
if (!self.disabled_symbols.is_empty() && self.disabled_symbols.contains(s))
|| token.map_or(false, |v| v.is_reserved())
&& self.custom_keywords.is_empty()
|| !self.custom_keywords.contains_key(s)
{
if self.custom_keywords.is_empty() || !self.custom_keywords.contains_key(s)
{
self.custom_keywords.insert(s.into(), None);
}
self.custom_keywords.insert(s.into(), None);
}
s.into()
}

View File

@ -28,7 +28,6 @@ impl Engine {
/// # }
/// ```
#[inline(always)]
#[must_use]
pub fn definitions(&self) -> Definitions {
Definitions {
engine: self,
@ -54,7 +53,6 @@ impl Engine {
/// # }
/// ```
#[inline(always)]
#[must_use]
pub fn definitions_with_scope<'e>(&'e self, scope: &'e Scope<'e>) -> Definitions<'e> {
Definitions {
engine: self,
@ -112,7 +110,6 @@ impl<'e> Definitions<'e> {
///
/// The returned iterator yields all definition files as (filename, content) pairs.
#[inline]
#[must_use]
pub fn iter_files(&self) -> impl Iterator<Item = (String, String)> + '_ {
IntoIterator::into_iter([
(
@ -182,7 +179,6 @@ impl<'e> Definitions<'e> {
///
/// Always starts with `module <module name>;`.
#[cfg(not(feature = "no_module"))]
#[must_use]
pub fn modules(&self) -> impl Iterator<Item = (String, String)> + '_ {
let mut m = self
.engine

View File

@ -9,24 +9,24 @@ bitflags! {
/// Bit-flags containing all language options for the [`Engine`].
pub struct LangOptions: u8 {
/// Is `if`-expression allowed?
const IF_EXPR = 0b_00000001;
const IF_EXPR = 0b_0000_0001;
/// Is `switch` expression allowed?
const SWITCH_EXPR = 0b_00000010;
const SWITCH_EXPR = 0b_0000_0010;
/// Is statement-expression allowed?
const STMT_EXPR = 0b_00000100;
const STMT_EXPR = 0b_0000_0100;
/// Is anonymous function allowed?
#[cfg(not(feature = "no_function"))]
const ANON_FN = 0b_00001000;
const ANON_FN = 0b_0000_1000;
/// Is looping allowed?
const LOOPING = 0b_00010000;
const LOOPING = 0b_0001_0000;
/// Is variables shadowing allowed?
const SHADOW = 0b_00100000;
const SHADOW = 0b_0010_0000;
/// Strict variables mode?
const STRICT_VAR = 0b_01000000;
const STRICT_VAR = 0b_0100_0000;
/// Raise error if an object map property does not exist?
/// Returns `()` if `false`.
#[cfg(not(feature = "no_object"))]
const FAIL_ON_INVALID_MAP_PROPERTY = 0b_10000000;
const FAIL_ON_INVALID_MAP_PROPERTY = 0b_1000_0000;
}
}

View File

@ -144,9 +144,9 @@ impl Engine {
#[inline]
#[must_use]
pub(crate) fn format_type_name<'a>(&'a self, name: &'a str) -> std::borrow::Cow<'a, str> {
if name.starts_with("&mut ") {
let x = &name[5..];
if let Some(x) = name.strip_prefix("&mut ") {
let r = self.format_type_name(x);
return if x != r {
format!("&mut {}", r).into()
} else {
@ -167,9 +167,9 @@ impl Engine {
return None;
})
.unwrap_or_else(|| match name {
"INT" => return type_name::<crate::INT>(),
"INT" => type_name::<crate::INT>(),
#[cfg(not(feature = "no_float"))]
"FLOAT" => return type_name::<crate::FLOAT>(),
"FLOAT" => type_name::<crate::FLOAT>(),
_ => map_std_type_name(name, false),
})
.into()

View File

@ -158,19 +158,13 @@ impl ConditionalExpr {
#[inline(always)]
#[must_use]
pub fn is_always_true(&self) -> bool {
match self.condition {
Expr::BoolConstant(true, ..) => true,
_ => false,
}
matches!(self.condition, Expr::BoolConstant(true, ..))
}
/// Is the condition always `false`?
#[inline(always)]
#[must_use]
pub fn is_always_false(&self) -> bool {
match self.condition {
Expr::BoolConstant(false, ..) => true,
_ => false,
}
matches!(self.condition, Expr::BoolConstant(false, ..))
}
}
@ -388,7 +382,6 @@ impl StmtBlock {
}
/// Get an iterator over the statements of this statements block.
#[inline(always)]
#[must_use]
pub fn iter(&self) -> impl Iterator<Item = &Stmt> {
self.block.iter()
}

View File

@ -29,7 +29,7 @@ fn print_source(lines: &[String], pos: Position, offset: usize, window: (usize,
println!("{0:>1$}", "^", pos + offset + line_no_len + 2);
}
} else {
for n in start..=end {
for (n, s) in lines.iter().enumerate().take(end + 1).skip(start) {
let marker = if n == line { "> " } else { " " };
println!(
@ -38,7 +38,7 @@ fn print_source(lines: &[String], pos: Position, offset: usize, window: (usize,
marker,
n + 1,
line_no_len,
lines[n],
s,
if n == line { "\x1b[39m" } else { "" },
);
@ -161,7 +161,7 @@ fn print_debug_help() {
// Load script to debug.
fn load_script(engine: &Engine) -> (rhai::AST, String) {
if let Some(filename) = env::args().skip(1).next() {
if let Some(filename) = env::args().nth(1) {
let mut contents = String::new();
let filename = match Path::new(&filename).canonicalize() {
@ -301,12 +301,7 @@ fn debug_callback(
match stdin().read_line(&mut input) {
Ok(0) => break Ok(DebuggerCommand::Continue),
Ok(_) => match input
.trim()
.split_whitespace()
.collect::<Vec<_>>()
.as_slice()
{
Ok(_) => match input.split_whitespace().collect::<Vec<_>>().as_slice() {
["help" | "h"] => print_debug_help(),
["exit" | "quit" | "q" | "kill", ..] => {
println!("Script terminated. Bye!");
@ -328,14 +323,14 @@ fn debug_callback(
["source"] => {
println!("{}", context.global_runtime_state().source().unwrap_or(""))
}
["list" | "l"] => print_current_source(&mut context, source, pos, &lines, (3, 6)),
["list" | "l"] => print_current_source(&mut context, source, pos, lines, (3, 6)),
["list" | "l", n] if n.parse::<usize>().is_ok() => {
let num = n.parse::<usize>().unwrap();
if num <= 0 || num > lines.len() {
if num == 0 || num > lines.len() {
eprintln!("\x1b[31mInvalid line: {}\x1b[39m", num);
} else {
let pos = Position::new(num as u16, 0);
print_current_source(&mut context, source, pos, &lines, (3, 6));
print_current_source(&mut context, source, pos, lines, (3, 6));
}
}
["continue" | "c"] => break Ok(DebuggerCommand::Continue),
@ -405,7 +400,7 @@ fn debug_callback(
rhai::debugger::BreakPoint::AtPosition { pos, .. } => {
let line_num = format!("[{}] line ", i + 1);
print!("{}", line_num);
print_source(&lines, *pos, line_num.len(), (0, 0));
print_source(lines, *pos, line_num.len(), (0, 0));
}
_ => println!("[{}] {}", i + 1, bp),
},
@ -580,7 +575,7 @@ fn debug_callback(
break Err(EvalAltResult::ErrorRuntime(value, pos).into());
}
["throw", ..] => {
let msg = input.trim().splitn(2, ' ').skip(1).next().unwrap_or("");
let msg = input.trim().split_once(' ').map(|(_, x)| x).unwrap_or("");
break Err(EvalAltResult::ErrorRuntime(msg.trim().into(), pos).into());
}
["run" | "r"] => {

View File

@ -158,7 +158,7 @@ fn load_script_files(engine: &mut Engine) {
.map_err(|err| err.into())
.and_then(|mut ast| {
ast.set_source(filename.to_string_lossy().to_string());
Module::eval_ast_as_new(Scope::new(), &ast, &engine)
Module::eval_ast_as_new(Scope::new(), &ast, engine)
}) {
Err(err) => {
let filename = filename.to_string_lossy();
@ -166,7 +166,7 @@ fn load_script_files(engine: &mut Engine) {
eprintln!("{:=<1$}", "", filename.len());
eprintln!("{}", filename);
eprintln!("{:=<1$}", "", filename.len());
eprintln!("");
eprintln!();
print_error(&contents, *err);
exit(1);
@ -353,7 +353,7 @@ fn main() {
match rl.readline(prompt) {
// Line continuation
Ok(mut line) if line.ends_with("\\") => {
Ok(mut line) if line.ends_with('\\') => {
line.pop();
input += &line;
input.push('\n');
@ -361,10 +361,12 @@ fn main() {
Ok(line) => {
input += &line;
let cmd = input.trim();
if !cmd.is_empty() && !cmd.starts_with('!') && cmd.trim() != "history" {
if rl.add_history_entry(input.clone()) {
history_offset += 1;
}
if !cmd.is_empty()
&& !cmd.starts_with('!')
&& cmd.trim() != "history"
&& rl.add_history_entry(input.clone())
{
history_offset += 1;
}
break;
}

View File

@ -14,7 +14,7 @@ fn eprint_error(input: &str, mut err: EvalAltResult) {
line_no.len() + pos.position().unwrap(),
err_msg
);
eprintln!("");
eprintln!();
}
let lines: Vec<_> = input.split('\n').collect();
@ -96,7 +96,7 @@ fn main() {
eprintln!("{:=<1$}", "", filename.len());
eprintln!("{}", filename);
eprintln!("{:=<1$}", "", filename.len());
eprintln!("");
eprintln!();
eprint_error(contents, *err);
}

View File

@ -322,22 +322,19 @@ impl Engine {
/// Check a result to ensure that it is valid.
pub(crate) fn check_return_value(&self, mut result: RhaiResult, _pos: Position) -> RhaiResult {
match result {
Ok(ref mut r) => {
// Concentrate all empty strings into one instance to save memory
if let Dynamic(Union::Str(s, ..)) = r {
if s.is_empty() {
if !s.ptr_eq(&self.empty_string) {
*s = self.const_empty_string();
}
return result;
if let Ok(ref mut r) = result {
// Concentrate all empty strings into one instance to save memory
if let Dynamic(Union::Str(s, ..)) = r {
if s.is_empty() {
if !s.ptr_eq(&self.empty_string) {
*s = self.const_empty_string();
}
return result;
}
#[cfg(not(feature = "unchecked"))]
self.check_data_size(r, _pos)?;
}
_ => (),
#[cfg(not(feature = "unchecked"))]
self.check_data_size(r, _pos)?;
}
result

View File

@ -980,8 +980,8 @@ impl Engine {
})?,
offset,
)
} else if let Some(abs_index) = index.checked_abs() {
let offset = abs_index as usize;
} else {
let offset = index.unsigned_abs() as usize;
(
// Count from end if negative
s.chars().rev().nth(offset - 1).ok_or_else(|| {
@ -990,9 +990,6 @@ impl Engine {
})?,
offset,
)
} else {
let chars_len = s.chars().count();
return Err(ERR::ErrorStringBounds(chars_len, index, idx_pos).into());
};
Ok(Target::StringChar {

View File

@ -441,7 +441,6 @@ impl Engine {
///
/// It is up to the [`Engine`] to reactivate the debugger.
#[inline(always)]
#[must_use]
pub(crate) fn run_debugger_with_reset<'a>(
&self,
scope: &mut Scope,
@ -464,7 +463,6 @@ impl Engine {
///
/// It is up to the [`Engine`] to reactivate the debugger.
#[inline]
#[must_use]
pub(crate) fn run_debugger_with_reset_raw<'a>(
&self,
scope: &mut Scope,
@ -514,7 +512,6 @@ impl Engine {
///
/// It is up to the [`Engine`] to reactivate the debugger.
#[inline]
#[must_use]
pub(crate) fn run_debugger_raw<'a>(
&self,
scope: &mut Scope,

View File

@ -15,9 +15,7 @@ use std::prelude::v1::*;
#[allow(dead_code)]
pub fn calc_offset_len(length: usize, start: crate::INT, len: crate::INT) -> (usize, usize) {
let start = if start < 0 {
start.checked_abs().map_or(0, |positive_start| {
length - usize::min(positive_start as usize, length)
})
length - usize::min(start.unsigned_abs() as usize, length)
} else if start as usize >= length {
return (length, 0);
} else {
@ -50,20 +48,14 @@ pub fn calc_index<E>(
) -> Result<usize, E> {
if start < 0 {
if negative_count_from_end {
let abs_start = start.unsigned_abs() as usize;
// Count from end if negative
#[cfg(not(feature = "unchecked"))]
return match start.checked_abs() {
Some(positive_start) => {
if (positive_start as usize) > length {
err()
} else {
Ok(length - (positive_start as usize))
}
}
None => err(),
};
#[cfg(feature = "unchecked")]
return Ok(length - (start.abs() as usize));
if abs_start > length {
err()
} else {
Ok(length - abs_start)
}
} else {
err()
}

View File

@ -453,7 +453,7 @@ impl Engine {
// Check the data size of any `&mut` object, which may be changed.
#[cfg(not(feature = "unchecked"))]
if is_ref_mut && args.len() > 0 {
if is_ref_mut && !args.is_empty() {
self.check_data_size(args[0], pos)?;
}
@ -1180,7 +1180,7 @@ impl Engine {
if capture_scope && !scope.is_empty() {
first_arg
.iter()
.map(|&v| v)
.copied()
.chain(a_expr.iter())
.try_for_each(|expr| {
self.get_arg_value(scope, global, caches, lib, this_ptr, expr, level)

View File

@ -173,10 +173,10 @@ pub fn calc_fn_hash(fn_name: &str, num: usize) -> u64 {
pub fn calc_fn_params_hash(params: impl IntoIterator<Item = TypeId>) -> u64 {
let s = &mut get_hasher();
let mut len = 0;
params
.into_iter()
.inspect(|_| len += 1)
.for_each(|t| t.hash(s));
params.into_iter().for_each(|t| {
len += 1;
t.hash(s)
});
len.hash(s);
match s.finish() {

View File

@ -37,17 +37,14 @@ pub use std::sync::Arc as Shared;
/// Synchronized shared object.
#[cfg(not(feature = "sync"))]
#[allow(dead_code)]
pub use std::cell::RefCell as Locked;
/// Read-only lock guard for synchronized shared object.
#[cfg(not(feature = "sync"))]
#[allow(dead_code)]
pub type LockGuard<'a, T> = std::cell::Ref<'a, T>;
/// Mutable lock guard for synchronized shared object.
#[cfg(not(feature = "sync"))]
#[allow(dead_code)]
pub type LockGuardMut<'a, T> = std::cell::RefMut<'a, T>;
/// Synchronized shared object.
@ -397,7 +394,7 @@ pub fn shared_take<T>(value: Shared<T>) -> T {
#[inline(always)]
#[must_use]
#[allow(dead_code)]
pub fn locked_read<'a, T>(value: &'a Locked<T>) -> LockGuard<'a, T> {
pub fn locked_read<T>(value: &Locked<T>) -> LockGuard<T> {
#[cfg(not(feature = "sync"))]
return value.borrow();
@ -409,7 +406,7 @@ pub fn locked_read<'a, T>(value: &'a Locked<T>) -> LockGuard<'a, T> {
#[inline(always)]
#[must_use]
#[allow(dead_code)]
pub fn locked_write<'a, T>(value: &'a Locked<T>) -> LockGuardMut<'a, T> {
pub fn locked_write<T>(value: &Locked<T>) -> LockGuardMut<T> {
#[cfg(not(feature = "sync"))]
return value.borrow_mut();

View File

@ -56,7 +56,7 @@ pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
// We consume the argument and then replace it with () - the argument is not supposed to be used again.
// This way, we avoid having to clone the argument again, because it is already a clone when passed here.
return mem::take(data).cast::<T>();
mem::take(data).cast::<T>()
}
/// Trait to register custom Rust functions.

View File

@ -88,7 +88,7 @@ impl Engine {
let orig_call_stack_len = global.debugger.call_stack().len();
// Put arguments into scope as variables
scope.extend(fn_def.params.iter().cloned().zip(args.into_iter().map(|v| {
scope.extend(fn_def.params.iter().cloned().zip(args.iter_mut().map(|v| {
// Actually consume the arguments instead of cloning them
mem::take(*v)
})));
@ -98,11 +98,7 @@ impl Engine {
if self.debugger.is_some() {
global.debugger.push_call_stack_frame(
fn_def.name.clone(),
scope
.iter()
.skip(orig_scope_len)
.map(|(.., v)| v.clone())
.collect(),
scope.iter().skip(orig_scope_len).map(|(.., v)| v).collect(),
global.source.clone(),
pos,
);

View File

@ -58,6 +58,7 @@
#![cfg_attr(feature = "no_std", no_std)]
#![deny(missing_docs)]
#![allow(clippy::unit_arg)]
#[cfg(feature = "no_std")]
extern crate alloc;

View File

@ -128,10 +128,9 @@ impl FuncInfo {
let typ = typ.trim();
if typ.starts_with("rhai::") {
return Self::format_type(&typ[6..], is_return_type);
} else if typ.starts_with("&mut ") {
let x = &typ[5..];
if let Some(x) = typ.strip_prefix("rhai::") {
return Self::format_type(x, is_return_type);
} else if let Some(x) = typ.strip_prefix("&mut ") {
let r = Self::format_type(x, false);
return if r == x {
typ.into()
@ -1896,7 +1895,6 @@ impl Module {
#[cfg(not(feature = "no_function"))]
#[cfg(feature = "internals")]
#[inline(always)]
#[must_use]
pub fn iter_script_fn_info(
&self,
) -> impl Iterator<

View File

@ -20,6 +20,7 @@ use std::{ops::AddAssign, slice::Iter, vec::IntoIter};
/// let mut engine = Engine::new();
/// engine.set_module_resolver(collection);
/// ```
#[derive(Default)]
pub struct ModuleResolversCollection(Vec<Box<dyn ModuleResolver>>);
impl ModuleResolversCollection {
@ -41,7 +42,7 @@ impl ModuleResolversCollection {
/// ```
#[inline(always)]
#[must_use]
pub fn new() -> Self {
pub const fn new() -> Self {
Self(Vec::new())
}
/// Append a [module resolver][ModuleResolver] to the end.

View File

@ -374,7 +374,7 @@ impl ModuleResolver for FileModuleResolver {
pos: Position,
) -> Option<RhaiResultOf<crate::AST>> {
// Construct the script file path
let file_path = self.get_file_path(path, source_path.map(|s| Path::new(s)));
let file_path = self.get_file_path(path, source_path.map(Path::new));
// Load the script file and compile it
Some(

View File

@ -212,26 +212,21 @@ fn optimize_stmt_block(
};
// Flatten blocks
loop {
if let Some(n) = statements.iter().position(|s| match s {
Stmt::Block(block, ..) if !block.iter().any(Stmt::is_block_dependent) => true,
_ => false,
}) {
let (first, second) = statements.split_at_mut(n);
let stmt = mem::take(&mut second[0]);
let mut stmts = match stmt {
Stmt::Block(block, ..) => block,
stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
};
statements = first
.iter_mut()
.map(mem::take)
.chain(stmts.iter_mut().map(mem::take))
.chain(second.iter_mut().skip(1).map(mem::take))
.collect();
} else {
break;
}
while let Some(n) = statements.iter().position(
|s| matches!(s, Stmt::Block(block, ..) if !block.iter().any(Stmt::is_block_dependent)),
) {
let (first, second) = statements.split_at_mut(n);
let stmt = mem::take(&mut second[0]);
let mut stmts = match stmt {
Stmt::Block(block, ..) => block,
stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
};
statements = first
.iter_mut()
.map(mem::take)
.chain(stmts.iter_mut().map(mem::take))
.chain(second.iter_mut().skip(1).map(mem::take))
.collect();
is_dirty = true;
}
@ -606,7 +601,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
.iter()
.all(|r| expressions[r.index()].is_always_true())
{
for r in ranges.iter().filter(|r| r.contains(value)) {
if let Some(r) = ranges.iter().find(|r| r.contains(value)) {
let range_block = &mut expressions[r.index()];
if range_block.is_always_true() {
@ -698,11 +693,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
optimize_expr(&mut b.condition, state, false);
optimize_expr(&mut b.expr, state, false);
if b.is_always_false() {
if !b.expr.is_unit() {
b.expr = Expr::Unit(b.expr.position());
state.set_dirty();
}
if b.is_always_false() && !b.expr.is_unit() {
b.expr = Expr::Unit(b.expr.position());
state.set_dirty();
}
}
@ -958,10 +951,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
***x = optimize_stmt_block(mem::take(&mut **x), state, true, true, false);
// { Stmt(Expr) } - promote
match &mut ****x {
[ Stmt::Expr(e) ] => { state.set_dirty(); *expr = mem::take(e); }
_ => ()
}
if let [ Stmt::Expr(e) ] = &mut ****x { state.set_dirty(); *expr = mem::take(e); }
}
// ()?.rhs
#[cfg(not(feature = "no_object"))]
@ -1010,11 +1000,11 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
*expr = result;
}
// array[-int]
(Expr::Array(a, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.checked_abs().map(|n| n as usize <= a.len()).unwrap_or(false) && a.iter().all(Expr::is_pure) => {
(Expr::Array(a, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.unsigned_abs() as usize <= a.len() && a.iter().all(Expr::is_pure) => {
// Array literal where everything is pure - promote the indexed item.
// All other items can be thrown away.
state.set_dirty();
let index = a.len() - i.abs() as usize;
let index = a.len() - i.unsigned_abs() as usize;
let mut result = mem::take(&mut a[index]);
result.set_position(*pos);
*expr = result;
@ -1035,10 +1025,10 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
*expr = Expr::BoolConstant((*n & (1 << (*i as usize))) != 0, *pos);
}
// int[-int]
(Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.checked_abs().map(|i| i as usize <= crate::INT_BITS).unwrap_or(false) => {
(Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.unsigned_abs() as usize <= crate::INT_BITS => {
// Bit-field literal indexing - get the bit
state.set_dirty();
*expr = Expr::BoolConstant((*n & (1 << (crate::INT_BITS - i.abs() as usize))) != 0, *pos);
*expr = Expr::BoolConstant((*n & (1 << (crate::INT_BITS - i.unsigned_abs() as usize))) != 0, *pos);
}
// string[int]
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, ..)) if *i >= 0 && (*i as usize) < s.chars().count() => {
@ -1047,10 +1037,10 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
*expr = Expr::CharConstant(s.chars().nth(*i as usize).unwrap(), *pos);
}
// string[-int]
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.checked_abs().map(|n| n as usize <= s.chars().count()).unwrap_or(false) => {
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, ..)) if *i < 0 && i.unsigned_abs() as usize <= s.chars().count() => {
// String literal indexing - get the character
state.set_dirty();
*expr = Expr::CharConstant(s.chars().rev().nth(i.abs() as usize - 1).unwrap(), *pos);
*expr = Expr::CharConstant(s.chars().rev().nth(i.unsigned_abs() as usize - 1).unwrap(), *pos);
}
// var[rhs]
(Expr::Variable(..), rhs) => optimize_expr(rhs, state, true),

View File

@ -290,7 +290,7 @@ pub mod array_functions {
if array.is_empty() {
Dynamic::UNIT
} else {
array.pop().unwrap_or_else(|| Dynamic::UNIT)
array.pop().unwrap_or(Dynamic::UNIT)
}
}
/// Remove the first element from the array and return it.
@ -1344,7 +1344,7 @@ pub mod array_functions {
array.dedup_by(|x, y| {
comparer
.call_raw(&ctx, None, [y.clone(), x.clone()])
.unwrap_or_else(|_| Dynamic::FALSE)
.unwrap_or(Dynamic::FALSE)
.as_bool()
.unwrap_or(false)
});

View File

@ -96,16 +96,11 @@ impl<T: Debug + Copy + PartialOrd> Iterator for StepRange<T> {
self.from = (self.add)(self.from, self.step)?;
if self.dir > 0 {
if self.from >= self.to {
self.dir = 0;
}
} else if self.dir < 0 {
if self.from <= self.to {
self.dir = 0;
}
} else {
unreachable!("`dir` != 0");
match self.dir.cmp(&0) {
Ordering::Greater if self.from >= self.to => self.dir = 0,
Ordering::Less if self.from <= self.to => self.dir = 0,
Ordering::Equal => unreachable!("`dir` != 0"),
_ => (),
}
Some(v)
@ -184,28 +179,15 @@ impl CharsStream {
0,
);
}
#[cfg(not(feature = "unchecked"))]
return if let Some(abs_from) = from.checked_abs() {
let num_chars = string.chars().count();
let offset = if num_chars < (abs_from as usize) {
0
} else {
num_chars - (abs_from as usize)
};
Self(string.chars().skip(offset).take(len as usize).collect(), 0)
} else {
Self(string.chars().skip(0).take(len as usize).collect(), 0)
};
#[cfg(feature = "unchecked")]
return Self(
string
.chars()
.skip(from as usize)
.take(len as usize)
.collect(),
0,
);
let abs_from = from.unsigned_abs() as usize;
let num_chars = string.chars().count();
let offset = if num_chars < abs_from {
0
} else {
num_chars - abs_from
};
Self(string.chars().skip(offset).take(len as usize).collect(), 0)
}
}

View File

@ -93,7 +93,7 @@ mod map_functions {
/// ```
pub fn remove(map: &mut Map, property: &str) -> Dynamic {
if !map.is_empty() {
map.remove(property).unwrap_or_else(|| Dynamic::UNIT)
map.remove(property).unwrap_or(Dynamic::UNIT)
} else {
Dynamic::UNIT
}

View File

@ -534,20 +534,17 @@ mod string_functions {
}
let start = if start < 0 {
if let Some(n) = start.checked_abs() {
let chars: Vec<_> = string.chars().collect();
let num_chars = chars.len();
if n as usize > num_chars {
0
} else {
chars
.into_iter()
.take(num_chars - n as usize)
.collect::<String>()
.len()
}
} else {
let abs_start = start.unsigned_abs() as usize;
let chars: Vec<_> = string.chars().collect();
let num_chars = chars.len();
if abs_start > num_chars {
0
} else {
chars
.into_iter()
.take(num_chars - abs_start)
.collect::<String>()
.len()
}
} else if start == 0 {
0
@ -615,20 +612,17 @@ mod string_functions {
}
let start = if start < 0 {
if let Some(n) = start.checked_abs() {
let chars = string.chars().collect::<Vec<_>>();
let num_chars = chars.len();
if n as usize > num_chars {
0
} else {
chars
.into_iter()
.take(num_chars - n as usize)
.collect::<String>()
.len()
}
} else {
let abs_start = start.unsigned_abs() as usize;
let chars = string.chars().collect::<Vec<_>>();
let num_chars = chars.len();
if abs_start > num_chars {
0
} else {
chars
.into_iter()
.take(num_chars - abs_start)
.collect::<String>()
.len()
}
} else if start == 0 {
0
@ -694,15 +688,13 @@ mod string_functions {
.chars()
.nth(index as usize)
.map_or_else(|| Dynamic::UNIT, Into::into)
} else if let Some(abs_index) = index.checked_abs() {
} else {
// Count from end if negative
string
.chars()
.rev()
.nth((abs_index as usize) - 1)
.nth((index.unsigned_abs() as usize) - 1)
.map_or_else(|| Dynamic::UNIT, Into::into)
} else {
Dynamic::UNIT
}
}
/// Set the `index` position in the string to a new `character`.
@ -736,11 +728,12 @@ mod string_functions {
.enumerate()
.map(|(i, ch)| if i == index { character } else { ch })
.collect();
} else if let Some(abs_index) = index.checked_abs() {
} else {
let abs_index = index.unsigned_abs() as usize;
let string_len = string.chars().count();
if abs_index as usize <= string_len {
let index = string_len - (abs_index as usize);
if abs_index <= string_len {
let index = string_len - abs_index;
*string = string
.chars()
.enumerate()
@ -820,15 +813,12 @@ mod string_functions {
let offset = if string.is_empty() || len <= 0 {
return ctx.engine().const_empty_string();
} else if start < 0 {
if let Some(n) = start.checked_abs() {
chars.extend(string.chars());
if n as usize > chars.len() {
0
} else {
chars.len() - n as usize
}
} else {
let abs_start = start.unsigned_abs() as usize;
chars.extend(string.chars());
if abs_start > chars.len() {
0
} else {
chars.len() - abs_start
}
} else if start as usize >= string.chars().count() {
return ctx.engine().const_empty_string();
@ -952,15 +942,12 @@ mod string_functions {
string.make_mut().clear();
return;
} else if start < 0 {
if let Some(n) = start.checked_abs() {
chars.extend(string.chars());
if n as usize > chars.len() {
0
} else {
chars.len() - n as usize
}
} else {
let abs_start = start.unsigned_abs() as usize;
chars.extend(string.chars());
if abs_start > chars.len() {
0
} else {
chars.len() - abs_start
}
} else if start as usize >= string.chars().count() {
string.make_mut().clear();
@ -1256,23 +1243,17 @@ mod string_functions {
#[rhai_fn(name = "split")]
pub fn split_at(ctx: NativeCallContext, string: &mut ImmutableString, index: INT) -> Array {
if index <= 0 {
if let Some(n) = index.checked_abs() {
let num_chars = string.chars().count();
if n as usize > num_chars {
vec![
ctx.engine().const_empty_string().into(),
string.as_str().into(),
]
} else {
let prefix: String = string.chars().take(num_chars - n as usize).collect();
let prefix_len = prefix.len();
vec![prefix.into(), string[prefix_len..].into()]
}
} else {
let abs_index = index.unsigned_abs() as usize;
let num_chars = string.chars().count();
if abs_index > num_chars {
vec![
ctx.engine().const_empty_string().into(),
string.as_str().into(),
]
} else {
let prefix: String = string.chars().take(num_chars - abs_index).collect();
let prefix_len = prefix.len();
vec![prefix.into(), string[prefix_len..].into()]
}
} else {
let prefix: String = string.chars().take(index as usize).collect();

View File

@ -265,10 +265,8 @@ impl ParseSettings {
#[cfg(not(feature = "unchecked"))]
#[inline]
pub fn ensure_level_within_max_limit(&self, limit: usize) -> ParseResult<()> {
if limit > 0 {
if self.level > limit {
return Err(PERR::ExprTooDeep.into_err(self.pos));
}
if limit > 0 && self.level > limit {
return Err(PERR::ExprTooDeep.into_err(self.pos));
}
Ok(())
}
@ -531,11 +529,14 @@ impl Engine {
#[cfg(any(feature = "no_function", feature = "no_module"))]
let is_global = false;
if settings.options.contains(LangOptions::STRICT_VAR) && index.is_none() {
if !is_global && !self.global_sub_modules.contains_key(root) {
return Err(PERR::ModuleUndefined(root.to_string())
.into_err(namespace.position()));
}
if settings.options.contains(LangOptions::STRICT_VAR)
&& index.is_none()
&& !is_global
&& !self.global_sub_modules.contains_key(root)
{
return Err(
PERR::ModuleUndefined(root.to_string()).into_err(namespace.position())
);
}
namespace.set_index(index);
@ -595,11 +596,13 @@ impl Engine {
#[cfg(any(feature = "no_function", feature = "no_module"))]
let is_global = false;
if settings.options.contains(LangOptions::STRICT_VAR) && index.is_none() {
if !is_global && !self.global_sub_modules.contains_key(root) {
return Err(PERR::ModuleUndefined(root.to_string())
.into_err(namespace.position()));
}
if settings.options.contains(LangOptions::STRICT_VAR)
&& index.is_none()
&& !is_global
&& !self.global_sub_modules.contains_key(root)
{
return Err(PERR::ModuleUndefined(root.to_string())
.into_err(namespace.position()));
}
namespace.set_index(index);
@ -1755,11 +1758,14 @@ impl Engine {
#[cfg(any(feature = "no_function", feature = "no_module"))]
let is_global = false;
if settings.options.contains(LangOptions::STRICT_VAR) && index.is_none() {
if !is_global && !self.global_sub_modules.contains_key(root) {
return Err(PERR::ModuleUndefined(root.to_string())
.into_err(namespace.position()));
}
if settings.options.contains(LangOptions::STRICT_VAR)
&& index.is_none()
&& !is_global
&& !self.global_sub_modules.contains_key(root)
{
return Err(
PERR::ModuleUndefined(root.to_string()).into_err(namespace.position())
);
}
namespace.set_index(index);
@ -2519,13 +2525,13 @@ impl Engine {
const KEYWORD_SEMICOLON: &str = Token::SemiColon.literal_syntax();
const KEYWORD_CLOSE_BRACE: &str = Token::RightBrace.literal_syntax();
let self_terminated = match required_token.as_str() {
let self_terminated = matches!(
required_token.as_str(),
// It is self-terminating if the last symbol is a block
CUSTOM_SYNTAX_MARKER_BLOCK => true,
CUSTOM_SYNTAX_MARKER_BLOCK |
// If the last symbol is `;` or `}`, it is self-terminating
KEYWORD_SEMICOLON | KEYWORD_CLOSE_BRACE => true,
_ => false,
};
KEYWORD_SEMICOLON | KEYWORD_CLOSE_BRACE
);
Ok(Expr::Custom(
crate::ast::CustomExpr {
@ -2794,12 +2800,12 @@ impl Engine {
// let name ...
let (name, pos) = parse_var_name(input)?;
if !self.allow_shadowing() && state.stack.iter().any(|(v, ..)| v == &name) {
if !self.allow_shadowing() && state.stack.iter().any(|(v, ..)| v == name) {
return Err(PERR::VariableExists(name.to_string()).into_err(pos));
}
if let Some(ref filter) = self.def_var_filter {
let will_shadow = state.stack.iter().any(|(v, ..)| v == &name);
let will_shadow = state.stack.iter().any(|(v, ..)| v == name);
let level = settings.level;
let is_const = access == AccessMode::ReadOnly;
let info = VarDefInfo {
@ -3192,7 +3198,6 @@ impl Engine {
level: 0,
options,
pos,
..settings
};
let func = self.parse_fn(

View File

@ -455,7 +455,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
let second = iter.next();
if let (Some((key, value)), None) = (first, second) {
visitor.visit_enum(EnumDeserializer {
tag: &key,
tag: key,
content: DynamicDeserializer::from_dynamic(value),
})
} else {

View File

@ -439,7 +439,7 @@ impl Hash for Dynamic {
mem::discriminant(&self.0).hash(state);
match self.0 {
Union::Unit(..) => ().hash(state),
Union::Unit(..) => (),
Union::Bool(ref b, ..) => b.hash(state),
Union::Str(ref s, ..) => s.hash(state),
Union::Char(ref c, ..) => c.hash(state),
@ -1018,17 +1018,11 @@ impl Dynamic {
#[must_use]
pub fn is_read_only(&self) -> bool {
#[cfg(not(feature = "no_closure"))]
match self.0 {
// Shared values do not consider the current access mode
//Union::Shared(.., ReadOnly) => return true,
Union::Shared(ref cell, ..) => {
return match locked_read(cell).access_mode() {
ReadWrite => false,
ReadOnly => true,
}
}
_ => (),
if let Union::Shared(ref cell, ..) = self.0 {
return match locked_read(cell).access_mode() {
ReadWrite => false,
ReadOnly => true,
};
}
match self.access_mode() {
@ -1368,14 +1362,11 @@ impl Dynamic {
#[must_use]
pub fn is_locked(&self) -> bool {
#[cfg(not(feature = "no_closure"))]
match self.0 {
Union::Shared(ref _cell, ..) => {
#[cfg(not(feature = "sync"))]
return _cell.try_borrow().is_err();
#[cfg(feature = "sync")]
return false;
}
_ => (),
if let Union::Shared(ref _cell, ..) = self.0 {
#[cfg(not(feature = "sync"))]
return _cell.try_borrow().is_err();
#[cfg(feature = "sync")]
return false;
}
false
@ -1791,7 +1782,7 @@ impl Dynamic {
#[cfg(feature = "no_closure")]
let typ = v.type_name();
v.try_cast::<T>().ok_or_else(|| typ)
v.try_cast::<T>().ok_or(typ)
})
.collect(),
Union::Blob(..) if TypeId::of::<T>() == TypeId::of::<u8>() => Ok(self.cast::<Vec<T>>()),
@ -1813,7 +1804,7 @@ impl Dynamic {
#[cfg(feature = "no_closure")]
let typ = v.type_name();
v.read_lock::<T>().ok_or_else(|| typ).map(|v| v.clone())
v.read_lock::<T>().ok_or(typ).map(|v| v.clone())
})
.collect()
}

View File

@ -170,14 +170,14 @@ impl<'a> FromIterator<&'a str> for ImmutableString {
}
}
impl<'a> FromIterator<String> for ImmutableString {
impl FromIterator<String> for ImmutableString {
#[inline]
fn from_iter<T: IntoIterator<Item = String>>(iter: T) -> Self {
Self(iter.into_iter().collect::<SmartString>().into())
}
}
impl<'a> FromIterator<SmartString> for ImmutableString {
impl FromIterator<SmartString> for ImmutableString {
#[inline]
fn from_iter<T: IntoIterator<Item = SmartString>>(iter: T) -> Self {
Self(iter.into_iter().collect::<SmartString>().into())

View File

@ -112,7 +112,7 @@ impl Clone for Scope<'_> {
.collect(),
names: self.names.clone(),
aliases: self.aliases.clone(),
dummy: self.dummy.clone(),
dummy: self.dummy,
}
}
}
@ -437,11 +437,9 @@ impl Scope<'_> {
/// ```
#[inline]
pub fn is_constant(&self, name: &str) -> Option<bool> {
self.get_index(name).and_then(|(.., access)| {
Some(match access {
AccessMode::ReadWrite => false,
AccessMode::ReadOnly => true,
})
self.get_index(name).map(|(.., access)| match access {
AccessMode::ReadWrite => false,
AccessMode::ReadOnly => true,
})
}
/// Update the value of the named entry in the [`Scope`] if it already exists and is not constant.