diff --git a/src/ast.rs b/src/ast.rs index 4413fe4d..45e4fe54 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -2200,12 +2200,11 @@ impl Expr { #[cfg(not(feature = "no_object"))] Self::Map(x, _) if self.is_constant() => { - let mut map = x.1.clone(); - x.0.iter().for_each(|(k, v)| { - *map.get_mut(k.name.as_str()).expect("contains all keys") = - v.get_literal_value().expect("constant value") - }); - Dynamic::from_map(map) + Dynamic::from_map(x.0.iter().fold(x.1.clone(), |mut map, (k, v)| { + let value_ref = map.get_mut(k.name.as_str()).expect("contains all keys"); + *value_ref = v.get_literal_value().expect("constant value"); + map + })) } _ => return None, diff --git a/src/engine.rs b/src/engine.rs index 91a53af5..3b215b6c 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1893,20 +1893,22 @@ impl Engine { let crate::ast::FnCallExpr { args, constants, .. } = x.as_ref(); - let mut arg_values = StaticVec::with_capacity(args.len()); - let mut first_arg_pos = Position::NONE; - args.iter().try_for_each(|expr| { - self.get_arg_value(scope, mods, state, lib, this_ptr, level, expr, constants) - .map(|(value, pos)| { - if arg_values.is_empty() { - first_arg_pos = pos - } - arg_values.push(value.flatten()); - }) - })?; + let (values, pos) = args.iter().try_fold( + (StaticVec::with_capacity(args.len()), Position::NONE), + |(mut values, mut pos), expr| -> Result<_, Box> { + let (value, arg_pos) = self.get_arg_value( + scope, mods, state, lib, this_ptr, level, expr, constants, + )?; + if values.is_empty() { + pos = arg_pos; + } + values.push(value.flatten()); + Ok((values, pos)) + }, + )?; - idx_values.push((arg_values, first_arg_pos).into()); + idx_values.push((values, pos).into()); } #[cfg(not(feature = "no_object"))] Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dotting => { @@ -1937,22 +1939,22 @@ impl Engine { let crate::ast::FnCallExpr { args, constants, .. } = x.as_ref(); - let mut arg_values = StaticVec::with_capacity(args.len()); - let mut first_arg_pos = Position::NONE; - args.iter().try_for_each(|expr| { - self.get_arg_value( - scope, mods, state, lib, this_ptr, level, expr, constants, - ) - .map(|(value, pos)| { - if arg_values.is_empty() { - first_arg_pos = pos - } - arg_values.push(value.flatten()); - }) - })?; - - (arg_values, first_arg_pos).into() + args.iter() + .try_fold( + (StaticVec::with_capacity(args.len()), Position::NONE), + |(mut values, mut pos), expr| -> Result<_, Box> { + let (value, arg_pos) = self.get_arg_value( + scope, mods, state, lib, this_ptr, level, expr, constants, + )?; + if values.is_empty() { + pos = arg_pos + } + values.push(value.flatten()); + Ok((values, pos)) + }, + )? + .into() } #[cfg(not(feature = "no_object"))] Expr::FnCall(_, _) if _parent_chain_type == ChainType::Dotting => { @@ -2255,25 +2257,35 @@ impl Engine { } #[cfg(not(feature = "no_index"))] - Expr::Array(x, _) => { - let mut arr = Array::with_capacity(x.len()); - x.iter().try_for_each(|item| { - self.eval_expr(scope, mods, state, lib, this_ptr, item, level) - .map(|value| arr.push(value.flatten())) - })?; - Ok(arr.into()) - } + Expr::Array(x, _) => Ok(x + .iter() + .try_fold( + Array::with_capacity(x.len()), + |mut arr, item| -> Result<_, Box> { + arr.push( + self.eval_expr(scope, mods, state, lib, this_ptr, item, level)? + .flatten(), + ); + Ok(arr) + }, + )? + .into()), #[cfg(not(feature = "no_object"))] - Expr::Map(x, _) => { - let mut map = x.1.clone(); - x.0.iter().try_for_each(|(Ident { name: key, .. }, expr)| { - let value_ref = map.get_mut(key.as_str()).expect("contains all keys"); - self.eval_expr(scope, mods, state, lib, this_ptr, expr, level) - .map(|value| *value_ref = value.flatten()) - })?; - Ok(map.into()) - } + Expr::Map(x, _) => Ok(x + .0 + .iter() + .try_fold( + x.1.clone(), + |mut map, (Ident { name: key, .. }, expr)| -> Result<_, Box> { + let value_ref = map.get_mut(key.as_str()).expect("contains all keys"); + *value_ref = self + .eval_expr(scope, mods, state, lib, this_ptr, expr, level)? + .flatten(); + Ok(map) + }, + )? + .into()), // Namespace-qualified function call Expr::FnCall(x, pos) if x.is_qualified() => { diff --git a/src/func/call.rs b/src/func/call.rs index 0d08f378..04841108 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -1153,13 +1153,19 @@ impl Engine { )); } - let (name, mut fn_curry) = arg.cast::().take_data(); + let (name, fn_curry) = arg.cast::().take_data(); // Append the new curried arguments to the existing list. - a_expr.iter().skip(1).try_for_each(|expr| { - self.get_arg_value(scope, mods, state, lib, this_ptr, level, expr, constants) - .map(|(value, _)| fn_curry.push(value)) - })?; + let fn_curry = a_expr.iter().skip(1).try_fold( + fn_curry, + |mut curried, expr| -> Result<_, Box> { + let (value, _) = self.get_arg_value( + scope, mods, state, lib, this_ptr, level, expr, constants, + )?; + curried.push(value); + Ok(curried) + }, + )?; return Ok(FnPtr::new_unchecked(name, fn_curry).into()); } diff --git a/src/func/hashing.rs b/src/func/hashing.rs index 952e5a72..8d360c04 100644 --- a/src/func/hashing.rs +++ b/src/func/hashing.rs @@ -124,10 +124,7 @@ pub fn calc_fn_hash(fn_name: &str, num: usize) -> u64 { pub fn calc_fn_params_hash(params: impl Iterator) -> u64 { let s = &mut get_hasher(); let mut len = 0; - params.for_each(|t| { - len += 1; - t.hash(s); - }); + params.inspect(|_| len += 1).for_each(|t| t.hash(s)); len.hash(s); s.finish() } diff --git a/src/module/mod.rs b/src/module/mod.rs index fb2835e5..c0d86696 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -1409,10 +1409,11 @@ impl Module { /// ``` #[cfg(not(feature = "no_module"))] pub fn eval_ast_as_new( - mut scope: crate::Scope, + scope: crate::Scope, ast: &crate::AST, engine: &crate::Engine, ) -> Result> { + let mut scope = scope; let mut mods = crate::engine::Imports::new(); let orig_mods_len = mods.len(); @@ -1420,21 +1421,28 @@ impl Module { engine.eval_ast_with_scope_raw(&mut scope, &mut mods, &ast, 0)?; // Create new module - let mut module = Module::new(); - - scope.into_iter().for_each(|(_, value, mut aliases)| { - // Variables with an alias left in the scope become module variables - match aliases.len() { - 0 => (), - 1 => { - let alias = aliases.pop().expect("not empty"); - module.set_var(alias, value); - } - _ => aliases.into_iter().for_each(|alias| { - module.set_var(alias, value.clone()); - }), - } - }); + let mut module = + scope + .into_iter() + .fold(Module::new(), |mut module, (_, value, mut aliases)| { + // Variables with an alias left in the scope become module variables + match aliases.len() { + 0 => (), + 1 => { + let alias = aliases.pop().expect("not empty"); + module.set_var(alias, value); + } + _ => { + let last_alias = aliases.pop().expect("not empty"); + aliases.into_iter().for_each(|alias| { + module.set_var(alias, value.clone()); + }); + // Avoid cloning the last value + module.set_var(last_alias, value); + } + } + module + }); // Extra modules left in the scope become sub-modules let mut func_mods = crate::engine::Imports::new(); diff --git a/src/packages/fn_basic.rs b/src/packages/fn_basic.rs index 5ec75874..93f6aa16 100644 --- a/src/packages/fn_basic.rs +++ b/src/packages/fn_basic.rs @@ -90,11 +90,13 @@ fn collect_fn_metadata(ctx: NativeCallContext) -> crate::Array { .map(|&s| s.into()) .collect(); - let mut list = Array::new(); - - ctx.iter_namespaces() - .flat_map(|m| m.iter_script_fn()) - .for_each(|(_, _, _, _, f)| list.push(make_metadata(&dict, None, f).into())); + let mut list = ctx.iter_namespaces().flat_map(Module::iter_script_fn).fold( + Array::new(), + |mut list, (_, _, _, _, f)| { + list.push(make_metadata(&dict, None, f).into()); + list + }, + ); #[cfg(not(feature = "no_module"))] { diff --git a/src/types/scope.rs b/src/types/scope.rs index 6e9e39ed..30fffcff 100644 --- a/src/types/scope.rs +++ b/src/types/scope.rs @@ -518,22 +518,18 @@ impl<'a> Scope<'a> { #[inline] #[must_use] pub fn clone_visible(&self) -> Self { - let mut entries = Self::new(); - - self.names - .iter() - .rev() - .enumerate() - .for_each(|(index, (name, alias))| { + self.names.iter().rev().enumerate().fold( + Self::new(), + |mut entries, (index, (name, alias))| { if !entries.names.iter().any(|(key, _)| key == name) { entries.names.push((name.clone(), alias.clone())); entries .values .push(self.values[self.len() - 1 - index].clone()); } - }); - - entries + entries + }, + ) } /// Get an iterator to entries in the [`Scope`]. #[inline]