diff --git a/.gitignore b/.gitignore index 2d64e220..de54f385 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,4 @@ benches/results before* after* .rhai-repl-history.txt +clippy.toml diff --git a/CHANGELOG.md b/CHANGELOG.md index 297abdb8..6db362aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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` type for functions metadata is simplified to `Iterator`. * `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 diff --git a/codegen/src/attrs.rs b/codegen/src/attrs.rs index 2258ede3..dfdfc8a9 100644 --- a/codegen/src/attrs.rs +++ b/codegen/src/attrs.rs @@ -149,25 +149,23 @@ pub fn doc_attributes(attrs: &[syn::Attribute]) -> syn::Result> { 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); } } } diff --git a/codegen/src/function.rs b/codegen/src/function.rs index 149f6bfb..078c1c2a 100644 --- a/codegen/src/function.rs +++ b/codegen/src/function.rs @@ -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, diff --git a/codegen/src/module.rs b/codegen/src/module.rs index 30afc75c..bd6a4c1f 100644 --- a/codegen/src/module.rs +++ b/codegen/src/module.rs @@ -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. diff --git a/src/api/custom_syntax.rs b/src/api/custom_syntax.rs index 6c7e2525..1ec9dd28 100644 --- a/src/api/custom_syntax.rs +++ b/src/api/custom_syntax.rs @@ -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() } diff --git a/src/api/definitions/mod.rs b/src/api/definitions/mod.rs index 5363f389..db44936f 100644 --- a/src/api/definitions/mod.rs +++ b/src/api/definitions/mod.rs @@ -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 + '_ { IntoIterator::into_iter([ ( @@ -182,7 +179,6 @@ impl<'e> Definitions<'e> { /// /// Always starts with `module ;`. #[cfg(not(feature = "no_module"))] - #[must_use] pub fn modules(&self) -> impl Iterator + '_ { let mut m = self .engine diff --git a/src/api/options.rs b/src/api/options.rs index 940439aa..960c6424 100644 --- a/src/api/options.rs +++ b/src/api/options.rs @@ -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; } } diff --git a/src/api/type_names.rs b/src/api/type_names.rs index 5717b7cc..8d333d7e 100644 --- a/src/api/type_names.rs +++ b/src/api/type_names.rs @@ -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::(), + "INT" => type_name::(), #[cfg(not(feature = "no_float"))] - "FLOAT" => return type_name::(), + "FLOAT" => type_name::(), _ => map_std_type_name(name, false), }) .into() diff --git a/src/ast/stmt.rs b/src/ast/stmt.rs index ae9b064a..8f1e1f7e 100644 --- a/src/ast/stmt.rs +++ b/src/ast/stmt.rs @@ -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 { self.block.iter() } diff --git a/src/bin/rhai-dbg.rs b/src/bin/rhai-dbg.rs index 93bc6b6d..56ed34c8 100644 --- a/src/bin/rhai-dbg.rs +++ b/src/bin/rhai-dbg.rs @@ -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::>() - .as_slice() - { + Ok(_) => match input.split_whitespace().collect::>().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::().is_ok() => { let num = n.parse::().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"] => { diff --git a/src/bin/rhai-repl.rs b/src/bin/rhai-repl.rs index 4fe171ce..43118f42 100644 --- a/src/bin/rhai-repl.rs +++ b/src/bin/rhai-repl.rs @@ -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; } diff --git a/src/bin/rhai-run.rs b/src/bin/rhai-run.rs index b6e4e6fa..0ccc6006 100644 --- a/src/bin/rhai-run.rs +++ b/src/bin/rhai-run.rs @@ -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); } diff --git a/src/engine.rs b/src/engine.rs index b6817419..2589f309 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -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 diff --git a/src/eval/chaining.rs b/src/eval/chaining.rs index a1e39da3..4e2aa8a8 100644 --- a/src/eval/chaining.rs +++ b/src/eval/chaining.rs @@ -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 { diff --git a/src/eval/debugger.rs b/src/eval/debugger.rs index 4954f923..69e55389 100644 --- a/src/eval/debugger.rs +++ b/src/eval/debugger.rs @@ -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, diff --git a/src/eval/target.rs b/src/eval/target.rs index 10456439..e8d1678a 100644 --- a/src/eval/target.rs +++ b/src/eval/target.rs @@ -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( ) -> Result { 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() } diff --git a/src/func/call.rs b/src/func/call.rs index 6c17d422..44fbea99 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -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) diff --git a/src/func/hashing.rs b/src/func/hashing.rs index 380da5db..32908661 100644 --- a/src/func/hashing.rs +++ b/src/func/hashing.rs @@ -173,10 +173,10 @@ pub fn calc_fn_hash(fn_name: &str, num: usize) -> u64 { pub fn calc_fn_params_hash(params: impl IntoIterator) -> 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() { diff --git a/src/func/native.rs b/src/func/native.rs index c88570ba..b8604786 100644 --- a/src/func/native.rs +++ b/src/func/native.rs @@ -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(value: Shared) -> T { #[inline(always)] #[must_use] #[allow(dead_code)] -pub fn locked_read<'a, T>(value: &'a Locked) -> LockGuard<'a, T> { +pub fn locked_read(value: &Locked) -> LockGuard { #[cfg(not(feature = "sync"))] return value.borrow(); @@ -409,7 +406,7 @@ pub fn locked_read<'a, T>(value: &'a Locked) -> LockGuard<'a, T> { #[inline(always)] #[must_use] #[allow(dead_code)] -pub fn locked_write<'a, T>(value: &'a Locked) -> LockGuardMut<'a, T> { +pub fn locked_write(value: &Locked) -> LockGuardMut { #[cfg(not(feature = "sync"))] return value.borrow_mut(); diff --git a/src/func/register.rs b/src/func/register.rs index 99e460f3..6417a224 100644 --- a/src/func/register.rs +++ b/src/func/register.rs @@ -56,7 +56,7 @@ pub fn by_value(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::(); + mem::take(data).cast::() } /// Trait to register custom Rust functions. diff --git a/src/func/script.rs b/src/func/script.rs index 985070f0..6fd3da58 100644 --- a/src/func/script.rs +++ b/src/func/script.rs @@ -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, ); diff --git a/src/lib.rs b/src/lib.rs index d251ac93..0e589f13 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -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; diff --git a/src/module/mod.rs b/src/module/mod.rs index 01ac556d..d9d6bd4a 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -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< diff --git a/src/module/resolvers/collection.rs b/src/module/resolvers/collection.rs index ca815968..1889cff4 100644 --- a/src/module/resolvers/collection.rs +++ b/src/module/resolvers/collection.rs @@ -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>); 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. diff --git a/src/module/resolvers/file.rs b/src/module/resolvers/file.rs index 52a87a4d..7bb31b62 100644 --- a/src/module/resolvers/file.rs +++ b/src/module/resolvers/file.rs @@ -374,7 +374,7 @@ impl ModuleResolver for FileModuleResolver { pos: Position, ) -> Option> { // 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( diff --git a/src/optimizer.rs b/src/optimizer.rs index f0f7461c..bb82dea8 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -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), diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index bda254e2..a86c6883 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -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) }); diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index 28304579..be024a4b 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -96,16 +96,11 @@ impl Iterator for StepRange { 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) } } diff --git a/src/packages/map_basic.rs b/src/packages/map_basic.rs index 427146b9..85229602 100644 --- a/src/packages/map_basic.rs +++ b/src/packages/map_basic.rs @@ -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 } diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index dd28d34c..08e86419 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -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::() - .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::() + .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::>(); - let num_chars = chars.len(); - if n as usize > num_chars { - 0 - } else { - chars - .into_iter() - .take(num_chars - n as usize) - .collect::() - .len() - } - } else { + let abs_start = start.unsigned_abs() as usize; + let chars = string.chars().collect::>(); + let num_chars = chars.len(); + if abs_start > num_chars { 0 + } else { + chars + .into_iter() + .take(num_chars - abs_start) + .collect::() + .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(); diff --git a/src/parser.rs b/src/parser.rs index af64546f..0231715f 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -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( diff --git a/src/serde/de.rs b/src/serde/de.rs index cf3e638a..178c3bbe 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -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 { diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index 8a6e1fa2..5b87393e 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -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::().ok_or_else(|| typ) + v.try_cast::().ok_or(typ) }) .collect(), Union::Blob(..) if TypeId::of::() == TypeId::of::() => Ok(self.cast::>()), @@ -1813,7 +1804,7 @@ impl Dynamic { #[cfg(feature = "no_closure")] let typ = v.type_name(); - v.read_lock::().ok_or_else(|| typ).map(|v| v.clone()) + v.read_lock::().ok_or(typ).map(|v| v.clone()) }) .collect() } diff --git a/src/types/immutable_string.rs b/src/types/immutable_string.rs index 85cd4127..8efed30b 100644 --- a/src/types/immutable_string.rs +++ b/src/types/immutable_string.rs @@ -170,14 +170,14 @@ impl<'a> FromIterator<&'a str> for ImmutableString { } } -impl<'a> FromIterator for ImmutableString { +impl FromIterator for ImmutableString { #[inline] fn from_iter>(iter: T) -> Self { Self(iter.into_iter().collect::().into()) } } -impl<'a> FromIterator for ImmutableString { +impl FromIterator for ImmutableString { #[inline] fn from_iter>(iter: T) -> Self { Self(iter.into_iter().collect::().into()) diff --git a/src/types/scope.rs b/src/types/scope.rs index 5f92188d..8c3b16ac 100644 --- a/src/types/scope.rs +++ b/src/types/scope.rs @@ -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 { - 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.