diff --git a/RELEASES.md b/RELEASES.md index 422a5ef5..d377aa7c 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -13,6 +13,7 @@ Enhancements ------------ * Source information is provided when there is an error within a call to a function defined in another module. +* Source information is provided to the `NativeCallContext` for native Rust functions. Version 0.19.9 diff --git a/src/engine.rs b/src/engine.rs index 00bce1c7..0eb1fc49 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -126,11 +126,14 @@ impl Imports { } /// Get specified function via its hash key. #[inline(always)] - pub fn get_fn(&self, hash: NonZeroU64) -> Option<&CallableFunction> { + pub fn get_fn( + &self, + hash: NonZeroU64, + ) -> Option<(&CallableFunction, &Option)> { self.0 .iter() .rev() - .find_map(|(_, m)| m.get_qualified_fn(hash)) + .find_map(|(_, m)| m.get_qualified_fn(hash).map(|f| (f, m.id_raw()))) } /// Does the specified [`TypeId`][std::any::TypeId] iterator exist in this stack of imported [modules][Module]? #[allow(dead_code)] @@ -2046,15 +2049,16 @@ impl Engine { match self .global_namespace .get_fn(hash_fn, false) + .map(|f| (f, None)) .or_else(|| { - self.global_modules - .iter() - .find_map(|m| m.get_fn(hash_fn, false)) + self.global_modules.iter().find_map(|m| { + m.get_fn(hash_fn, false).map(|f| (f, m.id_raw().as_ref())) + }) }) - .or_else(|| mods.get_fn(hash_fn)) + .or_else(|| mods.get_fn(hash_fn).map(|(f, source)| (f, source.as_ref()))) { // op= function registered as method - Some(func) if func.is_method() => { + Some((func, source)) if func.is_method() => { let mut lock_guard; let lhs_ptr_inner; @@ -2068,14 +2072,16 @@ impl Engine { let args = &mut [lhs_ptr_inner, &mut rhs_val]; // Overriding exact implementation + let source = if source.is_none() { + state.source.as_ref() + } else { + source + }; if func.is_plugin_fn() { func.get_plugin_fn() - .call((self, &state.source, &*mods, lib).into(), args)?; + .call((self, source, &*mods, lib).into(), args)?; } else { - func.get_native_fn()( - (self, &state.source, &*mods, lib).into(), - args, - )?; + func.get_native_fn()((self, source, &*mods, lib).into(), args)?; } } // Built-in op-assignment function diff --git a/src/fn_call.rs b/src/fn_call.rs index 85da3fcb..38c0dc89 100644 --- a/src/fn_call.rs +++ b/src/fn_call.rs @@ -176,15 +176,14 @@ impl Engine { self.inc_operations(state, pos)?; // Check if function access already in the cache - if !state.functions_cache.contains_key(&hash_fn) { + let func = &*state.functions_cache.entry(hash_fn).or_insert_with(|| { // Search for the native function // First search registered functions (can override packages) // Then search packages // Finally search modules //lib.get_fn(hash_fn, pub_only) - let f = self - .global_namespace + self.global_namespace .get_fn(hash_fn, pub_only) .cloned() .map(|f| (f, None)) @@ -195,13 +194,11 @@ impl Engine { .map(|f| (f, m.id_raw().clone())) }) }) - .or_else(|| mods.get_fn(hash_fn).cloned().map(|f| (f, None))); - - // Store into cache - state.functions_cache.insert(hash_fn, f); - } - - let func = state.functions_cache.get(&hash_fn).unwrap(); + .or_else(|| { + mods.get_fn(hash_fn) + .map(|(f, source)| (f.clone(), source.clone())) + }) + }); if let Some((func, source)) = func { assert!(func.is_native()); @@ -212,9 +209,9 @@ impl Engine { // Run external function let source = if source.is_none() { - &state.source + state.source.as_ref() } else { - source + source.as_ref() }; let result = if func.is_plugin_fn() { func.get_plugin_fn() @@ -1240,10 +1237,10 @@ impl Engine { result } - Some(f) if f.is_plugin_fn() => f - .get_plugin_fn() - .clone() - .call((self, module.id_raw(), &*mods, lib).into(), args.as_mut()), + Some(f) if f.is_plugin_fn() => f.get_plugin_fn().clone().call( + (self, module.id_raw().as_ref(), &*mods, lib).into(), + args.as_mut(), + ), Some(f) if f.is_native() => { if !f.is_method() { // Clone first argument @@ -1254,7 +1251,10 @@ impl Engine { } } - f.get_native_fn()((self, module.id_raw(), &*mods, lib).into(), args.as_mut()) + f.get_native_fn()( + (self, module.id_raw().as_ref(), &*mods, lib).into(), + args.as_mut(), + ) } Some(f) => unreachable!("unknown function type: {:?}", f), None if def_val.is_some() => Ok(def_val.unwrap().clone()), diff --git a/src/fn_native.rs b/src/fn_native.rs index 261a3935..6144ac5e 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -63,14 +63,14 @@ pub struct NativeCallContext<'e, 's, 'a, 'm, 'pm: 'm> { } impl<'e, 's, 'a, 'm, 'pm: 'm, M: AsRef<[&'pm Module]> + ?Sized> - From<(&'e Engine, &'s Option, &'a Imports, &'m M)> + From<(&'e Engine, Option<&'s ImmutableString>, &'a Imports, &'m M)> for NativeCallContext<'e, 's, 'a, 'm, 'pm> { #[inline(always)] - fn from(value: (&'e Engine, &'s Option, &'a Imports, &'m M)) -> Self { + fn from(value: (&'e Engine, Option<&'s ImmutableString>, &'a Imports, &'m M)) -> Self { Self { engine: value.0, - source: value.1.as_ref().map(|s| s.as_str()), + source: value.1.map(|s| s.as_str()), mods: Some(value.2), lib: value.3.as_ref(), }