diff --git a/src/engine.rs b/src/engine.rs index 6f6c6009..00532895 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -176,9 +176,17 @@ impl<'a> State<'a> { } } +/// An external native Rust function. +#[cfg(not(feature = "sync"))] +pub type NativeFunction = Rc>; +/// An external native Rust function. +#[cfg(feature = "sync")] +pub type NativeFunction = Arc>; + /// A sharable script-defined function. #[cfg(feature = "sync")] pub type ScriptedFunction = Arc; +/// A sharable script-defined function. #[cfg(not(feature = "sync"))] pub type ScriptedFunction = Rc; @@ -512,6 +520,15 @@ impl Engine { self.packages.push(package); } + /// Load a new package into the `Engine`. + /// + /// When searching for functions, packages loaded later are preferred. + /// In other words, loaded packages are searched in reverse order. + pub fn load_packages(&mut self, package: PackageLibrary) { + // Push the package to the top - packages are searched in reverse order + self.packages.push(package); + } + /// Control whether and how the `Engine` will optimize an AST after compilation. /// /// Not available under the `no_optimize` feature. diff --git a/src/module.rs b/src/module.rs index 53af8e4d..a1721835 100644 --- a/src/module.rs +++ b/src/module.rs @@ -3,7 +3,7 @@ use crate::any::{Dynamic, Variant}; use crate::calc_fn_hash; -use crate::engine::{Engine, FnAny, FnCallArgs, FunctionsLib, ScriptedFunction}; +use crate::engine::{Engine, FnAny, FnCallArgs, FunctionsLib, NativeFunction, ScriptedFunction}; use crate::parser::{FnDef, AST}; use crate::result::EvalAltResult; use crate::scope::{Entry as ScopeEntry, EntryType as ScopeEntryType, Scope}; @@ -25,11 +25,6 @@ use crate::stdlib::{ vec::Vec, }; -#[cfg(not(feature = "sync"))] -type NativeFunction = Rc>; -#[cfg(feature = "sync")] -type NativeFunction = Arc>; - /// A trait that encapsulates a module resolution service. pub trait ModuleResolver { /// Resolve a module based on a path string. diff --git a/src/packages/mod.rs b/src/packages/mod.rs index c9be4487..0d935e40 100644 --- a/src/packages/mod.rs +++ b/src/packages/mod.rs @@ -34,11 +34,10 @@ pub use time_basic::BasicTimePackage; pub use utils::*; +const NUM_NATIVE_FUNCTIONS: usize = 512; + /// Trait that all packages must implement. pub trait Package { - /// Create a new instance of a package. - fn new() -> Self; - /// Register all the functions in a package into a store. fn init(lib: &mut PackageStore); @@ -47,7 +46,6 @@ pub trait Package { } /// Type to store all functions in the package. -#[derive(Default)] pub struct PackageStore { /// All functions, keyed by a hash created from the function name and parameter types. pub functions: HashMap>, @@ -61,14 +59,6 @@ impl PackageStore { pub fn new() -> Self { Default::default() } - /// Get an iterator over the keys of the functions in the `PackageStore`. - pub fn function_keys(&self) -> impl Iterator { - self.functions.keys() - } - /// Get an iterator over the `TypeId` of the type iterators in the `PackageStore`. - pub fn type_iterator_keys(&self) -> impl Iterator { - self.type_iterators.keys() - } /// Does the specified function hash key exist in the `PackageStore`? pub fn contains_function(&self, hash: u64) -> bool { self.functions.contains_key(&hash) @@ -87,6 +77,15 @@ impl PackageStore { } } +impl Default for PackageStore { + fn default() -> Self { + Self { + functions: HashMap::with_capacity(NUM_NATIVE_FUNCTIONS), + type_iterators: HashMap::with_capacity(4), + } + } +} + /// Type which `Rc`-wraps a `PackageStore` to facilitate sharing library instances. #[cfg(not(feature = "sync"))] pub type PackageLibrary = Rc; @@ -95,48 +94,42 @@ pub type PackageLibrary = Rc; #[cfg(feature = "sync")] pub type PackageLibrary = Arc; -#[derive(Default)] /// Type containing a collection of `PackageLibrary` instances. /// All function and type iterator keys in the loaded packages are indexed for fast access. +#[derive(Clone, Default)] pub(crate) struct PackagesCollection { /// Collection of `PackageLibrary` instances. packages: Vec, - /// Index of all function keys, pointing to the offset in `packages`. - function_keys: HashMap, - /// Index of all type iterator `TypeId`'s, pointing to the offset in `packages`. - iterator_types: HashMap, } impl PackagesCollection { /// Add a `PackageLibrary` into the `PackagesCollection`. pub fn push(&mut self, package: PackageLibrary) { - let index = self.packages.len(); - package.function_keys().for_each(|&hash| { - self.function_keys.insert(hash, index); - }); - package.type_iterator_keys().for_each(|&id| { - self.iterator_types.insert(id, index); - }); - self.packages.push(package); + // Later packages override previous ones. + self.packages.insert(0, package); } /// Does the specified function hash key exist in the `PackagesCollection`? pub fn contains_function(&self, hash: u64) -> bool { - self.function_keys.contains_key(&hash) + self.packages.iter().any(|p| p.contains_function(hash)) } /// Get specified function via its hash key. pub fn get_function(&self, hash: u64) -> Option<&Box> { - self.function_keys - .get(&hash) - .and_then(|&index| self.packages[index].functions.get(&hash)) + self.packages + .iter() + .map(|p| p.get_function(hash)) + .find(|f| f.is_some()) + .flatten() } /// Does the specified TypeId iterator exist in the `PackagesCollection`? pub fn contains_iterator(&self, id: TypeId) -> bool { - self.iterator_types.contains_key(&id) + self.packages.iter().any(|p| p.contains_iterator(id)) } /// Get the specified TypeId iterator. pub fn get_iterator(&self, id: TypeId) -> Option<&Box> { - self.iterator_types - .get(&id) - .and_then(|&index| self.packages[index].type_iterators.get(&id)) + self.packages + .iter() + .map(|p| p.get_iterator(id)) + .find(|f| f.is_some()) + .flatten() } } diff --git a/src/packages/utils.rs b/src/packages/utils.rs index f8c60f2c..fbb8c31d 100644 --- a/src/packages/utils.rs +++ b/src/packages/utils.rs @@ -44,12 +44,6 @@ macro_rules! def_package { pub struct $package($root::packages::PackageLibrary); impl $root::packages::Package for $package { - fn new() -> Self { - let mut pkg = $root::packages::PackageStore::new(); - Self::init(&mut pkg); - Self(pkg.into()) - } - fn get(&self) -> $root::packages::PackageLibrary { self.0.clone() } @@ -58,6 +52,14 @@ macro_rules! def_package { $block } } + + impl $package { + pub fn new() -> Self { + let mut pkg = $root::packages::PackageStore::new(); + ::init(&mut pkg); + Self(pkg.into()) + } + } }; }