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 c81c5682..6db362aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,8 @@ Enhancements * `as_string` is added to BLOB's to convert it into a string by interpreting it as a UTF-8 byte stream. * `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..da376cf2 100644 --- a/codegen/src/attrs.rs +++ b/codegen/src/attrs.rs @@ -120,14 +120,14 @@ pub fn inner_item_attributes( // Find the #[rhai_fn] attribute which will turn be read for function parameters. if let Some(index) = attrs .iter() - .position(|a| a.path.get_ident().map(|i| *i == attr_name).unwrap_or(false)) + .position(|a| a.path.get_ident().map_or(false, |i| *i == attr_name)) { let rhai_fn_attr = attrs.remove(index); // Cannot have more than one #[rhai_fn] if let Some(duplicate) = attrs .iter() - .find(|a| a.path.get_ident().map(|i| *i == attr_name).unwrap_or(false)) + .find(|a| a.path.get_ident().map_or(false, |i| *i == attr_name)) { return Err(syn::Error::new( duplicate.span(), @@ -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); } } } @@ -179,7 +177,7 @@ pub fn doc_attributes(attrs: &[syn::Attribute]) -> syn::Result> { pub fn collect_cfg_attr(attrs: &[syn::Attribute]) -> Vec { attrs .iter() - .filter(|&a| a.path.get_ident().map(|i| *i == "cfg").unwrap_or(false)) + .filter(|&a| a.path.get_ident().map_or(false, |i| *i == "cfg")) .cloned() .collect() } 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..b84a0c26 100644 --- a/src/api/custom_syntax.rs +++ b/src/api/custom_syntax.rs @@ -252,7 +252,7 @@ impl Engine { } // Standard keyword in first position but not disabled _ if segments.is_empty() - && token.as_ref().map_or(false, |v| v.is_standard_keyword()) + && token.as_ref().map_or(false, Token::is_standard_keyword) && (self.disabled_symbols.is_empty() || !self.disabled_symbols.contains(s)) => { return Err(LexError::ImproperSymbol( @@ -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..d7342053 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 @@ -295,20 +291,18 @@ impl FuncInfo { } first = false; - let (param_name, param_type) = self - .metadata - .params_info - .get(i) - .map(|s| { - let mut s = s.splitn(2, ':'); - ( - s.next().unwrap_or("_").split(' ').last().unwrap(), - s.next() - .map(|ty| def_type_name(ty, def.engine)) - .unwrap_or(Cow::Borrowed("?")), - ) - }) - .unwrap_or(("_", "?".into())); + let (param_name, param_type) = + self.metadata + .params_info + .get(i) + .map_or(("_", "?".into()), |s| { + let mut s = s.splitn(2, ':'); + ( + s.next().unwrap_or("_").split(' ').last().unwrap(), + s.next() + .map_or(Cow::Borrowed("?"), |ty| def_type_name(ty, def.engine)), + ) + }); if operator { write!(writer, "{param_type}")?; @@ -342,8 +336,7 @@ fn def_type_name<'a>(ty: &'a str, engine: &'a Engine) -> Cow<'a, str> { let ty = ty .strip_prefix("RhaiResultOf<") .and_then(|s| s.strip_suffix('>')) - .map(str::trim) - .unwrap_or(ty); + .map_or(ty, str::trim); let ty = ty .replace("Iterator String { let mut result = String::from('{'); diff --git a/src/api/options.rs b/src/api/options.rs index 940439aa..4397e066 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; } } @@ -51,17 +51,20 @@ impl Engine { /// Is `if`-expression allowed? /// Default is `true`. #[inline(always)] + #[must_use] pub const fn allow_if_expression(&self) -> bool { self.options.contains(LangOptions::IF_EXPR) } /// Set whether `if`-expression is allowed. #[inline(always)] + #[must_use] pub fn set_allow_if_expression(&mut self, enable: bool) { - self.options.set(LangOptions::IF_EXPR, enable) + self.options.set(LangOptions::IF_EXPR, enable); } /// Is `switch` expression allowed? /// Default is `true`. #[inline(always)] + #[must_use] pub const fn allow_switch_expression(&self) -> bool { self.options.contains(LangOptions::SWITCH_EXPR) } @@ -73,6 +76,7 @@ impl Engine { /// Is statement-expression allowed? /// Default is `true`. #[inline(always)] + #[must_use] pub const fn allow_statement_expression(&self) -> bool { self.options.contains(LangOptions::STMT_EXPR) } @@ -87,6 +91,7 @@ impl Engine { /// Not available under `no_function`. #[cfg(not(feature = "no_function"))] #[inline(always)] + #[must_use] pub const fn allow_anonymous_fn(&self) -> bool { self.options.contains(LangOptions::ANON_FN) } @@ -101,6 +106,7 @@ impl Engine { /// Is looping allowed? /// Default is `true`. #[inline(always)] + #[must_use] pub const fn allow_looping(&self) -> bool { self.options.contains(LangOptions::LOOPING) } @@ -112,6 +118,7 @@ impl Engine { /// Is variables shadowing allowed? /// Default is `true`. #[inline(always)] + #[must_use] pub const fn allow_shadowing(&self) -> bool { self.options.contains(LangOptions::SHADOW) } @@ -123,6 +130,7 @@ impl Engine { /// Is strict variables mode enabled? /// Default is `false`. #[inline(always)] + #[must_use] pub const fn strict_variables(&self) -> bool { self.options.contains(LangOptions::STRICT_VAR) } @@ -137,6 +145,7 @@ impl Engine { /// Not available under `no_object`. #[cfg(not(feature = "no_object"))] #[inline(always)] + #[must_use] pub const fn fail_on_invalid_map_property(&self) -> bool { self.options .contains(LangOptions::FAIL_ON_INVALID_MAP_PROPERTY) diff --git a/src/api/register.rs b/src/api/register.rs index 485cec44..7a782229 100644 --- a/src/api/register.rs +++ b/src/api/register.rs @@ -70,7 +70,7 @@ impl Engine { #[cfg(feature = "metadata")] let param_type_names: crate::StaticVec<_> = - param_type_names.iter().map(|ty| ty.as_str()).collect(); + param_type_names.iter().map(String::as_str).collect(); #[cfg(feature = "metadata")] let param_type_names = Some(param_type_names.as_ref()); @@ -128,7 +128,7 @@ impl Engine { #[cfg(feature = "metadata")] let param_type_names: crate::StaticVec<_> = - param_type_names.iter().map(|ty| ty.as_str()).collect(); + param_type_names.iter().map(String::as_str).collect(); #[cfg(feature = "metadata")] let param_type_names = Some(param_type_names.as_ref()); @@ -989,16 +989,7 @@ impl Engine { let separator = crate::tokenizer::Token::DoubleColon.syntax(); let separator = separator.as_ref(); - if !name.contains(separator) { - if !module.is_indexed() { - // Index the module (making a clone copy if necessary) if it is not indexed - let mut module = crate::func::shared_take_or_clone(module); - module.build_index(); - root.insert(name.into(), module.into()); - } else { - root.insert(name.into(), module); - } - } else { + if name.contains(separator) { let mut iter = name.splitn(2, separator); let sub_module = iter.next().expect("contains separator").trim(); let remainder = iter.next().expect("contains separator").trim(); @@ -1015,6 +1006,13 @@ impl Engine { m.build_index(); root.insert(sub_module.into(), m.into()); } + } else if module.is_indexed() { + root.insert(name.into(), module); + } else { + // Index the module (making a clone copy if necessary) if it is not indexed + let mut module = crate::func::shared_take_or_clone(module); + module.build_index(); + root.insert(name.into(), module.into()); } } @@ -1039,7 +1037,7 @@ impl Engine { #[cfg(not(feature = "no_module"))] for (name, m) in &self.global_sub_modules { - signatures.extend(m.gen_fn_signatures().map(|f| format!("{}::{}", name, f))) + signatures.extend(m.gen_fn_signatures().map(|f| format!("{}::{}", name, f))); } signatures.extend( diff --git a/src/api/run.rs b/src/api/run.rs index 5352e761..babb3295 100644 --- a/src/api/run.rs +++ b/src/api/run.rs @@ -51,7 +51,7 @@ impl Engine { #[cfg(not(feature = "no_function"))] ast.as_ref(), ]; - let lib = if lib.first().map(|m: &&Module| m.is_empty()).unwrap_or(true) { + let lib = if lib.first().map_or(true, |m: &&Module| m.is_empty()) { &lib[0..0] } else { &lib diff --git a/src/api/type_names.rs b/src/api/type_names.rs index 5717b7cc..db63ffbd 100644 --- a/src/api/type_names.rs +++ b/src/api/type_names.rs @@ -144,13 +144,13 @@ 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 { + + return if x == r { name.into() + } else { + format!("&mut {}", r).into() }; } @@ -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/ast.rs b/src/ast/ast.rs index 854ce431..fc9e3257 100644 --- a/src/ast/ast.rs +++ b/src/ast/ast.rs @@ -554,19 +554,19 @@ impl AST { lib }; - let mut _ast = if !other.source.is_empty() { + let mut _ast = if other.source.is_empty() { + Self::new( + merged, + #[cfg(not(feature = "no_function"))] + lib, + ) + } else { Self::new_with_source( merged, #[cfg(not(feature = "no_function"))] lib, other.source.clone(), ) - } else { - Self::new( - merged, - #[cfg(not(feature = "no_function"))] - lib, - ) }; #[cfg(not(feature = "no_module"))] @@ -977,6 +977,7 @@ impl Eq for ASTNode<'_> {} impl ASTNode<'_> { /// Get the [`Position`] of this [`ASTNode`]. + #[must_use] pub fn position(&self) -> Position { match self { ASTNode::Stmt(stmt) => stmt.position(), diff --git a/src/ast/expr.rs b/src/ast/expr.rs index edb66068..4d6a4b69 100644 --- a/src/ast/expr.rs +++ b/src/ast/expr.rs @@ -326,10 +326,10 @@ impl FromStr for FloatWrapper { #[cfg(not(feature = "no_float"))] impl FloatWrapper { /// Maximum floating-point number for natural display before switching to scientific notation. - pub const MAX_NATURAL_FLOAT_FOR_DISPLAY: f32 = 10000000000000.0; + pub const MAX_NATURAL_FLOAT_FOR_DISPLAY: f32 = 10_000_000_000_000.0; /// Minimum floating-point number for natural display before switching to scientific notation. - pub const MIN_NATURAL_FLOAT_FOR_DISPLAY: f32 = 0.0000000000001; + pub const MIN_NATURAL_FLOAT_FOR_DISPLAY: f32 = 0.000_000_000_000_1; /// Create a new [`FloatWrapper`]. #[inline(always)] @@ -728,10 +728,10 @@ impl Expr { match self { #[cfg(not(feature = "no_module"))] Self::Variable(x, ..) => { - if !x.1.is_empty() { - x.1.position() - } else { + if x.1.is_empty() { self.position() + } else { + x.1.position() } } diff --git a/src/ast/ident.rs b/src/ast/ident.rs index 4fb0d3f2..415de2bc 100644 --- a/src/ast/ident.rs +++ b/src/ast/ident.rs @@ -58,6 +58,7 @@ impl Ident { /// Get the name of the identifier as a string slice. #[inline(always)] + #[must_use] pub fn as_str(&self) -> &str { self.name.as_str() } diff --git a/src/ast/namespace.rs b/src/ast/namespace.rs index 9bf328dd..800dba52 100644 --- a/src/ast/namespace.rs +++ b/src/ast/namespace.rs @@ -42,7 +42,7 @@ impl fmt::Debug for Namespace { &self .path .iter() - .map(|m| m.as_str()) + .map(Ident::as_str) .collect::>() .join(Token::DoubleColon.literal_syntax()), ) @@ -59,7 +59,7 @@ impl fmt::Display for Namespace { &self .path .iter() - .map(|m| m.as_str()) + .map(Ident::as_str) .collect::>() .join(Token::DoubleColon.literal_syntax()), ) @@ -126,7 +126,7 @@ impl Namespace { /// Set the [`Scope`][crate::Scope] index offset. #[inline(always)] pub(crate) fn set_index(&mut self, index: Option) { - self.index = index + self.index = index; } /// Get the [position][Position] of this [`Namespace`]. /// diff --git a/src/ast/script_fn.rs b/src/ast/script_fn.rs index e7c44a87..f56a7450 100644 --- a/src/ast/script_fn.rs +++ b/src/ast/script_fn.rs @@ -2,7 +2,7 @@ #![cfg(not(feature = "no_function"))] use super::{FnAccess, StmtBlock}; -use crate::{Identifier, StaticVec}; +use crate::{Identifier, SmartString, StaticVec}; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{fmt, hash::Hash}; @@ -71,7 +71,7 @@ impl fmt::Display for ScriptFnDef { self.name, self.params .iter() - .map(|s| s.as_str()) + .map(SmartString::as_str) .collect::>() .join(", ") ) @@ -120,7 +120,7 @@ impl fmt::Display for ScriptFnMetadata<'_> { self.name, self.params .iter() - .cloned() + .copied() .collect::>() .join(", ") ) @@ -132,7 +132,7 @@ impl<'a> From<&'a ScriptFnDef> for ScriptFnMetadata<'a> { fn from(value: &'a ScriptFnDef) -> Self { Self { name: &value.name, - params: value.params.iter().map(|s| s.as_str()).collect(), + params: value.params.iter().map(SmartString::as_str).collect(), access: value.access, #[cfg(feature = "metadata")] comments: value.comments.iter().map(<_>::as_ref).collect(), diff --git a/src/ast/stmt.rs b/src/ast/stmt.rs index ae9b064a..e853701a 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() } @@ -514,7 +507,7 @@ impl<'a> IntoIterator for &'a StmtBlock { impl Extend for StmtBlock { #[inline(always)] fn extend>(&mut self, iter: T) { - self.block.extend(iter) + self.block.extend(iter); } } @@ -806,7 +799,7 @@ impl Stmt { Self::For(x, ..) => x.2.is_pure() && x.3.iter().all(Stmt::is_pure), Self::Var(..) | Self::Assignment(..) | Self::FnCall(..) => false, - Self::Block(block, ..) => block.iter().all(|stmt| stmt.is_pure()), + Self::Block(block, ..) => block.iter().all(Stmt::is_pure), Self::BreakLoop(..) | Self::Return(..) => false, Self::TryCatch(x, ..) => { x.try_block.iter().all(Stmt::is_pure) && x.catch_block.iter().all(Stmt::is_pure) 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..c9c12eef 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -169,7 +169,7 @@ impl fmt::Debug for Engine { &self .custom_syntax .keys() - .map(|s| s.as_str()) + .map(crate::SmartString::as_str) .collect::(), ); @@ -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..2198dda2 100644 --- a/src/eval/debugger.rs +++ b/src/eval/debugger.rs @@ -147,10 +147,10 @@ impl fmt::Display for BreakPoint { pos, enabled, } => { - if !source.is_empty() { - write!(f, "{} @ {:?}", source, pos)?; - } else { + if source.is_empty() { write!(f, "@ {:?}", pos)?; + } else { + write!(f, "{} @ {:?}", source, pos)?; } if !*enabled { f.write_str(" (disabled)")?; @@ -201,6 +201,7 @@ impl fmt::Display for BreakPoint { impl BreakPoint { /// Is this [`BreakPoint`] enabled? #[inline(always)] + #[must_use] pub fn is_enabled(&self) -> bool { match self { #[cfg(not(feature = "no_position"))] @@ -441,7 +442,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 +464,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 +513,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/eval_context.rs b/src/eval/eval_context.rs index e57b87a2..94cf564a 100644 --- a/src/eval/eval_context.rs +++ b/src/eval/eval_context.rs @@ -113,7 +113,7 @@ impl<'a, 's, 'ps, 'g, 'pg, 'c, 'pc, 't, 'pt> EvalContext<'a, 's, 'ps, 'g, 'pg, ' /// Get an iterator over the namespaces containing definition of all script-defined functions. #[inline] pub fn iter_namespaces(&self) -> impl Iterator { - self.lib.iter().cloned() + self.lib.iter().copied() } /// _(internals)_ The current set of namespaces containing definitions of all script-defined functions. /// Exported under the `internals` feature only. @@ -133,7 +133,7 @@ impl<'a, 's, 'ps, 'g, 'pg, 'c, 'pc, 't, 'pt> EvalContext<'a, 's, 'ps, 'g, 'pg, ' #[inline(always)] #[must_use] pub fn this_ptr_mut(&mut self) -> &mut Option<&'pt mut Dynamic> { - &mut self.this_ptr + self.this_ptr } /// The current nesting level of function calls. #[inline(always)] diff --git a/src/eval/expr.rs b/src/eval/expr.rs index 2980760e..b46367df 100644 --- a/src/eval/expr.rs +++ b/src/eval/expr.rs @@ -149,7 +149,7 @@ impl Engine { } _ if global.always_search_scope => (0, expr.start_position()), Expr::Variable(.., Some(i), pos) => (i.get() as usize, *pos), - Expr::Variable(v, None, pos) => (v.0.map(NonZeroUsize::get).unwrap_or(0), *pos), + Expr::Variable(v, None, pos) => (v.0.map_or(0, NonZeroUsize::get), *pos), _ => unreachable!("Expr::Variable expected but gets {:?}", expr), }; @@ -485,7 +485,7 @@ impl Engine { let custom_def = self.custom_syntax.get(key_token).ok_or_else(|| { Box::new(ERR::ErrorCustomSyntax( format!("Invalid custom syntax prefix: {}", key_token), - custom.tokens.iter().map(|s| s.to_string()).collect(), + custom.tokens.iter().map(<_>::to_string).collect(), *pos, )) })?; diff --git a/src/eval/global_state.rs b/src/eval/global_state.rs index 35b15416..225f724c 100644 --- a/src/eval/global_state.rs +++ b/src/eval/global_state.rs @@ -284,26 +284,26 @@ impl GlobalRuntimeState<'_> { #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[must_use] pub(crate) fn hash_idx_get(&mut self) -> u64 { - if self.fn_hash_indexing != (0, 0) { - self.fn_hash_indexing.0 - } else { + if self.fn_hash_indexing == (0, 0) { let n1 = crate::calc_fn_hash(crate::engine::FN_IDX_GET, 2); let n2 = crate::calc_fn_hash(crate::engine::FN_IDX_SET, 3); self.fn_hash_indexing = (n1, n2); n1 + } else { + self.fn_hash_indexing.0 } } /// Get the pre-calculated index setter hash. #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] #[must_use] pub(crate) fn hash_idx_set(&mut self) -> u64 { - if self.fn_hash_indexing != (0, 0) { - self.fn_hash_indexing.1 - } else { + if self.fn_hash_indexing == (0, 0) { let n1 = crate::calc_fn_hash(crate::engine::FN_IDX_GET, 2); let n2 = crate::calc_fn_hash(crate::engine::FN_IDX_SET, 3); self.fn_hash_indexing = (n1, n2); n2 + } else { + self.fn_hash_indexing.1 } } } diff --git a/src/eval/stmt.rs b/src/eval/stmt.rs index 86a06e04..9154a92e 100644 --- a/src/eval/stmt.rs +++ b/src/eval/stmt.rs @@ -368,21 +368,21 @@ impl Engine { match guard_val { Ok(true) => { - if !if_block.is_empty() { + if if_block.is_empty() { + Ok(Dynamic::UNIT) + } else { self.eval_stmt_block( scope, global, caches, lib, this_ptr, if_block, true, level, ) - } else { - Ok(Dynamic::UNIT) } } Ok(false) => { - if !else_block.is_empty() { + if else_block.is_empty() { + Ok(Dynamic::UNIT) + } else { self.eval_stmt_block( scope, global, caches, lib, this_ptr, else_block, true, level, ) - } else { - Ok(Dynamic::UNIT) } } err => err.map(Into::into), @@ -510,7 +510,10 @@ impl Engine { Stmt::While(x, ..) if matches!(x.0, Expr::Unit(..)) => loop { let (.., body) = &**x; - if !body.is_empty() { + if body.is_empty() { + #[cfg(not(feature = "unchecked"))] + self.inc_operations(&mut global.num_operations, body.position())?; + } else { match self .eval_stmt_block(scope, global, caches, lib, this_ptr, body, true, level) { @@ -521,9 +524,6 @@ impl Engine { _ => break Err(err), }, } - } else { - #[cfg(not(feature = "unchecked"))] - self.inc_operations(&mut global.num_operations, body.position())?; } }, @@ -624,11 +624,11 @@ impl Engine { if let Some(func) = func { // Add the loop variables let orig_scope_len = scope.len(); - let counter_index = if !counter.is_empty() { + let counter_index = if counter.is_empty() { + usize::MAX + } else { scope.push(counter.name.clone(), 0 as INT); scope.len() - 1 - } else { - usize::MAX }; scope.push(var_name.name.clone(), ()); @@ -979,13 +979,13 @@ impl Engine { if let Ok(module) = module_result { if !export.is_empty() { - if !module.is_indexed() { + if module.is_indexed() { + global.push_import(export.name.clone(), module); + } else { // Index the module (making a clone copy if necessary) if it is not indexed let mut m = crate::func::shared_take_or_clone(module); m.build_index(); global.push_import(export.name.clone(), m); - } else { - global.push_import(export.name.clone(), module); } } 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/builtin.rs b/src/func/builtin.rs index 3e728764..2214cfda 100644 --- a/src/func/builtin.rs +++ b/src/func/builtin.rs @@ -287,7 +287,7 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option Some(|_, args| { let blob = &*args[0].read_lock::().expect(BUILTIN); - let x = (args[1].as_int().expect("`INT`") & 0x000000ff) as u8; + let x = (args[1].as_int().expect("`INT`") & 0x0000_00ff) as u8; Ok((!blob.is_empty() && blob.contains(&x)).into()) }), _ => None, @@ -517,16 +517,14 @@ pub fn get_builtin_binary_op_fn(op: &str, x: &Dynamic, y: &Dynamic) -> Option().expect(BUILTIN); let blob2 = &*args[1].read_lock::().expect(BUILTIN); - Ok(Dynamic::from_blob(if !blob2.is_empty() { - if blob1.is_empty() { - blob2.clone() - } else { - let mut blob = blob1.clone(); - blob.extend(blob2); - blob - } - } else { + Ok(Dynamic::from_blob(if blob2.is_empty() { blob1.clone() + } else if blob1.is_empty() { + blob2.clone() + } else { + let mut blob = blob1.clone(); + blob.extend(blob2); + blob })) }), "==" => Some(impl_op!(Blob == Blob)), diff --git a/src/func/call.rs b/src/func/call.rs index 6c17d422..fd1545b8 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -140,10 +140,10 @@ impl Engine { #[cfg(not(feature = "no_module"))] let (ns, sep) = ( namespace.to_string(), - if !namespace.is_empty() { - crate::tokenizer::Token::DoubleColon.literal_syntax() - } else { + if namespace.is_empty() { "" + } else { + crate::tokenizer::Token::DoubleColon.literal_syntax() }, ); #[cfg(feature = "no_module")] @@ -169,7 +169,7 @@ impl Engine { /// /// Search order: /// 1) AST - script functions in the AST - /// 2) Global namespace - functions registered via Engine::register_XXX + /// 2) Global namespace - functions registered via `Engine::register_XXX` /// 3) Global registered modules - packages /// 4) Imported modules - functions marked with global namespace /// 5) Static registered modules @@ -280,16 +280,7 @@ impl Engine { } return args.and_then(|args| { - if !is_op_assignment { - get_builtin_binary_op_fn(fn_name, args[0], args[1]).map(|f| { - FnResolutionCacheEntry { - func: CallableFunction::from_method( - Box::new(f) as Box - ), - source: None, - } - }) - } else { + if is_op_assignment { let (first_arg, rest_args) = args.split_first().unwrap(); get_builtin_op_assignment_fn(fn_name, *first_arg, rest_args[0]).map( @@ -300,6 +291,15 @@ impl Engine { source: None, }, ) + } else { + get_builtin_binary_op_fn(fn_name, args[0], args[1]).map(|f| { + FnResolutionCacheEntry { + func: CallableFunction::from_method( + Box::new(f) as Box + ), + source: None, + } + }) } }); } @@ -312,11 +312,11 @@ impl Engine { .enumerate() .map(|(i, a)| { let mask = 1usize << (num_args - i - 1); - if bitmask & mask != 0 { + if bitmask & mask == 0 { + a.type_id() + } else { // Replace with `Dynamic` TypeId::of::() - } else { - a.type_id() } }), ); @@ -371,7 +371,7 @@ impl Engine { ); if func.is_some() { - let is_method = func.map(|f| f.func.is_method()).unwrap_or(false); + let is_method = func.map_or(false, |f| f.func.is_method()); // Push a new call stack frame #[cfg(feature = "debugging")] @@ -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)?; } @@ -680,8 +680,7 @@ impl Engine { &mut global.source, source .as_ref() - .map(|s| (**s).clone()) - .unwrap_or(crate::Identifier::new_const()), + .map_or(crate::Identifier::new_const(), |s| (**s).clone()), ); let result = if _is_method_call { @@ -841,14 +840,12 @@ impl Engine { ) } KEYWORD_FN_PTR_CALL => { - if !call_args.is_empty() { - if !call_args[0].is::() { - let typ = self.map_type_name(call_args[0].type_name()); - return Err(self.make_type_mismatch_err::(typ, first_arg_pos)); - } - } else { + if call_args.is_empty() { let typ = self.map_type_name(target.type_name()); return Err(self.make_type_mismatch_err::(typ, fn_call_pos)); + } else if !call_args[0].is::() { + let typ = self.map_type_name(call_args[0].type_name()); + return Err(self.make_type_mismatch_err::(typ, first_arg_pos)); } // FnPtr call on object @@ -1036,10 +1033,10 @@ impl Engine { // Recalculate hash let args_len = total_args + curry.len(); - hashes = if !hashes.is_native_only() { - calc_fn_hash(name, args_len).into() - } else { + hashes = if hashes.is_native_only() { FnCallHashes::from_native(calc_fn_hash(name, args_len)) + } else { + calc_fn_hash(name, args_len).into() }; } // Handle Fn() @@ -1180,7 +1177,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) @@ -1236,7 +1233,7 @@ impl Engine { if target_is_shared || target.is_temp_value() { arg_values.insert(0, target.take_or_clone().flatten()); - args.extend(arg_values.iter_mut()) + args.extend(arg_values.iter_mut()); } else { // Turn it into a method call only if the object is not shared and not a simple value is_ref_mut = true; @@ -1370,11 +1367,11 @@ impl Engine { while bitmask < max_bitmask { let hash_params = calc_fn_params_hash(args.iter().enumerate().map(|(i, a)| { let mask = 1usize << (num_args - i - 1); - if bitmask & mask != 0 { + if bitmask & mask == 0 { + a.type_id() + } else { // Replace with `Dynamic` TypeId::of::() - } else { - a.type_id() } })); let hash_qualified_fn = combine_hashes(hash, hash_params); @@ -1392,7 +1389,7 @@ impl Engine { } // Clone first argument if the function is not a method after-all - if !func.map(|f| f.is_method()).unwrap_or(true) { + if !func.map_or(true, CallableFunction::is_method) { if let Some(first) = first_arg_value { *first = args[0].clone(); args[0] = first; diff --git a/src/func/hashing.rs b/src/func/hashing.rs index 380da5db..108b1035 100644 --- a/src/func/hashing.rs +++ b/src/func/hashing.rs @@ -47,7 +47,7 @@ impl Hasher for StraightHasher { self.0 = u64::from_ne_bytes(key); if self.0 == 0 { - self.0 = ALT_ZERO_HASH + self.0 = ALT_ZERO_HASH; } } } @@ -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..a69ca830 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. @@ -255,7 +252,7 @@ impl<'a> NativeCallContext<'a> { /// in reverse order. #[inline] pub fn iter_namespaces(&self) -> impl Iterator { - self.lib.iter().rev().cloned() + self.lib.iter().rev().copied() } /// _(internals)_ The current set of namespaces containing definitions of all script-defined functions. /// Exported under the `internals` feature only. @@ -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..41944cf6 100644 --- a/src/func/register.rs +++ b/src/func/register.rs @@ -28,7 +28,7 @@ use std::{any::TypeId, mem}; pub struct Mut(T); //pub struct Ref(T); -/// Dereference into DynamicWriteLock +/// Dereference into [`DynamicWriteLock`] #[inline(always)] #[must_use] pub fn by_ref(data: &mut Dynamic) -> DynamicWriteLock { @@ -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..5202e61a 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, ); @@ -132,7 +128,7 @@ impl Engine { } else { caches.push_fn_resolution_cache(); lib_merged.push(&**fn_lib); - lib_merged.extend(lib.iter().cloned()); + lib_merged.extend(lib.iter().copied()); &lib_merged }, Some(mem::replace(&mut global.constants, constants.clone())), @@ -209,7 +205,7 @@ impl Engine { scope.rewind(orig_scope_len); } else if !args.is_empty() { // Remove arguments only, leaving new variables in the scope - scope.remove_range(orig_scope_len, args.len()) + scope.remove_range(orig_scope_len, args.len()); } #[cfg(not(feature = "no_module"))] global.truncate_imports(orig_imports_len); @@ -237,7 +233,7 @@ impl Engine { ) -> bool { let cache = caches.fn_resolution_cache_mut(); - if let Some(result) = cache.get(&hash_script).map(|v| v.is_some()) { + if let Some(result) = cache.get(&hash_script).map(Option::is_some) { return result; } 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..76e5428d 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -8,7 +8,7 @@ use crate::func::{ use crate::types::{dynamic::Variant, CustomTypesCollection}; use crate::{ calc_fn_hash, calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes, Dynamic, Identifier, - ImmutableString, NativeCallContext, RhaiResultOf, Shared, StaticVec, + ImmutableString, NativeCallContext, RhaiResultOf, Shared, SmartString, StaticVec, }; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -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() @@ -182,7 +181,15 @@ impl FuncInfo { let return_type = Self::format_type(&self.metadata.return_type, true); - if !self.metadata.params_info.is_empty() { + if self.metadata.params_info.is_empty() { + for x in 0..self.metadata.params { + sig.push('_'); + if x < self.metadata.params - 1 { + sig.push_str(", "); + } + } + sig.push(')'); + } else { let params: StaticVec<_> = self .metadata .params_info @@ -204,14 +211,6 @@ impl FuncInfo { .collect(); sig.push_str(¶ms.join(", ")); sig.push(')'); - } else { - for x in 0..self.metadata.params { - sig.push('_'); - if x < self.metadata.params - 1 { - sig.push_str(", "); - } - } - sig.push(')'); } if !self.func.is_script() && !return_type.is_empty() { @@ -239,7 +238,7 @@ pub fn calc_native_fn_hash<'a>( params: &[TypeId], ) -> u64 { let hash_script = calc_qualified_fn_hash(modules, fn_name, params.len()); - let hash_params = calc_fn_params_hash(params.iter().cloned()); + let hash_params = calc_fn_params_hash(params.iter().copied()); combine_hashes(hash_script, hash_params) } @@ -299,7 +298,7 @@ impl fmt::Debug for Module { &self .modules .keys() - .map(|m| m.as_str()) + .map(SmartString::as_str) .collect::>(), ) .field("vars", &self.variables) @@ -585,6 +584,7 @@ impl Module { /// assert_eq!(module.get_custom_type(name), Some("MyType")); /// ``` #[inline(always)] + #[must_use] pub fn get_custom_type(&self, key: &str) -> Option<&str> { self.custom_types.get(key) } @@ -648,7 +648,7 @@ impl Module { FnAccess::Public => true, FnAccess::Private => false, }) - .map(|f| f.gen_signature()) + .map(FuncInfo::gen_signature) } /// Does a variable exist in the [`Module`]? @@ -664,10 +664,10 @@ impl Module { #[inline(always)] #[must_use] pub fn contains_var(&self, name: &str) -> bool { - if !self.variables.is_empty() { - self.variables.contains_key(name) - } else { + if self.variables.is_empty() { false + } else { + self.variables.contains_key(name) } } @@ -700,10 +700,10 @@ impl Module { #[inline(always)] #[must_use] pub fn get_var(&self, name: &str) -> Option { - if !self.variables.is_empty() { - self.variables.get(name).cloned() - } else { + if self.variables.is_empty() { None + } else { + self.variables.get(name).cloned() } } @@ -740,10 +740,10 @@ impl Module { #[cfg(not(feature = "no_module"))] #[inline] pub(crate) fn get_qualified_var(&self, hash_var: u64) -> Option { - if !self.all_variables.is_empty() { - self.all_variables.get(&hash_var).cloned() - } else { + if self.all_variables.is_empty() { None + } else { + self.all_variables.get(&hash_var).cloned() } } @@ -795,14 +795,14 @@ impl Module { name: impl AsRef, num_params: usize, ) -> Option<&Shared> { - if !self.functions.is_empty() { + if self.functions.is_empty() { + None + } else { let name = name.as_ref(); self.iter_fn() .find(|f| f.metadata.params == num_params && f.metadata.name == name) .and_then(|f| f.func.get_script_fn_def()) - } else { - None } } @@ -841,10 +841,10 @@ impl Module { #[inline(always)] #[must_use] pub fn contains_sub_module(&self, name: &str) -> bool { - if !self.modules.is_empty() { - self.modules.contains_key(name) - } else { + if self.modules.is_empty() { false + } else { + self.modules.contains_key(name) } } @@ -862,10 +862,10 @@ impl Module { #[inline] #[must_use] pub fn get_sub_module(&self, name: &str) -> Option<&Module> { - if !self.modules.is_empty() { - self.modules.get(name).map(|m| &**m) - } else { + if self.modules.is_empty() { None + } else { + self.modules.get(name).map(|m| &**m) } } @@ -909,10 +909,10 @@ impl Module { #[inline(always)] #[must_use] pub fn contains_fn(&self, hash_fn: u64) -> bool { - if !self.functions.is_empty() { - self.functions.contains_key(&hash_fn) - } else { + if self.functions.is_empty() { false + } else { + self.functions.contains_key(&hash_fn) } } @@ -1062,7 +1062,7 @@ impl Module { let mut param_types: StaticVec<_> = arg_types .as_ref() .iter() - .cloned() + .copied() .enumerate() .map(|(i, type_id)| Self::map_type(!is_method || i > 0, type_id)) .collect(); @@ -1328,8 +1328,10 @@ impl Module { where A: Variant + Clone, T: Variant + Clone, - F: RegisterNativeFunction>, - F: Fn(&mut A) -> RhaiResultOf + SendSync + 'static, + F: RegisterNativeFunction> + + Fn(&mut A) -> RhaiResultOf + + SendSync + + 'static, { self.set_fn( crate::engine::make_getter(name.as_ref()).as_str(), @@ -1370,8 +1372,10 @@ impl Module { where A: Variant + Clone, B: Variant + Clone, - F: RegisterNativeFunction>, - F: Fn(&mut A, B) -> RhaiResultOf<()> + SendSync + 'static, + F: RegisterNativeFunction> + + Fn(&mut A, B) -> RhaiResultOf<()> + + SendSync + + 'static, { self.set_fn( crate::engine::make_setter(name.as_ref()).as_str(), @@ -1417,8 +1421,10 @@ impl Module { A: Variant + Clone, B: Variant + Clone, T: Variant + Clone, - F: RegisterNativeFunction>, - F: Fn(&mut A, B) -> RhaiResultOf + SendSync + 'static, + F: RegisterNativeFunction> + + Fn(&mut A, B) -> RhaiResultOf + + SendSync + + 'static, { #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { @@ -1479,8 +1485,10 @@ impl Module { A: Variant + Clone, B: Variant + Clone, C: Variant + Clone, - F: RegisterNativeFunction>, - F: Fn(&mut A, B, C) -> RhaiResultOf<()> + SendSync + 'static, + F: RegisterNativeFunction> + + Fn(&mut A, B, C) -> RhaiResultOf<()> + + SendSync + + 'static, { #[cfg(not(feature = "no_index"))] if TypeId::of::() == TypeId::of::() { @@ -1564,10 +1572,10 @@ impl Module { #[inline] #[must_use] pub(crate) fn get_fn(&self, hash_native: u64) -> Option<&CallableFunction> { - if !self.functions.is_empty() { - self.functions.get(&hash_native).map(|f| &f.func) - } else { + if self.functions.is_empty() { None + } else { + self.functions.get(&hash_native).map(|f| &f.func) } } @@ -1575,10 +1583,10 @@ impl Module { #[inline(always)] #[must_use] pub(crate) fn contains_dynamic_fn(&self, hash_script: u64) -> bool { - if !self.dynamic_functions.is_empty() { - self.dynamic_functions.contains(&hash_script) - } else { + if self.dynamic_functions.is_empty() { false + } else { + self.dynamic_functions.contains(&hash_script) } } @@ -1588,10 +1596,10 @@ impl Module { #[inline(always)] #[must_use] pub fn contains_qualified_fn(&self, hash_fn: u64) -> bool { - if !self.all_functions.is_empty() { - self.all_functions.contains_key(&hash_fn) - } else { + if self.all_functions.is_empty() { false + } else { + self.all_functions.contains_key(&hash_fn) } } @@ -1602,10 +1610,10 @@ impl Module { #[inline] #[must_use] pub(crate) fn get_qualified_fn(&self, hash_qualified_fn: u64) -> Option<&CallableFunction> { - if !self.all_functions.is_empty() { - self.all_functions.get(&hash_qualified_fn) - } else { + if self.all_functions.is_empty() { None + } else { + self.all_functions.get(&hash_qualified_fn) } } @@ -1684,7 +1692,7 @@ impl Module { self.functions.entry(k).or_insert_with(|| v.clone()); } self.dynamic_functions - .extend(other.dynamic_functions.iter().cloned()); + .extend(other.dynamic_functions.iter().copied()); for (&k, v) in &other.type_iterators { self.type_iterators.entry(k).or_insert_with(|| v.clone()); } @@ -1746,7 +1754,7 @@ impl Module { ); // This may introduce entries that are superfluous because the function has been filtered away. self.dynamic_functions - .extend(other.dynamic_functions.iter().cloned()); + .extend(other.dynamic_functions.iter().copied()); self.type_iterators .extend(other.type_iterators.iter().map(|(&k, v)| (k, v.clone()))); @@ -1896,7 +1904,6 @@ impl Module { #[cfg(not(feature = "no_function"))] #[cfg(feature = "internals")] #[inline(always)] - #[must_use] pub fn iter_script_fn_info( &self, ) -> impl Iterator< @@ -2147,14 +2154,14 @@ impl Module { if !f.func.is_script() { let hash_qualified_fn = calc_native_fn_hash( - path.iter().cloned(), + path.iter().copied(), f.metadata.name.as_str(), &f.param_types, ); functions.insert(hash_qualified_fn, f.func.clone()); } else if cfg!(not(feature = "no_function")) { let hash_qualified_script = crate::calc_qualified_fn_hash( - path.iter().cloned(), + path.iter().copied(), f.metadata.name.as_str(), f.metadata.params, ); @@ -2194,10 +2201,10 @@ impl Module { #[inline(always)] #[must_use] pub fn contains_qualified_iter(&self, id: TypeId) -> bool { - if !self.all_type_iterators.is_empty() { - self.all_type_iterators.contains_key(&id) - } else { + if self.all_type_iterators.is_empty() { false + } else { + self.all_type_iterators.contains_key(&id) } } @@ -2205,10 +2212,10 @@ impl Module { #[inline(always)] #[must_use] pub fn contains_iter(&self, id: TypeId) -> bool { - if !self.type_iterators.is_empty() { - self.type_iterators.contains_key(&id) - } else { + if self.type_iterators.is_empty() { false + } else { + self.type_iterators.contains_key(&id) } } @@ -2275,10 +2282,10 @@ impl Module { #[inline] #[must_use] pub(crate) fn get_qualified_iter(&self, id: TypeId) -> Option<&IteratorFn> { - if !self.all_type_iterators.is_empty() { - self.all_type_iterators.get(&id).map(|f| &**f) - } else { + if self.all_type_iterators.is_empty() { None + } else { + self.all_type_iterators.get(&id).map(|f| &**f) } } @@ -2286,10 +2293,10 @@ impl Module { #[inline] #[must_use] pub(crate) fn get_iter(&self, id: TypeId) -> Option<&IteratorFn> { - if !self.type_iterators.is_empty() { - self.type_iterators.get(&id).map(|f| &**f) - } else { + if self.type_iterators.is_empty() { None + } else { + self.type_iterators.get(&id).map(|f| &**f) } } } diff --git a/src/module/resolvers/collection.rs b/src/module/resolvers/collection.rs index ca815968..aa39329f 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 { diff --git a/src/module/resolvers/dummy.rs b/src/module/resolvers/dummy.rs index f36148bc..f5782ebc 100644 --- a/src/module/resolvers/dummy.rs +++ b/src/module/resolvers/dummy.rs @@ -31,6 +31,7 @@ impl DummyModuleResolver { /// engine.set_module_resolver(resolver); /// ``` #[inline(always)] + #[must_use] pub const fn new() -> Self { Self } diff --git a/src/module/resolvers/file.rs b/src/module/resolvers/file.rs index 52a87a4d..69731944 100644 --- a/src/module/resolvers/file.rs +++ b/src/module/resolvers/file.rs @@ -244,10 +244,10 @@ impl FileModuleResolver { let cache = locked_read(&self.cache); - if !cache.is_empty() { - cache.contains_key(path.as_ref()) - } else { + if cache.is_empty() { false + } else { + cache.contains_key(path.as_ref()) } } /// Empty the internal cache. @@ -277,7 +277,7 @@ impl FileModuleResolver { file_path = self .base_path .clone() - .or_else(|| source_path.map(|p| p.into())) + .or_else(|| source_path.map(Into::into)) .unwrap_or_default(); file_path.push(path); } else { @@ -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/module/resolvers/stat.rs b/src/module/resolvers/stat.rs index 60a89950..3f556db2 100644 --- a/src/module/resolvers/stat.rs +++ b/src/module/resolvers/stat.rs @@ -66,10 +66,10 @@ impl StaticModuleResolver { #[inline(always)] #[must_use] pub fn contains_path(&self, path: &str) -> bool { - if !self.0.is_empty() { - self.0.contains_key(path) - } else { + if self.0.is_empty() { false + } else { + self.0.contains_key(path) } } /// Get an iterator of all the [modules][Module]. @@ -85,7 +85,7 @@ impl StaticModuleResolver { /// Get an iterator of all the [module][Module] paths. #[inline] pub fn paths(&self) -> impl Iterator { - self.0.keys().map(|s| s.as_str()) + self.0.keys().map(SmartString::as_str) } /// Get an iterator of all the [modules][Module]. #[inline(always)] @@ -100,6 +100,7 @@ impl StaticModuleResolver { } /// Is this [`StaticModuleResolver`] empty? #[inline(always)] + #[must_use] pub fn is_empty(&self) -> bool { self.0.is_empty() } diff --git a/src/optimizer.rs b/src/optimizer.rs index f0f7461c..590e760d 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -103,7 +103,7 @@ impl<'a> OptimizerState<'a> { /// Prune the list of constants back to a specified size. #[inline(always)] pub fn restore_var(&mut self, len: usize) { - self.variables.truncate(len) + self.variables.truncate(len); } /// Add a new variable to the list. #[inline(always)] @@ -113,7 +113,7 @@ impl<'a> OptimizerState<'a> { access: AccessMode, value: Option, ) { - self.variables.push((name.into(), access, value)) + self.variables.push((name.into(), access, value)); } /// Look up a constant from the list. #[inline] @@ -169,7 +169,7 @@ fn has_native_fn_override( hash_script: u64, arg_types: impl AsRef<[TypeId]>, ) -> bool { - let hash_params = calc_fn_params_hash(arg_types.as_ref().iter().cloned()); + let hash_params = calc_fn_params_hash(arg_types.as_ref().iter().copied()); let hash = combine_hashes(hash_script, hash_params); // First check the global namespace and packages, but skip modules that are standard because @@ -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; } @@ -438,7 +433,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b if !x.0.is_op_assignment() && x.1.lhs.is_variable_access(true) && matches!(&x.1.rhs, Expr::FnCall(x2, ..) - if Token::lookup_from_syntax(&x2.name).map(|t| t.has_op_assignment()).unwrap_or(false) + if Token::lookup_from_syntax(&x2.name).map_or(false, |t| t.has_op_assignment()) && x2.args.len() == 2 && x2.args[0].get_variable_name(true) == x.1.lhs.get_variable_name(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(); } } @@ -728,12 +721,11 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b } } // Remove if no entry left - match list.is_empty() { - true => { - state.set_dirty(); - false - } - false => true, + if list.is_empty() { + state.set_dirty(); + false + } else { + true } }); @@ -773,7 +765,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b Stmt::While(x, ..) if matches!(x.0, Expr::BoolConstant(false, ..)) => match x.0 { Expr::BoolConstant(false, pos) => { state.set_dirty(); - *stmt = Stmt::Noop(pos) + *stmt = Stmt::Noop(pos); } _ => unreachable!("`Expr::BoolConstant"), }, @@ -792,14 +784,14 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b Stmt::BreakLoop(options, pos) if options.contains(ASTFlags::BREAK) => { // Only a single break statement - turn into running the guard expression once state.set_dirty(); - if !condition.is_unit() { + if condition.is_unit() { + *stmt = Stmt::Noop(pos); + } else { let mut statements = vec![Stmt::Expr(mem::take(condition).into())]; if preserve_result { - statements.push(Stmt::Noop(pos)) + statements.push(Stmt::Noop(pos)); } *stmt = (statements, Span::new(pos, Position::NONE)).into(); - } else { - *stmt = Stmt::Noop(pos); }; } _ => (), @@ -842,7 +834,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b } // let id = expr; Stmt::Var(x, options, ..) if !options.contains(ASTFlags::CONSTANT) => { - optimize_expr(&mut x.1, state, false) + optimize_expr(&mut x.1, state, false); } // import expr as var; #[cfg(not(feature = "no_module"))] @@ -958,10 +950,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"))] @@ -979,8 +968,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) { // All other items can be thrown away. state.set_dirty(); *expr = mem::take(&mut m.0).into_iter().find(|(x, ..)| x.as_str() == prop) - .map(|(.., mut expr)| { expr.set_position(*pos); expr }) - .unwrap_or_else(|| Expr::Unit(*pos)); + .map_or_else(|| Expr::Unit(*pos), |(.., mut expr)| { expr.set_position(*pos); expr }); } // var.rhs (Expr::Variable(..), rhs) => optimize_expr(rhs, state, true), @@ -1010,11 +998,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; @@ -1025,8 +1013,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) { // All other items can be thrown away. state.set_dirty(); *expr = mem::take(&mut m.0).into_iter().find(|(x, ..)| x.as_str() == s.as_str()) - .map(|(.., mut expr)| { expr.set_position(*pos); expr }) - .unwrap_or_else(|| Expr::Unit(*pos)); + .map_or_else(|| Expr::Unit(*pos), |(.., mut expr)| { expr.set_position(*pos); expr }); } // int[int] (Expr::IntegerConstant(n, pos), Expr::IntegerConstant(i, ..)) if *i >= 0 && (*i as usize) < crate::INT_BITS => { @@ -1035,10 +1022,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 +1034,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), @@ -1158,7 +1145,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) { _ => Dynamic::UNIT }; - if let Ok(fn_ptr) = fn_name.into_immutable_string().map_err(|err| err.into()).and_then(FnPtr::try_from) { + if let Ok(fn_ptr) = fn_name.into_immutable_string().map_err(Into::into).and_then(FnPtr::try_from) { state.set_dirty(); *expr = Expr::DynamicConstant(Box::new(fn_ptr.into()), *pos); } else { @@ -1348,10 +1335,10 @@ fn optimize_top_level( // Add constants and variables from the scope for (name, constant, value) in scope.iter() { - if !constant { - state.push_var(name, AccessMode::ReadWrite, None); - } else { + if constant { state.push_var(name, AccessMode::ReadOnly, Some(value)); + } else { + state.push_var(name, AccessMode::ReadWrite, None); } } diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index bda254e2..d0a0b671 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -145,16 +145,14 @@ pub mod array_functions { /// ``` #[rhai_fn(name = "+")] pub fn concat(array1: Array, array2: Array) -> Array { - if !array2.is_empty() { - if array1.is_empty() { - array2 - } else { - let mut array = array1; - array.extend(array2); - array - } - } else { + if array2.is_empty() { array1 + } else if array1.is_empty() { + array2 + } else { + let mut array = array1; + array.extend(array2); + array } } /// Add a new element into the array at a particular `index` position. @@ -290,7 +288,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. @@ -432,7 +430,7 @@ pub mod array_functions { pub fn splice_range(array: &mut Array, range: ExclusiveRange, replace: Array) { let start = INT::max(range.start, 0); let end = INT::max(range.end, start); - splice(array, start, end - start, replace) + splice(array, start, end - start, replace); } /// Replace an inclusive range of the array with another array. /// @@ -450,7 +448,7 @@ pub mod array_functions { pub fn splice_inclusive_range(array: &mut Array, range: InclusiveRange, replace: Array) { let start = INT::max(*range.start(), 0); let end = INT::max(*range.end(), start); - splice(array, start, end - start + 1, replace) + splice(array, start, end - start + 1, replace); } /// Replace a portion of the array with another array. /// @@ -1344,7 +1342,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) }); @@ -1739,13 +1737,15 @@ pub mod array_functions { .call_raw(&ctx, None, [x.clone(), y.clone()]) .ok() .and_then(|v| v.as_int().ok()) - .map(|v| match v { - v if v > 0 => Ordering::Greater, - v if v < 0 => Ordering::Less, - 0 => Ordering::Equal, - _ => unreachable!("v is {}", v), - }) - .unwrap_or_else(|| x.type_id().cmp(&y.type_id())) + .map_or_else( + || x.type_id().cmp(&y.type_id()), + |v| match v { + v if v > 0 => Ordering::Greater, + v if v < 0 => Ordering::Less, + 0 => Ordering::Equal, + _ => unreachable!("v is {}", v), + }, + ) }); Ok(()) @@ -2119,7 +2119,7 @@ pub mod array_functions { let mut x = 0; while x < array.len() { - if !filter + if filter .call_raw(&ctx, None, [array[x].clone()]) .or_else(|err| match *err { ERR::ErrorFunctionNotFound(fn_sig, ..) @@ -2140,9 +2140,9 @@ pub mod array_functions { .as_bool() .unwrap_or(false) { - drained.push(array.remove(x)); - } else { x += 1; + } else { + drained.push(array.remove(x)); } i += 1; diff --git a/src/packages/blob_basic.rs b/src/packages/blob_basic.rs index ad26ccac..c3f43aff 100644 --- a/src/packages/blob_basic.rs +++ b/src/packages/blob_basic.rs @@ -86,7 +86,7 @@ pub mod blob_functions { } let mut blob = Blob::new(); - blob.resize(len, (value & 0x000000ff) as u8); + blob.resize(len, (value & 0x0000_00ff) as u8); Ok(blob) } /// Convert the BLOB into an array of integers. @@ -205,7 +205,7 @@ pub mod blob_functions { let (index, ..) = calc_offset_len(blob.len(), index, 0); if index < blob.len() { - blob[index] = (value & 0x000000ff) as u8; + blob[index] = (value & 0x0000_00ff) as u8; } } /// Add a new byte `value` to the end of the BLOB. @@ -223,7 +223,7 @@ pub mod blob_functions { /// ``` #[rhai_fn(name = "push", name = "append")] pub fn push(blob: &mut Blob, value: INT) { - blob.push((value & 0x000000ff) as u8); + blob.push((value & 0x0000_00ff) as u8); } /// Add another BLOB to the end of the BLOB. /// @@ -298,7 +298,7 @@ pub mod blob_functions { /// print(b); // prints "[4242184242]" /// ``` pub fn insert(blob: &mut Blob, index: INT, value: INT) { - let value = (value & 0x000000ff) as u8; + let value = (value & 0x0000_00ff) as u8; if blob.is_empty() { blob.push(value); @@ -338,7 +338,7 @@ pub mod blob_functions { return Ok(()); } - let value = (value & 0x000000ff) as u8; + let value = (value & 0x0000_00ff) as u8; let _ctx = ctx; // Check if blob will be over max size limit @@ -528,7 +528,7 @@ pub mod blob_functions { pub fn splice_range(blob: &mut Blob, range: ExclusiveRange, replace: Blob) { let start = INT::max(range.start, 0); let end = INT::max(range.end, start); - splice(blob, start, end - start, replace) + splice(blob, start, end - start, replace); } /// Replace an inclusive `range` of the BLOB with another BLOB. /// @@ -546,7 +546,7 @@ pub mod blob_functions { pub fn splice_range_inclusive(blob: &mut Blob, range: InclusiveRange, replace: Blob) { let start = INT::max(*range.start(), 0); let end = INT::max(*range.end(), start); - splice(blob, start, end - start + 1, replace) + splice(blob, start, end - start + 1, replace); } /// Replace a portion of the BLOB with another BLOB. /// @@ -1220,7 +1220,7 @@ mod write_int_functions { pub fn write_le_int_range(blob: &mut Blob, range: ExclusiveRange, value: INT) { let start = INT::max(range.start, 0); let end = INT::max(range.end, start); - write_le_int(blob, start, end - start, value) + write_le_int(blob, start, end - start, value); } /// Write an `INT` value to the bytes within an inclusive `range` in the BLOB /// in little-endian byte order. @@ -1239,7 +1239,7 @@ mod write_int_functions { pub fn write_le_int_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: INT) { let start = INT::max(*range.start(), 0); let end = INT::max(*range.end(), start); - write_le_int(blob, start, end - start + 1, value) + write_le_int(blob, start, end - start + 1, value); } /// Write an `INT` value to the bytes beginning at the `start` position in the BLOB /// in little-endian byte order. @@ -1262,7 +1262,7 @@ mod write_int_functions { /// ``` #[rhai_fn(name = "write_le")] pub fn write_le_int(blob: &mut Blob, start: INT, len: INT, value: INT) { - write_int(blob, start, len, value, true) + write_int(blob, start, len, value, true); } /// Write an `INT` value to the bytes within an exclusive `range` in the BLOB /// in big-endian byte order. @@ -1281,7 +1281,7 @@ mod write_int_functions { pub fn write_be_int_range(blob: &mut Blob, range: ExclusiveRange, value: INT) { let start = INT::max(range.start, 0); let end = INT::max(range.end, start); - write_be_int(blob, start, end - start, value) + write_be_int(blob, start, end - start, value); } /// Write an `INT` value to the bytes within an inclusive `range` in the BLOB /// in big-endian byte order. @@ -1300,7 +1300,7 @@ mod write_int_functions { pub fn write_be_int_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: INT) { let start = INT::max(*range.start(), 0); let end = INT::max(*range.end(), start); - write_be_int(blob, start, end - start + 1, value) + write_be_int(blob, start, end - start + 1, value); } /// Write an `INT` value to the bytes beginning at the `start` position in the BLOB /// in big-endian byte order. @@ -1323,7 +1323,7 @@ mod write_int_functions { /// ``` #[rhai_fn(name = "write_be")] pub fn write_be_int(blob: &mut Blob, start: INT, len: INT, value: INT) { - write_int(blob, start, len, value, false) + write_int(blob, start, len, value, false); } } @@ -1360,7 +1360,7 @@ mod write_float_functions { pub fn write_le_float_range(blob: &mut Blob, range: ExclusiveRange, value: FLOAT) { let start = INT::max(range.start, 0); let end = INT::max(range.end, start); - write_le_float(blob, start, end - start, value) + write_le_float(blob, start, end - start, value); } /// Write a `FLOAT` value to the bytes within an inclusive `range` in the BLOB /// in little-endian byte order. @@ -1371,7 +1371,7 @@ mod write_float_functions { pub fn write_le_float_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: FLOAT) { let start = INT::max(*range.start(), 0); let end = INT::max(*range.end(), start); - write_le_float(blob, start, end - start + 1, value) + write_le_float(blob, start, end - start + 1, value); } /// Write a `FLOAT` value to the bytes beginning at the `start` position in the BLOB /// in little-endian byte order. @@ -1386,7 +1386,7 @@ mod write_float_functions { /// * If number of bytes in `range` > number of bytes for `FLOAT`, extra bytes in `range` are not modified. #[rhai_fn(name = "write_le")] pub fn write_le_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT) { - write_float(blob, start, len, value, true) + write_float(blob, start, len, value, true); } /// Write a `FLOAT` value to the bytes within an exclusive `range` in the BLOB /// in big-endian byte order. @@ -1397,7 +1397,7 @@ mod write_float_functions { pub fn write_be_float_range(blob: &mut Blob, range: ExclusiveRange, value: FLOAT) { let start = INT::max(range.start, 0); let end = INT::max(range.end, start); - write_be_float(blob, start, end - start, value) + write_be_float(blob, start, end - start, value); } /// Write a `FLOAT` value to the bytes within an inclusive `range` in the BLOB /// in big-endian byte order. @@ -1408,7 +1408,7 @@ mod write_float_functions { pub fn write_be_float_range_inclusive(blob: &mut Blob, range: InclusiveRange, value: FLOAT) { let start = INT::max(*range.start(), 0); let end = INT::max(*range.end(), start); - write_be_float(blob, start, end - start + 1, value) + write_be_float(blob, start, end - start + 1, value); } /// Write a `FLOAT` value to the bytes beginning at the `start` position in the BLOB /// in big-endian byte order. @@ -1423,7 +1423,7 @@ mod write_float_functions { /// * If number of bytes in `range` > number of bytes for `FLOAT`, extra bytes in `range` are not modified. #[rhai_fn(name = "write_be")] pub fn write_be_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT) { - write_float(blob, start, len, value, false) + write_float(blob, start, len, value, false); } } @@ -1471,7 +1471,7 @@ mod write_string_functions { pub fn write_utf8_string_range(blob: &mut Blob, range: ExclusiveRange, string: &str) { let start = INT::max(range.start, 0); let end = INT::max(range.end, start); - write_string(blob, start, end - start, string, false) + write_string(blob, start, end - start, string, false); } /// Write a string to the bytes within an inclusive `range` in the BLOB in UTF-8 encoding. /// @@ -1489,7 +1489,7 @@ mod write_string_functions { pub fn write_utf8_string_range_inclusive(blob: &mut Blob, range: InclusiveRange, string: &str) { let start = INT::max(*range.start(), 0); let end = INT::max(*range.end(), start); - write_string(blob, start, end - start + 1, string, false) + write_string(blob, start, end - start + 1, string, false); } /// Write a string to the bytes within an inclusive `range` in the BLOB in UTF-8 encoding. /// @@ -1511,7 +1511,7 @@ mod write_string_functions { /// ``` #[rhai_fn(name = "write_utf8")] pub fn write_utf8_string(blob: &mut Blob, start: INT, len: INT, string: &str) { - write_string(blob, start, len, string, false) + write_string(blob, start, len, string, false); } /// Write an ASCII string to the bytes within an exclusive `range` in the BLOB. /// @@ -1532,7 +1532,7 @@ mod write_string_functions { pub fn write_ascii_string_range(blob: &mut Blob, range: ExclusiveRange, string: &str) { let start = INT::max(range.start, 0); let end = INT::max(range.end, start); - write_string(blob, start, end - start, string, true) + write_string(blob, start, end - start, string, true); } /// Write an ASCII string to the bytes within an inclusive `range` in the BLOB. /// @@ -1557,7 +1557,7 @@ mod write_string_functions { ) { let start = INT::max(*range.start(), 0); let end = INT::max(*range.end(), start); - write_string(blob, start, end - start + 1, string, true) + write_string(blob, start, end - start + 1, string, true); } /// Write an ASCII string to the bytes within an exclusive `range` in the BLOB. /// @@ -1579,6 +1579,6 @@ mod write_string_functions { /// ``` #[rhai_fn(name = "write_ascii")] pub fn write_ascii_string(blob: &mut Blob, start: INT, len: INT, string: &str) { - write_string(blob, start, len, string, true) + write_string(blob, start, len, string, true); } } diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index 28304579..f6f0e35b 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -28,7 +28,7 @@ where } // Range iterator with step -#[derive(Clone, Copy, Hash, Eq, PartialEq)] +#[derive(Clone, Hash, Eq, PartialEq)] pub struct StepRange { pub from: T, pub to: T, @@ -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) @@ -115,7 +110,7 @@ impl Iterator for StepRange { impl FusedIterator for StepRange {} // Bit-field iterator with step -#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)] +#[derive(Debug, Clone, Hash, Eq, PartialEq)] pub struct BitRange(INT, INT, usize); impl BitRange { @@ -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/lang_core.rs b/src/packages/lang_core.rs index 2390487d..72aca603 100644 --- a/src/packages/lang_core.rs +++ b/src/packages/lang_core.rs @@ -220,7 +220,7 @@ fn collect_fn_metadata( f, ) .into(), - ) + ); }); ctx.engine() @@ -237,7 +237,7 @@ fn collect_fn_metadata( f, ) .into(), - ) + ); }); #[cfg(not(feature = "no_module"))] @@ -255,7 +255,7 @@ fn collect_fn_metadata( f, ) .into(), - ) + ); }); #[cfg(not(feature = "no_module"))] @@ -264,7 +264,7 @@ fn collect_fn_metadata( fn scan_module( list: &mut Array, dict: &BTreeSet, - namespace: Identifier, + namespace: &str, module: &Module, filter: impl Fn( FnNamespace, @@ -278,7 +278,7 @@ fn collect_fn_metadata( module .iter_script_fn() .filter(|(s, a, n, p, f)| filter(*s, *a, n, *p, f)) - .for_each(|(.., f)| list.push(make_metadata(dict, namespace.clone(), f).into())); + .for_each(|(.., f)| list.push(make_metadata(dict, namespace.into(), f).into())); for (ns, m) in module.iter_sub_modules() { let ns = format!( "{}{}{}", @@ -286,12 +286,12 @@ fn collect_fn_metadata( crate::tokenizer::Token::DoubleColon.literal_syntax(), ns ); - scan_module(list, dict, ns.into(), &**m, filter) + scan_module(list, dict, &ns, &**m, filter); } } for (ns, m) in ctx.iter_imports_raw() { - scan_module(&mut list, &dict, ns.clone(), &**m, filter) + scan_module(&mut list, &dict, ns, &**m, filter); } } diff --git a/src/packages/map_basic.rs b/src/packages/map_basic.rs index 427146b9..bb990cb4 100644 --- a/src/packages/map_basic.rs +++ b/src/packages/map_basic.rs @@ -92,10 +92,10 @@ mod map_functions { /// print(m); // prints "#{a:1, c:3}" /// ``` pub fn remove(map: &mut Map, property: &str) -> Dynamic { - if !map.is_empty() { - map.remove(property).unwrap_or_else(|| Dynamic::UNIT) - } else { + if map.is_empty() { Dynamic::UNIT + } else { + map.remove(property).unwrap_or(Dynamic::UNIT) } } /// Add all property values of another object map into the object map. @@ -160,9 +160,9 @@ mod map_functions { if map.is_empty() { *map = map2; } else { - map2.into_iter().for_each(|(key, value)| { + for (key, value) in map2 { map.entry(key).or_insert(value); - }); + } } } } diff --git a/src/packages/mod.rs b/src/packages/mod.rs index 853ec95a..ef59ae26 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -98,6 +98,7 @@ macro_rules! def_package { impl $package { #[doc=concat!("Create a new `", stringify!($package), "`")] + #[must_use] pub fn new() -> Self { let mut module = $crate::Module::new(); ::init(&mut module); diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index dd28d34c..c1ceebb3 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -114,7 +114,7 @@ mod string_functions { } } #[rhai_fn(name = "+")] - pub fn add_prepend(utf8: Blob, string: ImmutableString) -> ImmutableString { + pub fn add_prepend(utf8: Blob, string: &str) -> ImmutableString { let s = String::from_utf8_lossy(&utf8); let mut s = match s { std::borrow::Cow::Borrowed(_) => String::from_utf8(utf8).unwrap(), @@ -122,7 +122,7 @@ mod string_functions { }; if !string.is_empty() { - s.push_str(&string); + s.push_str(string); } s.into() @@ -440,7 +440,7 @@ mod string_functions { /// ``` #[rhai_fn(name = "make_upper")] pub fn make_upper_char(character: &mut char) { - *character = to_upper_char(*character) + *character = to_upper_char(*character); } /// Convert the character to lower-case and return it as a new character. /// @@ -476,7 +476,7 @@ mod string_functions { /// ``` #[rhai_fn(name = "make_lower")] pub fn make_lower_char(character: &mut char) { - *character = to_lower_char(*character) + *character = to_lower_char(*character); } /// Return `true` if the string starts with a specified string. @@ -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 @@ -561,10 +558,9 @@ mod string_functions { .len() }; - string[start..] - .find(character) - .map(|index| string[0..start + index].chars().count() as INT) - .unwrap_or(-1 as INT) + string[start..].find(character).map_or(-1 as INT, |index| { + string[0..start + index].chars().count() as INT + }) } /// Find the specified `character` in the string and return the first index where it is found. /// If the `character` is not found, `-1` is returned. @@ -585,8 +581,7 @@ mod string_functions { } else { string .find(character) - .map(|index| string[0..index].chars().count() as INT) - .unwrap_or(-1 as INT) + .map_or(-1 as INT, |index| string[0..index].chars().count() as INT) } } /// Find the specified sub-string in the string, starting from the specified `start` position, @@ -615,20 +610,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 @@ -644,8 +636,9 @@ mod string_functions { string[start..] .find(find_string) - .map(|index| string[0..start + index].chars().count() as INT) - .unwrap_or(-1 as INT) + .map_or(-1 as INT, |index| { + string[0..start + index].chars().count() as INT + }) } /// Find the specified `character` in the string and return the first index where it is found. /// If the `character` is not found, `-1` is returned. @@ -666,8 +659,7 @@ mod string_functions { } else { string .find(find_string) - .map(|index| string[0..index].chars().count() as INT) - .unwrap_or(-1 as INT) + .map_or(-1 as INT, |index| string[0..index].chars().count() as INT) } } @@ -694,15 +686,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 +726,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 +811,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(); @@ -850,7 +838,7 @@ mod string_functions { .iter() .skip(offset) .take(len) - .cloned() + .copied() .collect::() .into() } @@ -899,7 +887,7 @@ mod string_functions { pub fn crop_range(string: &mut ImmutableString, range: ExclusiveRange) { let start = INT::max(range.start, 0); let end = INT::max(range.end, start); - crop(string, start, end - start) + crop(string, start, end - start); } /// Remove all characters from the string except those within an inclusive `range`. /// @@ -916,7 +904,7 @@ mod string_functions { pub fn crop_inclusive_range(string: &mut ImmutableString, range: InclusiveRange) { let start = INT::max(*range.start(), 0); let end = INT::max(*range.end(), start); - crop(string, start, end - start + 1) + crop(string, start, end - start + 1); } /// Remove all characters from the string except those within a range. @@ -952,15 +940,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 +1241,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..ec13dd3e 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -130,6 +130,7 @@ impl<'e> ParseState<'e> { /// If the variable is not present in the scope, the first return value is zero. /// /// The second return value indicates whether the barrier has been hit before finding the variable. + #[must_use] pub fn find_var(&self, name: &str) -> (usize, bool) { let mut hit_barrier = false; @@ -175,7 +176,7 @@ impl<'e> ParseState<'e> { }); } } else { - self.allow_capture = true + self.allow_capture = true; } if hit_barrier { @@ -265,10 +266,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(()) } @@ -362,7 +361,10 @@ impl Expr { /// Make sure that the next expression is not a statement expression (i.e. wrapped in `{}`). #[inline] -fn ensure_not_statement_expr(input: &mut TokenStream, type_name: impl ToString) -> ParseResult<()> { +fn ensure_not_statement_expr( + input: &mut TokenStream, + type_name: &(impl ToString + ?Sized), +) -> ParseResult<()> { match input.peek().expect(NEVER_ENDS) { (Token::LeftBrace, pos) => Err(PERR::ExprExpected(type_name.to_string()).into_err(*pos)), _ => Ok(()), @@ -521,7 +523,9 @@ impl Engine { } #[cfg(not(feature = "no_module"))] - let hash = if !namespace.is_empty() { + let hash = if namespace.is_empty() { + calc_fn_hash(&id, 0) + } else { let root = namespace.root(); let index = state.find_module(root); @@ -531,18 +535,19 @@ 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); - crate::calc_qualified_fn_hash(namespace.iter().map(|m| m.as_str()), &id, 0) - } else { - calc_fn_hash(&id, 0) + crate::calc_qualified_fn_hash(namespace.iter().map(Ident::as_str), &id, 0) }; #[cfg(feature = "no_module")] let hash = calc_fn_hash(&id, 0); @@ -585,7 +590,9 @@ impl Engine { eat_token(input, Token::RightParen); #[cfg(not(feature = "no_module"))] - let hash = if !namespace.is_empty() { + let hash = if namespace.is_empty() { + calc_fn_hash(&id, args.len()) + } else { let root = namespace.root(); let index = state.find_module(root); @@ -595,22 +602,22 @@ 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); crate::calc_qualified_fn_hash( - namespace.iter().map(|m| m.as_str()), + namespace.iter().map(Ident::as_str), &id, args.len(), ) - } else { - calc_fn_hash(&id, args.len()) }; #[cfg(feature = "no_module")] let hash = calc_fn_hash(&id, args.len()); @@ -785,7 +792,7 @@ impl Engine { // Any more indexing following? match input.peek().expect(NEVER_ENDS) { // If another indexing level, right-bind it - (Token::LeftBracket, ..) | (Token::QuestionBracket, ..) => { + (Token::LeftBracket | Token::QuestionBracket, ..) => { let (token, pos) = input.next().expect(NEVER_ENDS); let prev_pos = settings.pos; settings.pos = pos; @@ -1085,7 +1092,10 @@ impl Engine { return Err(PERR::WrongSwitchCaseCondition.into_err(if_pos)); } - (Default::default(), Expr::BoolConstant(true, Position::NONE)) + ( + StaticVec::default(), + Expr::BoolConstant(true, Position::NONE), + ) } _ if def_case.is_some() => { return Err(PERR::WrongSwitchDefaultCase.into_err(def_case_pos)) @@ -1146,7 +1156,9 @@ impl Engine { expressions.push((condition, Expr::Stmt(stmt_block.into())).into()); let index = expressions.len() - 1; - if !case_expr_list.is_empty() { + if case_expr_list.is_empty() { + def_case = Some(index); + } else { for expr in case_expr_list { let value = expr.get_literal_value().ok_or_else(|| { PERR::ExprExpected("a literal".to_string()).into_err(expr.start_position()) @@ -1197,8 +1209,6 @@ impl Engine { .and_modify(|cases| cases.push(index)) .or_insert_with(|| [index].into()); } - } else { - def_case = Some(index); } match input.peek().expect(NEVER_ENDS) { @@ -1687,7 +1697,7 @@ impl Engine { } // Indexing #[cfg(not(feature = "no_index"))] - (expr, token @ Token::LeftBracket) | (expr, token @ Token::QuestionBracket) => { + (expr, token @ (Token::LeftBracket | Token::QuestionBracket)) => { let opt = match token { Token::LeftBracket => ASTFlags::NONE, Token::QuestionBracket => ASTFlags::NEGATED, @@ -1697,7 +1707,7 @@ impl Engine { } // Property access #[cfg(not(feature = "no_object"))] - (expr, op @ Token::Period) | (expr, op @ Token::Elvis) => { + (expr, op @ (Token::Period | Token::Elvis)) => { // Expression after dot must start with an identifier match input.peek().expect(NEVER_ENDS) { (Token::Identifier(..), ..) => { @@ -1742,7 +1752,7 @@ impl Engine { #[cfg(not(feature = "no_module"))] if let Some((.., namespace, hash, name)) = namespaced_variable { if !namespace.is_empty() { - *hash = crate::calc_qualified_var_hash(namespace.iter().map(|v| v.as_str()), name); + *hash = crate::calc_qualified_var_hash(namespace.iter().map(Ident::as_str), name); #[cfg(not(feature = "no_module"))] { @@ -1755,11 +1765,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); @@ -2190,7 +2203,7 @@ impl Engine { Token::Custom(c) => self .custom_keywords .get(c) - .cloned() + .copied() .ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*current_pos))?, Token::Reserved(c) if !is_valid_identifier(c.chars()) => { return Err(PERR::UnknownOperator(c.to_string()).into_err(*current_pos)) @@ -2215,7 +2228,7 @@ impl Engine { Token::Custom(c) => self .custom_keywords .get(c) - .cloned() + .copied() .ok_or_else(|| PERR::Reserved(c.to_string()).into_err(*next_pos))?, Token::Reserved(c) if !is_valid_identifier(c.chars()) => { return Err(PERR::UnknownOperator(c.to_string()).into_err(*next_pos)) @@ -2519,13 +2532,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 +2807,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 +3205,6 @@ impl Engine { level: 0, options, pos, - ..settings }; let func = self.parse_fn( @@ -3424,7 +3436,7 @@ impl Engine { } let s = state.get_identifier("", s); state.stack.push(s.clone(), ()); - params.push((s, pos)) + params.push((s, pos)); } (Token::LexError(err), pos) => return Err(err.into_err(pos)), (.., pos) => { @@ -3560,7 +3572,7 @@ impl Engine { } let s = state.get_identifier("", s); state.stack.push(s.clone(), ()); - params_list.push(s) + params_list.push(s); } (Token::LexError(err), pos) => return Err(err.into_err(pos)), (.., pos) => { diff --git a/src/serde/de.rs b/src/serde/de.rs index cf3e638a..747b0597 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -1,7 +1,9 @@ //! Implement deserialization support of [`Dynamic`][crate::Dynamic] for [`serde`]. use crate::types::dynamic::Union; -use crate::{Dynamic, ImmutableString, LexError, Position, RhaiError, RhaiResultOf, ERR}; +use crate::{ + Dynamic, ImmutableString, LexError, Position, RhaiError, RhaiResultOf, SmartString, ERR, +}; use serde::de::{Error, IntoDeserializer, Visitor}; use serde::{Deserialize, Deserializer}; #[cfg(feature = "no_std")] @@ -420,7 +422,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { || self.type_error(), |map| { _visitor.visit_map(IterateMap::new( - map.keys().map(|key| key.as_str()), + map.keys().map(SmartString::as_str), map.values(), )) }, @@ -455,7 +457,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/serde/metadata.rs b/src/serde/metadata.rs index 4c8cc501..3ce42c2d 100644 --- a/src/serde/metadata.rs +++ b/src/serde/metadata.rs @@ -181,7 +181,7 @@ impl ModuleMetadata<'_> { impl<'a> From<&'a crate::Module> for ModuleMetadata<'a> { fn from(module: &'a crate::Module) -> Self { - let mut functions: Vec<_> = module.iter_fn().map(|f| f.into()).collect(); + let mut functions: Vec<_> = module.iter_fn().map(Into::into).collect(); functions.sort(); Self { diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 682e4285..bd742702 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -210,7 +210,7 @@ impl Position { } /// Print this [`Position`] for debug purposes. #[inline] - pub(crate) fn debug_print(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { + pub(crate) fn debug_print(self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { if !self.is_none() { write!(_f, " @ {:?}", self)?; } @@ -1215,7 +1215,7 @@ pub fn parse_string_literal( if allow_interpolation && next_char == '$' && escape.is_empty() - && stream.peek_next().map(|ch| ch == '{').unwrap_or(false) + && stream.peek_next().map_or(false, |ch| ch == '{') { interpolated = true; state.is_within_text_terminated_by = None; @@ -1245,7 +1245,7 @@ pub fn parse_string_literal( match next_char { // \r - ignore if followed by \n - '\r' if stream.peek_next().map(|ch| ch == '\n').unwrap_or(false) => (), + '\r' if stream.peek_next().map_or(false, |ch| ch == '\n') => (), // \... '\\' if !verbatim && escape.is_empty() => { escape.push('\\'); @@ -1271,7 +1271,7 @@ pub fn parse_string_literal( result.push('\r'); } // \x??, \u????, \U???????? - ch @ 'x' | ch @ 'u' | ch @ 'U' if !escape.is_empty() => { + ch @ ('x' | 'u' | 'U') if !escape.is_empty() => { let mut seq = escape.clone(); escape.clear(); seq.push(ch); @@ -1307,7 +1307,7 @@ pub fn parse_string_literal( // \{termination_char} - escaped _ if termination_char == next_char && !escape.is_empty() => { escape.clear(); - result.push(next_char) + result.push(next_char); } // Verbatim @@ -1598,7 +1598,7 @@ fn get_next_token_inner( } } // 0x????, 0o????, 0b???? at beginning - ch @ 'x' | ch @ 'o' | ch @ 'b' | ch @ 'X' | ch @ 'O' | ch @ 'B' + ch @ ('x' | 'o' | 'b' | 'X' | 'O' | 'B') if c == '0' && result.len() <= 1 => { result.push(next_char); @@ -1639,12 +1639,14 @@ fn get_next_token_inner( UNSIGNED_INT::from_str_radix(&out, radix) .map(|v| v as INT) - .map(Token::IntegerConstant) - .unwrap_or_else(|_| { - Token::LexError( - LERR::MalformedNumber(result.into_iter().collect()).into(), - ) - }) + .map_or_else( + |_| { + Token::LexError( + LERR::MalformedNumber(result.into_iter().collect()).into(), + ) + }, + Token::IntegerConstant, + ) } else { let out: String = result.iter().filter(|&&c| c != NUMBER_SEPARATOR).collect(); @@ -1680,7 +1682,7 @@ fn get_next_token_inner( // letter or underscore ... #[cfg(not(feature = "unicode-xid-ident"))] - ('a'..='z', ..) | ('_', ..) | ('A'..='Z', ..) => { + ('a'..='z' | '_' | 'A'..='Z', ..) => { return get_identifier(stream, pos, start_pos, c); } #[cfg(feature = "unicode-xid-ident")] @@ -2161,7 +2163,7 @@ fn get_identifier( } } - let is_valid_identifier = is_valid_identifier(result.iter().cloned()); + let is_valid_identifier = is_valid_identifier(result.iter().copied()); let identifier: String = result.into_iter().collect(); @@ -2384,7 +2386,7 @@ impl<'a> Iterator for TokenIterator<'a> { ("::<", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(), "'::<>' is not a valid symbol. This is not Rust! Should it be '::'?".to_string(), ).into()), - ("(*", false) | ("*)", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(), + ("(*" | "*)", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(), "'(* .. *)' is not a valid comment format. This is not Pascal! Should it be '/* .. */'?".to_string(), ).into()), ("# {", false) => Token::LexError(LERR::ImproperSymbol(s.to_string(), diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index 8a6e1fa2..d83eb68d 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), @@ -739,7 +739,7 @@ impl Dynamic { /// A [`Dynamic`] containing the integer 1,000. pub const THOUSAND: Self = Self::from_int(1000); /// A [`Dynamic`] containing the integer 1,000,000. - pub const MILLION: Self = Self::from_int(1000000); + pub const MILLION: Self = Self::from_int(1_000_000); /// A [`Dynamic`] containing the integer -1. pub const NEGATIVE_ONE: Self = Self::from_int(-1); /// A [`Dynamic`] containing the integer -2. @@ -778,7 +778,7 @@ impl Dynamic { /// /// Not available under `no_float`. #[cfg(not(feature = "no_float"))] - pub const FLOAT_MILLION: Self = Self::from_float(1000000.0); + pub const FLOAT_MILLION: Self = Self::from_float(1_000_000.0); /// A [`Dynamic`] containing `-1.0`. /// /// Not available under `no_float`. @@ -823,7 +823,7 @@ impl Dynamic { /// /// Not available under `no_float`. #[cfg(not(feature = "no_float"))] - pub const FLOAT_MILLIONTH: Self = Self::from_float(0.000001); + pub const FLOAT_MILLIONTH: Self = Self::from_float(0.000_001); /// A [`Dynamic`] containing π. /// /// Not available under `no_float`. @@ -867,16 +867,19 @@ impl Dynamic { /// Create a new [`Dynamic`] from a [`bool`]. #[inline(always)] + #[must_use] pub const fn from_bool(value: bool) -> Self { Self(Union::Bool(value, DEFAULT_TAG_VALUE, ReadWrite)) } /// Create a new [`Dynamic`] from an [`INT`]. #[inline(always)] + #[must_use] pub const fn from_int(value: INT) -> Self { Self(Union::Int(value, DEFAULT_TAG_VALUE, ReadWrite)) } /// Create a new [`Dynamic`] from a [`char`]. #[inline(always)] + #[must_use] pub const fn from_char(value: char) -> Self { Self(Union::Char(value, DEFAULT_TAG_VALUE, ReadWrite)) } @@ -885,6 +888,7 @@ impl Dynamic { /// Not available under `no_float`. #[cfg(not(feature = "no_float"))] #[inline(always)] + #[must_use] pub const fn from_float(value: crate::FLOAT) -> Self { Self(Union::Float( crate::ast::FloatWrapper::new_const(value), @@ -897,24 +901,28 @@ impl Dynamic { /// Exported under the `decimal` feature only. #[cfg(feature = "decimal")] #[inline(always)] + #[must_use] pub fn from_decimal(value: rust_decimal::Decimal) -> Self { Self(Union::Decimal(value.into(), DEFAULT_TAG_VALUE, ReadWrite)) } /// Create a [`Dynamic`] from an [`Array`][crate::Array]. #[cfg(not(feature = "no_index"))] #[inline(always)] + #[must_use] pub fn from_array(array: crate::Array) -> Self { Self(Union::Array(array.into(), DEFAULT_TAG_VALUE, ReadWrite)) } /// Create a [`Dynamic`] from a [`Blob`][crate::Blob]. #[cfg(not(feature = "no_index"))] #[inline(always)] + #[must_use] pub fn from_blob(blob: crate::Blob) -> Self { Self(Union::Blob(blob.into(), DEFAULT_TAG_VALUE, ReadWrite)) } /// Create a [`Dynamic`] from a [`Map`][crate::Map]. #[cfg(not(feature = "no_object"))] #[inline(always)] + #[must_use] pub fn from_map(map: crate::Map) -> Self { Self(Union::Map(map.into(), DEFAULT_TAG_VALUE, ReadWrite)) } @@ -923,6 +931,7 @@ impl Dynamic { /// Not available under `no-std`. #[cfg(not(feature = "no_std"))] #[inline(always)] + #[must_use] pub fn from_timestamp(value: Instant) -> Self { Self(Union::TimeStamp(value.into(), DEFAULT_TAG_VALUE, ReadWrite)) } @@ -993,6 +1002,7 @@ impl Dynamic { } /// Make this [`Dynamic`] read-only (i.e. a constant). #[inline(always)] + #[must_use] pub fn into_read_only(self) -> Self { let mut value = self; value.set_access_mode(AccessMode::ReadOnly); @@ -1018,17 +1028,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 +1372,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 @@ -1397,13 +1398,13 @@ impl Dynamic { Union::Shared(ref cell, ..) => { let value = locked_read(cell); - if (*value).type_id() != TypeId::of::() + return if (*value).type_id() != TypeId::of::() && TypeId::of::() != TypeId::of::() { - return None; + None } else { - return Some(DynamicReadLock(DynamicReadLockInner::Guard(value))); - } + Some(DynamicReadLock(DynamicReadLockInner::Guard(value))) + }; } _ => (), } @@ -1429,13 +1430,13 @@ impl Dynamic { Union::Shared(ref cell, ..) => { let guard = crate::func::locked_write(cell); - if (*guard).type_id() != TypeId::of::() + return if (*guard).type_id() != TypeId::of::() && TypeId::of::() != TypeId::of::() { - return None; + None } else { - return Some(DynamicWriteLock(DynamicWriteLockInner::Guard(guard))); - } + Some(DynamicWriteLock(DynamicWriteLockInner::Guard(guard))) + }; } _ => (), } @@ -1791,7 +1792,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 +1814,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/fn_ptr.rs b/src/types/fn_ptr.rs index 6b8d6254..3ac75077 100644 --- a/src/types/fn_ptr.rs +++ b/src/types/fn_ptr.rs @@ -24,15 +24,15 @@ pub struct FnPtr { impl fmt::Debug for FnPtr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if !self.is_curried() { - write!(f, "Fn({})", self.fn_name()) - } else { + if self.is_curried() { self.curry .iter() .fold(f.debug_tuple("Fn").field(&self.name), |f, curry| { f.field(curry) }) .finish() + } else { + write!(f, "Fn({})", self.fn_name()) } } } @@ -149,7 +149,7 @@ impl FnPtr { #[cfg(not(feature = "no_function"))] _ast.as_ref(), ]; - let lib = if lib.first().map(|m: &&Module| m.is_empty()).unwrap_or(true) { + let lib = if lib.first().map_or(true, |m: &&Module| m.is_empty()) { &lib[0..0] } else { &lib diff --git a/src/types/immutable_string.rs b/src/types/immutable_string.rs index 85cd4127..b668ee15 100644 --- a/src/types/immutable_string.rs +++ b/src/types/immutable_string.rs @@ -159,7 +159,7 @@ impl FromIterator for ImmutableString { impl<'a> FromIterator<&'a char> for ImmutableString { #[inline] fn from_iter>(iter: T) -> Self { - Self(iter.into_iter().cloned().collect::().into()) + Self(iter.into_iter().copied().collect::().into()) } } @@ -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()) @@ -576,6 +576,7 @@ impl PartialOrd for String { impl ImmutableString { /// Create a new [`ImmutableString`]. #[inline(always)] + #[must_use] pub fn new() -> Self { Self(SmartString::new_const().into()) } @@ -583,6 +584,7 @@ impl ImmutableString { /// /// If there are other references to the same string, a cloned copy is returned. #[inline] + #[must_use] pub fn into_owned(mut self) -> String { self.make_mut(); // Make sure it is unique reference shared_take(self.0).into() // Should succeed @@ -620,6 +622,7 @@ impl ImmutableString { /// assert!(!s2.ptr_eq(&s3)); /// ``` #[inline(always)] + #[must_use] pub fn ptr_eq(&self, other: &Self) -> bool { Shared::ptr_eq(&self.0, &other.0) } diff --git a/src/types/scope.rs b/src/types/scope.rs index 41e40afe..8939c94b 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, } } } @@ -436,12 +436,11 @@ impl Scope<'_> { /// assert_eq!(my_scope.is_constant("y"), None); /// ``` #[inline] + #[must_use] 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. @@ -550,6 +549,41 @@ impl Scope<'_> { pub fn get(&self, name: &str) -> Option<&Dynamic> { self.get_index(name).map(|(index, _)| &self.values[index]) } + /// Remove the last entry in the [`Scope`] by the specified name and return its value. + /// + /// If the entry by the specified name is not found, [`None`] is returned. + /// + /// # Example + /// + /// ``` + /// use rhai::Scope; + /// + /// let mut my_scope = Scope::new(); + /// + /// my_scope.push("x", 123_i64); // first 'x' + /// my_scope.push("x", 42_i64); // second 'x', shadows first + /// + /// assert_eq!(my_scope.len(), 2); + /// + /// let value = my_scope.remove::("x").expect("x should exist"); + /// + /// assert_eq!(value, 42); + /// + /// assert_eq!(my_scope.len(), 1); + /// + /// let value = my_scope.get_value::("x").expect("x should still exist"); + /// + /// assert_eq!(value, 123); + /// ``` + #[inline(always)] + #[must_use] + pub fn remove(&mut self, name: &str) -> Option { + self.get_index(name).and_then(|(index, _)| { + self.names.remove(index); + self.aliases.remove(index); + self.values.remove(index).try_cast() + }) + } /// Get a mutable reference to an entry in the [`Scope`]. /// /// If the entry by the specified name is not found, or if it is read-only,