From 707ece7e80dad9f67e29d15c4e77bec83f1961c6 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Wed, 14 Oct 2020 23:22:10 +0800 Subject: [PATCH] Refactor iterators API. --- RELEASES.md | 2 ++ src/api.rs | 10 ++++++---- src/engine.rs | 15 ++++++++------- src/lib.rs | 2 +- src/module/mod.rs | 18 ++++++++++++++++++ src/packages/array_basic.rs | 5 +---- src/packages/iter_basic.rs | 18 ++++-------------- src/packages/string_more.rs | 4 +--- 8 files changed, 41 insertions(+), 33 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index 6f9e4ed9..4ce09906 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -12,6 +12,7 @@ Breaking changes * `AST::iter_functions` now returns an iterator instead of taking a closure. * `Module::get_script_function_by_signature` renamed to `Module::get_script_fn` and returns `&>`. * `Module::num_fn`, `Module::num_var` and `Module::num_iter` are removed and merged into `Module::count`. +* `Module::set_iter` is renamed to `Module::set_iter_raw`. * The `merge_namespaces` parameter to `Module::eval_ast_as_new` is removed and now defaults to `true`. * `GlobalFileModuleResolver` is removed because its performance gain over the `FileModuleResolver` is no longer very significant. * The following `EvalAltResult` variants are removed and merged into `EvalAltResult::ErrorMismatchDataType`: `ErrorCharMismatch`, `ErrorNumericIndexExpr`, `ErrorStringIndexExpr`, `ErrorImportExpr`, `ErrorLogicGuard`, `ErrorBooleanArgMismatch` @@ -32,6 +33,7 @@ New features * `Dynamic::from(&str)` now constructs a `Dynamic` with a copy of the string as value. * `AST::combine` and `AST::combine_filtered` allows combining two `AST`'s without creating a new one. * `map`, `filter`, `reduce`, `reduce_rev`, `some`, `all`, `extract`, `splice`, `chop` and `sort` functions for arrays. +* New `Module::set_iter`, `Module::set_iterable` and `Module::set_iterator` to define type iterators more easily. `Engine::register_iterator` is changed to use the simpler version. Enhancements ------------ diff --git a/src/api.rs b/src/api.rs index f07b05c0..14fb4083 100644 --- a/src/api.rs +++ b/src/api.rs @@ -3,7 +3,7 @@ use crate::any::{Dynamic, Variant}; use crate::engine::{Engine, EvalContext, Imports, State}; use crate::error::ParseError; -use crate::fn_native::{IteratorFn, SendSync}; +use crate::fn_native::SendSync; use crate::module::{FuncReturn, Module}; use crate::optimize::OptimizationLevel; use crate::parser::AST; @@ -174,11 +174,13 @@ impl Engine { self } - /// Register an iterator adapter for a type with the `Engine`. + /// Register an iterator adapter for an iterable type with the `Engine`. /// This is an advanced feature. #[inline(always)] - pub fn register_iterator(&mut self, f: IteratorFn) -> &mut Self { - self.global_module.set_iter(TypeId::of::(), f); + pub fn register_iterator, U: Variant + Clone>( + &mut self, + ) -> &mut Self { + self.global_module.set_iterable::(); self } diff --git a/src/engine.rs b/src/engine.rs index 127a4277..c282a436 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1782,21 +1782,22 @@ impl Engine { // For loop Stmt::For(x) => { let (name, expr, stmt, _) = x.as_ref(); - let iter_type = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?; - let tid = iter_type.type_id(); + let iter_obj = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?; + let iter_type = iter_obj.type_id(); - if let Some(func) = self + let func = self .global_module - .get_iter(tid) - .or_else(|| self.packages.get_iter(tid)) - { + .get_iter(iter_type) + .or_else(|| self.packages.get_iter(iter_type)); + + if let Some(func) = func { // Add the loop variable let var_name = unsafe_cast_var_name_to_lifetime(name, &state); scope.push(var_name, ()); let index = scope.len() - 1; state.scope_level += 1; - for iter_value in func(iter_type) { + for iter_value in func(iter_obj) { let (loop_var, _) = scope.get_mut(index); let value = iter_value.flatten(); diff --git a/src/lib.rs b/src/lib.rs index b024ca69..dd277a73 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -85,7 +85,7 @@ mod utils; pub use any::Dynamic; pub use engine::{Engine, EvalContext}; pub use error::{ParseError, ParseErrorType}; -pub use fn_native::{FnPtr, IteratorFn}; +pub use fn_native::FnPtr; pub use fn_register::{RegisterFn, RegisterResultFn}; pub use module::Module; pub use parser::{ImmutableString, AST, INT}; diff --git a/src/module/mod.rs b/src/module/mod.rs index 566b678d..ed135f71 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -1468,6 +1468,24 @@ impl Module { self } + /// Set a type iterator into the module. + pub fn set_iterable, U: Variant + Clone>( + &mut self, + ) -> &mut Self { + self.set_iter(TypeId::of::(), |obj: Dynamic| { + Box::new(obj.cast::().into_iter().map(Dynamic::from)) + }) + } + + /// Set an iterator type into the module as a type iterator. + pub fn set_iterator, U: Variant + Clone>( + &mut self, + ) -> &mut Self { + self.set_iter(TypeId::of::(), |obj: Dynamic| { + Box::new(obj.cast::().map(Dynamic::from)) + }) + } + /// Get the specified type iterator. pub(crate) fn get_iter(&self, id: TypeId) -> Option { self.type_iterators.get(&id).cloned() diff --git a/src/packages/array_basic.rs b/src/packages/array_basic.rs index d688ef3a..43543ad8 100644 --- a/src/packages/array_basic.rs +++ b/src/packages/array_basic.rs @@ -86,10 +86,7 @@ def_package!(crate:BasicArrayPackage:"Basic array utilities.", lib, { combine_with_exported_module!(lib, "array", array_functions); // Register array iterator - lib.set_iter( - TypeId::of::(), - |arr| Box::new(arr.cast::().into_iter()) as Box>, - ); + lib.set_iterable::(); }); #[export_module] diff --git a/src/packages/iter_basic.rs b/src/packages/iter_basic.rs index 8914c6a5..eaf74fe0 100644 --- a/src/packages/iter_basic.rs +++ b/src/packages/iter_basic.rs @@ -1,23 +1,16 @@ -use crate::any::{Dynamic, Variant}; +use crate::any::Variant; use crate::def_package; use crate::module::{FuncReturn, Module}; use crate::parser::INT; -use crate::stdlib::{ - any::TypeId, - boxed::Box, - ops::{Add, Range}, -}; +use crate::stdlib::ops::{Add, Range}; // Register range function fn reg_range(lib: &mut Module) where Range: Iterator, { - lib.set_iter(TypeId::of::>(), |source| { - Box::new(source.cast::>().map(|x| x.into_dynamic())) - as Box> - }); + lib.set_iterator::, T>(); } fn get_range(from: T, to: T) -> FuncReturn> { @@ -55,10 +48,7 @@ where T: Variant + Clone + PartialOrd, StepRange: Iterator, { - lib.set_iter(TypeId::of::>(), |source| { - Box::new(source.cast::>().map(|x| x.into_dynamic())) - as Box> - }); + lib.set_iterator::, T>(); } fn get_step_range(from: T, to: T, step: T) -> FuncReturn> diff --git a/src/packages/string_more.rs b/src/packages/string_more.rs index c799e221..e3b78292 100644 --- a/src/packages/string_more.rs +++ b/src/packages/string_more.rs @@ -108,9 +108,7 @@ def_package!(crate:MoreStringPackage:"Additional string utilities, including str // Register string iterator lib.set_iter( TypeId::of::(), - |arr| Box::new( - arr.cast::().chars().collect::>().into_iter().map(Into::into) - ) as Box>, + |s: Dynamic| Box::new(s.cast::().chars().collect::>().into_iter().map(Into::into)) ); });