Detect whether dynamic functions exist to save checking.
This commit is contained in:
parent
d6bfd8f617
commit
84b8e1ed87
@ -165,7 +165,7 @@ impl Engine {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resolve a function call.
|
/// Resolve a normal (non-qualified) function call.
|
||||||
///
|
///
|
||||||
/// Search order:
|
/// Search order:
|
||||||
/// 1) AST - script functions in the AST
|
/// 1) AST - script functions in the AST
|
||||||
@ -201,11 +201,8 @@ impl Engine {
|
|||||||
.entry(hash)
|
.entry(hash)
|
||||||
.or_insert_with(|| {
|
.or_insert_with(|| {
|
||||||
let num_args = args.as_ref().map_or(0, |a| a.len());
|
let num_args = args.as_ref().map_or(0, |a| a.len());
|
||||||
let max_bitmask = if !allow_dynamic {
|
let mut max_bitmask = 0; // One above maximum bitmask based on number of parameters.
|
||||||
0
|
// Set later when a specific matching function is not found.
|
||||||
} else {
|
|
||||||
1usize << usize::min(num_args, MAX_DYNAMIC_PARAMETERS)
|
|
||||||
};
|
|
||||||
let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic`
|
let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic`
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -247,12 +244,37 @@ impl Engine {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
match func {
|
|
||||||
// Specific version found
|
// Specific version found
|
||||||
Some(f) => return Some(f),
|
if let Some(f) = func {
|
||||||
|
return Some(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check `Dynamic` parameters for functions with parameters
|
||||||
|
if allow_dynamic && max_bitmask == 0 && num_args > 0 {
|
||||||
|
let is_dynamic = lib.iter().any(|&m| m.contains_dynamic_fn(hash_script))
|
||||||
|
|| self
|
||||||
|
.global_modules
|
||||||
|
.iter()
|
||||||
|
.any(|m| m.contains_dynamic_fn(hash_script));
|
||||||
|
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
|
let is_dynamic = is_dynamic
|
||||||
|
|| _global
|
||||||
|
.iter_imports_raw()
|
||||||
|
.any(|(_, m)| m.contains_dynamic_fn(hash_script))
|
||||||
|
|| self
|
||||||
|
.global_sub_modules
|
||||||
|
.values()
|
||||||
|
.any(|m| m.contains_dynamic_fn(hash_script));
|
||||||
|
|
||||||
|
// Set maximum bitmask when there are dynamic versions of the function
|
||||||
|
if is_dynamic {
|
||||||
|
max_bitmask = 1usize << usize::min(num_args, MAX_DYNAMIC_PARAMETERS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Stop when all permutations are exhausted
|
// Stop when all permutations are exhausted
|
||||||
None if bitmask >= max_bitmask => {
|
if bitmask >= max_bitmask {
|
||||||
if num_args != 2 {
|
if num_args != 2 {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
@ -270,19 +292,19 @@ impl Engine {
|
|||||||
} else {
|
} else {
|
||||||
let (first_arg, rest_args) = args.split_first().unwrap();
|
let (first_arg, rest_args) = args.split_first().unwrap();
|
||||||
|
|
||||||
get_builtin_op_assignment_fn(fn_name, *first_arg, rest_args[0])
|
get_builtin_op_assignment_fn(fn_name, *first_arg, rest_args[0]).map(
|
||||||
.map(|f| FnResolutionCacheEntry {
|
|f| FnResolutionCacheEntry {
|
||||||
func: CallableFunction::from_method(
|
func: CallableFunction::from_method(
|
||||||
Box::new(f) as Box<FnAny>
|
Box::new(f) as Box<FnAny>
|
||||||
),
|
),
|
||||||
source: None,
|
source: None,
|
||||||
})
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try all permutations with `Dynamic` wildcards
|
// Try all permutations with `Dynamic` wildcards
|
||||||
None => {
|
|
||||||
let hash_params = calc_fn_params_hash(
|
let hash_params = calc_fn_params_hash(
|
||||||
args.as_ref()
|
args.as_ref()
|
||||||
.expect("no permutations")
|
.expect("no permutations")
|
||||||
@ -302,8 +324,6 @@ impl Engine {
|
|||||||
|
|
||||||
bitmask += 1;
|
bitmask += 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
result.as_ref()
|
result.as_ref()
|
||||||
|
@ -7,7 +7,7 @@ use crate::func::{
|
|||||||
};
|
};
|
||||||
use crate::types::{dynamic::Variant, CustomTypesCollection};
|
use crate::types::{dynamic::Variant, CustomTypesCollection};
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes, Dynamic, Identifier,
|
calc_fn_hash, calc_fn_params_hash, calc_qualified_fn_hash, combine_hashes, Dynamic, Identifier,
|
||||||
ImmutableString, NativeCallContext, RhaiResultOf, Shared, StaticVec,
|
ImmutableString, NativeCallContext, RhaiResultOf, Shared, StaticVec,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
@ -241,11 +241,13 @@ pub struct Module {
|
|||||||
variables: BTreeMap<Identifier, Dynamic>,
|
variables: BTreeMap<Identifier, Dynamic>,
|
||||||
/// Flattened collection of all [`Module`] variables, including those in sub-modules.
|
/// Flattened collection of all [`Module`] variables, including those in sub-modules.
|
||||||
all_variables: BTreeMap<u64, Dynamic>,
|
all_variables: BTreeMap<u64, Dynamic>,
|
||||||
/// External Rust functions.
|
/// Functions (both native Rust and scripted).
|
||||||
functions: BTreeMap<u64, Box<FuncInfo>>,
|
functions: BTreeMap<u64, Box<FuncInfo>>,
|
||||||
/// Flattened collection of all external Rust functions, native or scripted.
|
/// Flattened collection of all functions, native Rust and scripted.
|
||||||
/// including those in sub-modules.
|
/// including those in sub-modules.
|
||||||
all_functions: BTreeMap<u64, CallableFunction>,
|
all_functions: BTreeMap<u64, CallableFunction>,
|
||||||
|
/// Native Rust functions (in scripted hash format) that contain [`Dynamic`] parameters.
|
||||||
|
dynamic_functions: BTreeSet<u64>,
|
||||||
/// Iterator functions, keyed by the type producing the iterator.
|
/// Iterator functions, keyed by the type producing the iterator.
|
||||||
type_iterators: BTreeMap<TypeId, Shared<IteratorFn>>,
|
type_iterators: BTreeMap<TypeId, Shared<IteratorFn>>,
|
||||||
/// Flattened collection of iterator functions, including those in sub-modules.
|
/// Flattened collection of iterator functions, including those in sub-modules.
|
||||||
@ -348,6 +350,7 @@ impl Module {
|
|||||||
all_variables: BTreeMap::new(),
|
all_variables: BTreeMap::new(),
|
||||||
functions: BTreeMap::new(),
|
functions: BTreeMap::new(),
|
||||||
all_functions: BTreeMap::new(),
|
all_functions: BTreeMap::new(),
|
||||||
|
dynamic_functions: BTreeSet::new(),
|
||||||
type_iterators: BTreeMap::new(),
|
type_iterators: BTreeMap::new(),
|
||||||
all_type_iterators: BTreeMap::new(),
|
all_type_iterators: BTreeMap::new(),
|
||||||
indexed: true,
|
indexed: true,
|
||||||
@ -417,6 +420,25 @@ impl Module {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Clear the [`Module`].
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.id.clear();
|
||||||
|
self.internal = false;
|
||||||
|
self.standard = false;
|
||||||
|
self.custom_types.clear();
|
||||||
|
self.modules.clear();
|
||||||
|
self.variables.clear();
|
||||||
|
self.all_variables.clear();
|
||||||
|
self.functions.clear();
|
||||||
|
self.all_functions.clear();
|
||||||
|
self.dynamic_functions.clear();
|
||||||
|
self.type_iterators.clear();
|
||||||
|
self.all_type_iterators.clear();
|
||||||
|
self.indexed = false;
|
||||||
|
self.contains_indexed_global_functions = false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Map a custom type to a friendly display name.
|
/// Map a custom type to a friendly display name.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
@ -964,6 +986,10 @@ impl Module {
|
|||||||
.collect();
|
.collect();
|
||||||
param_types.shrink_to_fit();
|
param_types.shrink_to_fit();
|
||||||
|
|
||||||
|
let is_dynamic = param_types
|
||||||
|
.iter()
|
||||||
|
.any(|&type_id| type_id == TypeId::of::<Dynamic>());
|
||||||
|
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
let (param_names, return_type_name) = {
|
let (param_names, return_type_name) = {
|
||||||
let mut names = _arg_names
|
let mut names = _arg_names
|
||||||
@ -982,6 +1008,11 @@ impl Module {
|
|||||||
|
|
||||||
let hash_fn = calc_native_fn_hash(None, name.as_ref(), ¶m_types);
|
let hash_fn = calc_native_fn_hash(None, name.as_ref(), ¶m_types);
|
||||||
|
|
||||||
|
if is_dynamic {
|
||||||
|
self.dynamic_functions
|
||||||
|
.insert(calc_fn_hash(name.as_ref(), param_types.len()));
|
||||||
|
}
|
||||||
|
|
||||||
self.functions.insert(
|
self.functions.insert(
|
||||||
hash_fn,
|
hash_fn,
|
||||||
FuncInfo {
|
FuncInfo {
|
||||||
@ -1444,19 +1475,30 @@ impl Module {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a Rust function.
|
/// Look up a Rust function by hash.
|
||||||
///
|
///
|
||||||
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
|
/// The [`u64`] hash is returned by the [`set_native_fn`][Module::set_native_fn] call.
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub(crate) fn get_fn(&self, hash_fn: u64) -> Option<&CallableFunction> {
|
pub(crate) fn get_fn(&self, hash_native: u64) -> Option<&CallableFunction> {
|
||||||
if !self.functions.is_empty() {
|
if !self.functions.is_empty() {
|
||||||
self.functions.get(&hash_fn).map(|f| &f.func)
|
self.functions.get(&hash_native).map(|f| &f.func)
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Does the particular function with [`Dynamic`] parameter(s) exist in the [`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 {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Does the particular namespace-qualified function exist in the [`Module`]?
|
/// Does the particular namespace-qualified function exist in the [`Module`]?
|
||||||
///
|
///
|
||||||
/// The [`u64`] hash is calculated by [`build_index`][Module::build_index].
|
/// The [`u64`] hash is calculated by [`build_index`][Module::build_index].
|
||||||
|
@ -25,6 +25,11 @@ impl CustomTypesCollection {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self(BTreeMap::new())
|
Self(BTreeMap::new())
|
||||||
}
|
}
|
||||||
|
/// Clear the [`CustomTypesCollection`].
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn clear(&mut self) {
|
||||||
|
self.0.clear();
|
||||||
|
}
|
||||||
/// Register a custom type.
|
/// Register a custom type.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn add(&mut self, type_name: impl Into<Identifier>, name: impl Into<Identifier>) {
|
pub fn add(&mut self, type_name: impl Into<Identifier>, name: impl Into<Identifier>) {
|
||||||
|
Loading…
Reference in New Issue
Block a user