diff --git a/src/engine.rs b/src/engine.rs index 7a57d972..8c710c69 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1893,7 +1893,7 @@ impl Engine { if mods .scan_raw() .skip(_mods_len) - .any(|(_, m)| m.has_namespace(crate::FnNamespace::Global, true)) + .any(|(_, m)| m.contains_indexed_global_functions()) { if _restore_fn_resolution_cache { // When new module is imported with global functions and there is already diff --git a/src/fn_call.rs b/src/fn_call.rs index 18d11447..6a3db275 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -188,42 +188,6 @@ impl Engine { allow_dynamic: bool, is_op_assignment: bool, ) -> &'s Option<(CallableFunction, Option)> { - fn find_function( - engine: &Engine, - hash: NonZeroU64, - mods: &Imports, - lib: &[&Module], - ) -> Option<(CallableFunction, Option)> { - lib.iter() - .find_map(|m| { - m.get_fn(hash, false) - .map(|f| (f.clone(), m.id_raw().cloned())) - }) - .or_else(|| { - engine - .global_namespace - .get_fn(hash, false) - .cloned() - .map(|f| (f, None)) - }) - .or_else(|| { - engine.global_modules.iter().find_map(|m| { - m.get_fn(hash, false) - .map(|f| (f.clone(), m.id_raw().cloned())) - }) - }) - .or_else(|| { - mods.get_fn(hash) - .map(|(f, source)| (f.clone(), source.cloned())) - }) - .or_else(|| { - engine.global_sub_modules.values().find_map(|m| { - m.get_qualified_fn(hash) - .map(|f| (f.clone(), m.id_raw().cloned())) - }) - }) - } - &*state .fn_resolution_cache_mut() .entry(hash) @@ -237,7 +201,36 @@ impl Engine { let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic` loop { - match find_function(self, hash, mods, lib) { + let func = lib + .iter() + .find_map(|m| { + m.get_fn(hash, false) + .map(|f| (f.clone(), m.id_raw().cloned())) + }) + .or_else(|| { + self.global_namespace + .get_fn(hash, false) + .cloned() + .map(|f| (f, None)) + }) + .or_else(|| { + self.global_modules.iter().find_map(|m| { + m.get_fn(hash, false) + .map(|f| (f.clone(), m.id_raw().cloned())) + }) + }) + .or_else(|| { + mods.get_fn(hash) + .map(|(f, source)| (f.clone(), source.cloned())) + }) + .or_else(|| { + self.global_sub_modules.values().find_map(|m| { + m.get_qualified_fn(hash) + .map(|f| (f.clone(), m.id_raw().cloned())) + }) + }); + + match func { // Specific version found Some(f) => return Some(f), @@ -520,18 +513,16 @@ impl Engine { ); // Merge in encapsulated environment, if any - let mut lib_merged: StaticVec<_>; - let mut unified = false; + let lib_merged; - let unified_lib = if let Some(ref env_lib) = fn_def.lib { - unified = true; + let (unified_lib, unified) = if let Some(ref env_lib) = fn_def.lib { state.push_fn_resolution_cache(); - lib_merged = Default::default(); - lib_merged.push(env_lib.as_ref()); - lib_merged.extend(lib.iter().cloned()); - lib_merged.as_ref() + lib_merged = once(env_lib.as_ref()) + .chain(lib.iter().cloned()) + .collect::>(); + (lib_merged.as_ref(), true) } else { - lib + (lib, false) }; #[cfg(not(feature = "no_module"))] diff --git a/src/module/mod.rs b/src/module/mod.rs index 0c3a0041..6bcdf3d8 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -127,6 +127,8 @@ pub struct Module { all_type_iterators: HashMap, /// Is the [`Module`] indexed? indexed: bool, + /// Does the [`Module`] contain indexed functions that have been exposed to the global namespace? + contains_indexed_global_functions: bool, } impl Default for Module { @@ -141,6 +143,7 @@ impl Default for Module { type_iterators: Default::default(), all_type_iterators: Default::default(), indexed: false, + contains_indexed_global_functions: false, } } } @@ -434,6 +437,7 @@ impl Module { ) -> &mut Self { self.variables.insert(name.into(), Dynamic::from(value)); self.indexed = false; + self.contains_indexed_global_functions = false; self } @@ -477,6 +481,7 @@ impl Module { }, ); self.indexed = false; + self.contains_indexed_global_functions = false; hash_script } @@ -521,6 +526,7 @@ impl Module { self.all_variables.clear(); self.all_type_iterators.clear(); self.indexed = false; + self.contains_indexed_global_functions = false; &mut self.modules } @@ -581,6 +587,7 @@ impl Module { ) -> &mut Self { self.modules.insert(name.into(), sub_module.into()); self.indexed = false; + self.contains_indexed_global_functions = false; self } @@ -649,6 +656,7 @@ impl Module { f.namespace = namespace; } self.indexed = false; + self.contains_indexed_global_functions = false; self } @@ -704,6 +712,7 @@ impl Module { ); self.indexed = false; + self.contains_indexed_global_functions = false; hash_fn } @@ -1497,6 +1506,7 @@ impl Module { self.all_variables.clear(); self.all_type_iterators.clear(); self.indexed = false; + self.contains_indexed_global_functions = false; self } @@ -1515,6 +1525,7 @@ impl Module { self.all_variables.clear(); self.all_type_iterators.clear(); self.indexed = false; + self.contains_indexed_global_functions = false; self } @@ -1542,6 +1553,7 @@ impl Module { self.all_variables.clear(); self.all_type_iterators.clear(); self.indexed = false; + self.contains_indexed_global_functions = false; self } @@ -1602,6 +1614,7 @@ impl Module { self.all_variables.clear(); self.all_type_iterators.clear(); self.indexed = false; + self.contains_indexed_global_functions = false; self } @@ -1634,6 +1647,7 @@ impl Module { self.all_variables.clear(); self.all_type_iterators.clear(); self.indexed = false; + self.contains_indexed_global_functions = false; self } @@ -1820,29 +1834,14 @@ impl Module { Ok(module) } - /// Are there functions (or type iterators) marked for the specified namespace? - pub fn has_namespace(&self, namespace: FnNamespace, recursive: bool) -> bool { - // Type iterators are default global - if !self.type_iterators.is_empty() { - return true; - } - // Any function marked global? - if self.functions.values().any(|f| f.namespace == namespace) { - return true; - } - - // Scan sub-modules - if recursive { - if self - .modules - .values() - .any(|m| m.has_namespace(namespace, recursive)) - { - return true; - } - } - - false + /// Does the [`Module`] contain indexed functions that have been exposed to the global namespace? + /// + /// # Panics + /// + /// Panics if the [`Module`] is not yet indexed via [`build_index`][Module::build_index]. + #[inline(always)] + pub fn contains_indexed_global_functions(&self) -> bool { + self.contains_indexed_global_functions } /// Scan through all the sub-modules in the [`Module`] and build a hash index of all @@ -1857,11 +1856,15 @@ impl Module { variables: &mut HashMap, functions: &mut HashMap, type_iterators: &mut HashMap, - ) { + ) -> bool { + let mut contains_indexed_global_functions = false; + module.modules.iter().for_each(|(name, m)| { // Index all the sub-modules first. qualifiers.push(name); - index_module(m, qualifiers, variables, functions, type_iterators); + if index_module(m, qualifiers, variables, functions, type_iterators) { + contains_indexed_global_functions = true; + } qualifiers.pop(); }); @@ -1875,6 +1878,7 @@ impl Module { // Index type iterators module.type_iterators.iter().for_each(|(&type_id, func)| { type_iterators.insert(type_id, func.clone()); + contains_indexed_global_functions = true; }); // Index all Rust functions @@ -1895,6 +1899,7 @@ impl Module { FnNamespace::Global => { // Flatten all functions with global namespace functions.insert(hash, func.clone()); + contains_indexed_global_functions = true; } FnNamespace::Internal => (), } @@ -1927,6 +1932,8 @@ impl Module { } }, ); + + contains_indexed_global_functions } if !self.indexed { @@ -1937,7 +1944,7 @@ impl Module { qualifiers.push("root"); - index_module( + self.contains_indexed_global_functions = index_module( self, &mut qualifiers, &mut variables, @@ -1968,6 +1975,7 @@ impl Module { pub fn set_iter(&mut self, typ: TypeId, func: IteratorFn) -> &mut Self { self.type_iterators.insert(typ, func); self.indexed = false; + self.contains_indexed_global_functions = false; self } diff --git a/tests/modules.rs b/tests/modules.rs index c42111b6..44f277e6 100644 --- a/tests/modules.rs +++ b/tests/modules.rs @@ -24,10 +24,12 @@ fn test_module_sub_module() -> Result<(), Box> { sub_module2.set_var("answer", 41 as INT); let hash_inc = sub_module2.set_fn_1_mut("inc", FnNamespace::Internal, |x: &mut INT| Ok(*x + 1)); - assert!(!sub_module2.has_namespace(FnNamespace::Global, true)); + sub_module2.build_index(); + assert!(!sub_module2.contains_indexed_global_functions()); sub_module2.set_fn_1_mut("super_inc", FnNamespace::Global, |x: &mut INT| Ok(*x + 1)); - assert!(sub_module2.has_namespace(FnNamespace::Global, true)); + sub_module2.build_index(); + assert!(sub_module2.contains_indexed_global_functions()); #[cfg(not(feature = "no_object"))] sub_module2.set_getter_fn("doubled", |x: &mut INT| Ok(*x * 2)); @@ -35,9 +37,9 @@ fn test_module_sub_module() -> Result<(), Box> { sub_module.set_sub_module("universe", sub_module2); module.set_sub_module("life", sub_module); module.set_var("MYSTIC_NUMBER", Dynamic::from(42 as INT)); + module.build_index(); - assert!(module.has_namespace(FnNamespace::Global, true)); - assert!(!module.has_namespace(FnNamespace::Global, false)); + assert!(module.contains_indexed_global_functions()); assert!(module.contains_sub_module("life")); let m = module.get_sub_module("life").unwrap();