From bf86cf2b992873f7fc1551b59cc5dc59380b539b Mon Sep 17 00:00:00 2001 From: Destiny Hailstorm <26828397+djgaven588@users.noreply.github.com> Date: Thu, 24 Jul 2025 04:26:36 -0400 Subject: [PATCH 1/3] First trial round --- Cargo.toml | 4 +-- src/api/call_fn.rs | 43 +++++++++++++------------- src/api/formatting.rs | 26 ++++++++-------- src/func/call.rs | 62 +++++++++++++++++++++++--------------- src/func/func_args.rs | 24 ++++++++++++--- src/func/hashing.rs | 3 -- src/func/script.rs | 4 +-- src/module/mod.rs | 23 ++++++++------ src/packages/time_basic.rs | 2 +- src/types/dynamic.rs | 8 ++--- src/types/interner.rs | 3 -- 11 files changed, 111 insertions(+), 91 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4b5b36eaf..0754b0277 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,7 +29,7 @@ rhai_codegen = { version = "3.1.0", path = "codegen" } no-std-compat = { git = "https://gitlab.com/jD91mZM2/no-std-compat.git", version = "0.4.1", default-features = false, features = ["alloc"], optional = true } libm = { version = "0.2.0", default-features = false, optional = true } -hashbrown = { version = "0.15.0", optional = true } +hashbrown = { version = "0.15.0" } core-error = { version = "0.0.0", default-features = false, features = ["alloc"], optional = true } serde = { version = "1.0.136", default-features = false, features = ["derive", "alloc"], optional = true } serde_json = { version = "1.0.45", default-features = false, features = ["alloc"], optional = true } @@ -113,7 +113,7 @@ no_optimize = [] #! ### Compiling for `no-std` ## Turn on `no-std` compilation (nightly only). -no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "hashbrown", "no_time"] +no_std = ["no-std-compat", "num-traits/libm", "core-error", "libm", "no_time"] #! ### JavaScript Interface for WASM diff --git a/src/api/call_fn.rs b/src/api/call_fn.rs index 01dcdf20d..7e9ef09db 100644 --- a/src/api/call_fn.rs +++ b/src/api/call_fn.rs @@ -223,7 +223,7 @@ impl Engine { let orig_tag = options.tag.map(|v| mem::replace(&mut global.tag, v)); - let mut this_ptr = options.this_ptr; + let this_ptr = options.this_ptr; #[cfg(not(feature = "no_module"))] let orig_embedded_module_resolver = @@ -259,28 +259,27 @@ impl Engine { #[cfg(not(feature = "no_closure"))] crate::func::ensure_no_data_race(name, args, false)?; - ast.shared_lib() - .get_script_fn(name, args.len()) - .map_or_else( - || Err(ERR::ErrorFunctionNotFound(name.into(), Position::NONE).into()), - |fn_def| { - self.call_script_fn( - global, - caches, - scope, - this_ptr.as_deref_mut(), - None, - fn_def, - args, - rewind_scope, - Position::NONE, - ) + if let Some(fn_def) = ast.shared_lib().get_script_fn(name, args.len()) { + match self.call_script_fn( + global, + caches, + scope, + this_ptr, + None, + fn_def, + args, + rewind_scope, + Position::NONE, + ) { + Ok(val) => Ok(val), + Err(err) => match *err { + ERR::Exit(out, ..) => Ok(out), + _ => Err(err), }, - ) - .or_else(|err| match *err { - ERR::Exit(out, ..) => Ok(out), - _ => Err(err), - }) + } + } else { + Err(ERR::ErrorFunctionNotFound(name.into(), Position::NONE).into()) + } }); #[cfg(feature = "debugging")] diff --git a/src/api/formatting.rs b/src/api/formatting.rs index d61bf1202..8fd96e5d1 100644 --- a/src/api/formatting.rs +++ b/src/api/formatting.rs @@ -203,20 +203,20 @@ impl Engine { #[inline] #[must_use] pub fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str { - self.global_modules - .iter() - .find_map(|m| m.get_custom_type_display_by_name(name)) - .or_else(|| { - #[cfg(not(feature = "no_module"))] - return self - .global_sub_modules - .values() - .find_map(|m| m.get_custom_type_display_by_name(name)); + for m in &self.global_modules { + if let Some(val) = m.get_custom_type_display_by_name(name) { + return val; + } + } + + #[cfg(not(feature = "no_module"))] + for m in self.global_sub_modules.values() { + if let Some(val) = m.get_custom_type_display_by_name(name) { + return val; + } + } - #[cfg(feature = "no_module")] - return None; - }) - .unwrap_or_else(|| map_std_type_name(name, true)) + map_std_type_name(name, true) } /// Format a Rust parameter type. diff --git a/src/func/call.rs b/src/func/call.rs index f5895ca7f..e49b28564 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -14,10 +14,7 @@ use crate::{ calc_fn_hash, calc_fn_hash_full, Dynamic, Engine, FnArgsVec, FnPtr, ImmutableString, Position, RhaiResult, RhaiResultOf, Scope, Shared, ERR, }; -#[cfg(feature = "no_std")] use hashbrown::hash_map::Entry; -#[cfg(not(feature = "no_std"))] -use std::collections::hash_map::Entry; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ @@ -170,9 +167,11 @@ impl Engine { args: Option<&mut FnCallArgs>, allow_dynamic: bool, ) -> Option<&'s FnResolutionCacheEntry> { - let mut hash = args.as_deref().map_or(hash_base, |args| { + let mut hash = if let Some(args) = &args { calc_fn_hash_full(hash_base, args.iter().map(|a| a.type_id())) - }); + } else { + hash_base + }; let cache = caches.fn_resolution_cache_mut(); @@ -185,33 +184,46 @@ impl Engine { let mut bitmask = 1usize; // Bitmask of which parameter to replace with `Dynamic` loop { + let mut func = None; // First check scripted functions in the AST or embedded environments #[cfg(not(feature = "no_function"))] - let func = _global - .lib - .iter() - .rev() - .find_map(|m| m.get_fn(hash).map(|f| (f, m.id_raw()))); - #[cfg(feature = "no_function")] - let func = None; + { + for m in 0.._global.lib.len() { + let m = &_global.lib[_global.lib.len() - m - 1]; + if let Some(f) = m.get_fn(hash) { + func = Some((f, m.id_raw())); + break; + } + } + } // Then check the global namespace - let func = func.or_else(|| { - self.global_modules - .iter() - .find_map(|m| m.get_fn(hash).map(|f| (f, m.id_raw()))) - }); + if func.is_none() { + for m in 0..self.global_modules.len() { + let m = &self.global_modules[self.global_modules.len() - m - 1]; + if let Some(f) = m.get_fn(hash) { + func = Some((f, m.id_raw())); + break; + } + } + } // Then check imported modules for global functions, then global sub-modules for global functions #[cfg(not(feature = "no_module"))] - let func = func - .or_else(|| _global.get_qualified_fn(hash, true)) - .or_else(|| { - self.global_sub_modules - .values() - .filter(|m| m.contains_indexed_global_functions()) - .find_map(|m| m.get_qualified_fn(hash).map(|f| (f, m.id_raw()))) - }); + if func.is_none() { + if let Some(val) = _global.get_qualified_fn(hash, true) { + func = Some(val); + } else { + for m in self.global_sub_modules.values() { + if m.contains_indexed_global_functions() { + if let Some(f) = m.get_qualified_fn(hash) { + func = Some((f, m.id_raw())); + break; + } + } + } + } + } if let Some((f, s)) = func { // Specific version found diff --git a/src/func/func_args.rs b/src/func/func_args.rs index 2413c0cf3..abf08c5d6 100644 --- a/src/func/func_args.rs +++ b/src/func/func_args.rs @@ -2,7 +2,7 @@ #![allow(non_snake_case)] -use crate::types::dynamic::Variant; +use crate::types::dynamic::{AccessMode, Union, Variant}; use crate::Dynamic; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -62,14 +62,26 @@ pub trait FuncArgs { impl FuncArgs for Vec { #[inline] fn parse>(self, args: &mut ARGS) { - args.extend(self.into_iter().map(Dynamic::from)); + args.extend(self.into_iter().map(|value| { + Dynamic(Union::Variant( + Box::new(Box::new(value)), + 0, + AccessMode::ReadWrite, + )) + })); } } impl FuncArgs for [T; N] { #[inline] fn parse>(self, args: &mut ARGS) { - args.extend(IntoIterator::into_iter(self).map(Dynamic::from)); + args.extend(IntoIterator::into_iter(self).map(|value| { + Dynamic(Union::Variant( + Box::new(Box::new(value)), + 0, + AccessMode::ReadWrite, + )) + })); } } @@ -82,7 +94,11 @@ macro_rules! impl_args { #[allow(unused_variables)] fn parse>(self, args: &mut ARGS) { let ($($p,)*) = self; - $(args.extend(Some(Dynamic::from($p)));)* + $(args.extend(Some(Dynamic(Union::Variant( + Box::new(Box::new($p)), + 0, + AccessMode::ReadWrite, + ))));)* } } diff --git a/src/func/hashing.rs b/src/func/hashing.rs index ab95f0740..7acc2df4c 100644 --- a/src/func/hashing.rs +++ b/src/func/hashing.rs @@ -8,11 +8,8 @@ use std::{ hash::{BuildHasher, Hash, Hasher}, }; -#[cfg(feature = "no_std")] pub type StraightHashMap = hashbrown::HashMap; -#[cfg(not(feature = "no_std"))] -pub type StraightHashMap = std::collections::HashMap; /// A hasher that only takes one single [`u64`] and returns it as a hash key. /// /// # Panics diff --git a/src/func/script.rs b/src/func/script.rs index 86024a39b..8142fe39b 100644 --- a/src/func/script.rs +++ b/src/func/script.rs @@ -26,7 +26,7 @@ impl Engine { global: &mut GlobalRuntimeState, caches: &mut Caches, scope: &mut Scope, - mut this_ptr: Option<&mut Dynamic>, + this_ptr: Option<&mut Dynamic>, _env: Option<&EncapsulatedEnviron>, fn_def: &ScriptFuncDef, args: &mut FnCallArgs, @@ -123,7 +123,7 @@ impl Engine { global, caches, scope, - this_ptr.as_deref_mut(), + this_ptr, fn_def.body.statements(), rewind_scope, ) diff --git a/src/module/mod.rs b/src/module/mod.rs index 08faa1c55..c46a14174 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -12,10 +12,7 @@ use crate::{ Identifier, ImmutableString, RhaiResultOf, Shared, SharedModule, SmartString, }; use bitflags::bitflags; -#[cfg(feature = "no_std")] use hashbrown::hash_map::Entry; -#[cfg(not(feature = "no_std"))] -use std::collections::hash_map::Entry; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ @@ -1028,11 +1025,14 @@ impl Module { /// /// assert_eq!(module.get_custom_type_display_by_name(name), Some("MyType")); /// ``` - #[inline] + #[inline(always)] #[must_use] pub fn get_custom_type_display_by_name(&self, type_name: &str) -> Option<&str> { - self.get_custom_type_by_name_raw(type_name) - .map(|typ| typ.display_name.as_str()) + if let Some(typ) = self.get_custom_type_by_name_raw(type_name) { + Some(typ.display_name.as_str()) + } else { + None + } } /// Get the display name of a registered custom type. /// @@ -1912,10 +1912,13 @@ impl Module { #[inline] #[must_use] pub(crate) fn get_fn(&self, hash_native: u64) -> Option<&RhaiFunc> { - self.functions - .as_ref() - .and_then(|m| m.get(&hash_native)) - .map(|(f, _)| f) + if let Some(funcs) = &self.functions { + if let Some(func) = funcs.get(&hash_native) { + return Some(&func.0); + } + } + + None } /// Can the particular function with [`Dynamic`] parameter(s) exist in the [`Module`]? diff --git a/src/packages/time_basic.rs b/src/packages/time_basic.rs index e57638994..89ca053da 100644 --- a/src/packages/time_basic.rs +++ b/src/packages/time_basic.rs @@ -224,7 +224,7 @@ mod time_functions { #[inline] fn subtract_impl(timestamp: Instant, seconds: INT) -> RhaiResultOf { if seconds < 0 { - add_inner(timestamp, u64::try_from(seconds.unsigned_abs()).unwrap()) + add_inner(timestamp, seconds.unsigned_abs()) } else { subtract_inner(timestamp, u64::try_from(seconds).unwrap()) } diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index e98492ba0..ffadab1c8 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -1403,11 +1403,7 @@ impl Dynamic { #[cfg(not(feature = "no_closure"))] reify! { value => |v: crate::Shared>| return v.into() } - Self(Union::Variant( - Box::new(Box::new(value)), - DEFAULT_TAG_VALUE, - ReadWrite, - )) + Self(Union::Variant(Box::new(Box::new(value)), 0, ReadWrite)) } /// Turn the [`Dynamic`] value into a shared [`Dynamic`] value backed by an /// [`Rc>`][std::rc::Rc] or [`Arc>`][std::sync::Arc] @@ -1594,7 +1590,7 @@ impl Dynamic { match self.0 { Union::Variant(v, ..) if TypeId::of::() == (**v).type_id() => { - Ok((*v).as_boxed_any().downcast().map(|x| *x).unwrap()) + Ok(*(*v).as_boxed_any().downcast().unwrap()) } _ => Err(self), } diff --git a/src/types/interner.rs b/src/types/interner.rs index e91d8df88..b187d2bd3 100644 --- a/src/types/interner.rs +++ b/src/types/interner.rs @@ -3,10 +3,7 @@ use super::BloomFilterU64; use crate::func::{hashing::get_hasher, StraightHashMap}; use crate::ImmutableString; -#[cfg(feature = "no_std")] use hashbrown::hash_map::Entry; -#[cfg(not(feature = "no_std"))] -use std::collections::hash_map::Entry; #[cfg(feature = "no_std")] use std::prelude::v1::*; use std::{ From de8498acbcb5bf3b7558f4124e6693c1728297d6 Mon Sep 17 00:00:00 2001 From: Destiny Hailstorm <26828397+djgaven588@users.noreply.github.com> Date: Thu, 24 Jul 2025 16:14:40 -0400 Subject: [PATCH 2/3] Trying to make functional again --- src/func/func_args.rs | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/src/func/func_args.rs b/src/func/func_args.rs index abf08c5d6..6a17a14e8 100644 --- a/src/func/func_args.rs +++ b/src/func/func_args.rs @@ -62,26 +62,14 @@ pub trait FuncArgs { impl FuncArgs for Vec { #[inline] fn parse>(self, args: &mut ARGS) { - args.extend(self.into_iter().map(|value| { - Dynamic(Union::Variant( - Box::new(Box::new(value)), - 0, - AccessMode::ReadWrite, - )) - })); + args.extend(self.into_iter().map(Dynamic::from)); } } impl FuncArgs for [T; N] { #[inline] fn parse>(self, args: &mut ARGS) { - args.extend(IntoIterator::into_iter(self).map(|value| { - Dynamic(Union::Variant( - Box::new(Box::new(value)), - 0, - AccessMode::ReadWrite, - )) - })); + args.extend(IntoIterator::into_iter(self).map(Dynamic::from)); } } @@ -94,11 +82,7 @@ macro_rules! impl_args { #[allow(unused_variables)] fn parse>(self, args: &mut ARGS) { let ($($p,)*) = self; - $(args.extend(Some(Dynamic(Union::Variant( - Box::new(Box::new($p)), - 0, - AccessMode::ReadWrite, - ))));)* + $(args.extend(Some(Dynamic::from($p)));)* } } From a2fc7ace5fd409bb7e1c034ac2a870245e2d5219 Mon Sep 17 00:00:00 2001 From: Destiny Hailstorm <26828397+djgaven588@users.noreply.github.com> Date: Thu, 24 Jul 2025 22:49:13 -0400 Subject: [PATCH 3/3] Second round --- src/eval/data_check.rs | 14 +++++++------- src/func/script.rs | 3 +-- src/parser.rs | 28 +++++++++++----------------- src/types/scope.rs | 22 +++++++++++----------- 4 files changed, 30 insertions(+), 37 deletions(-) diff --git a/src/eval/data_check.rs b/src/eval/data_check.rs index e8bef6b1c..efeb06889 100644 --- a/src/eval/data_check.rs +++ b/src/eval/data_check.rs @@ -194,12 +194,12 @@ impl Engine { return Err(ERR::ErrorTooManyOperations(pos).into()); } - self.progress - .as_ref() - .and_then(|progress| { - progress(global.num_operations) - .map(|token| Err(ERR::ErrorTerminated(token, pos).into())) - }) - .unwrap_or(Ok(())) + if let Some(progress) = &self.progress { + if let Some(token) = progress(global.num_operations) { + return Err(ERR::ErrorTerminated(token, pos).into()); + } + } + + Ok(()) } } diff --git a/src/func/script.rs b/src/func/script.rs index 8142fe39b..b34a481c4 100644 --- a/src/func/script.rs +++ b/src/func/script.rs @@ -102,8 +102,7 @@ impl Engine { }| { imports .iter() - .cloned() - .for_each(|(n, m)| global.push_import(n, m)); + .for_each(|(n, m)| global.push_import(n, m.clone())); global.lib.extend(lib.clone()); diff --git a/src/parser.rs b/src/parser.rs index 29139b55f..340888176 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3658,23 +3658,17 @@ impl Engine { args.push(fn_expr); - args.extend( - externals - .as_ref() - .iter() - .cloned() - .map(|Ident { name, pos }| { - let (index, is_func) = self.access_var(state, &name, pos); - let idx = match index { - Some(n) if !is_func => u8::try_from(n.get()).ok().and_then(NonZeroU8::new), - _ => None, - }; - #[cfg(not(feature = "no_module"))] - return Expr::Variable((index, name, <_>::default(), 0).into(), idx, pos); - #[cfg(feature = "no_module")] - return Expr::Variable((index, name).into(), idx, pos); - }), - ); + args.extend(externals.as_ref().iter().map(|Ident { name, pos }| { + let (index, is_func) = self.access_var(state, name, *pos); + let idx = match index { + Some(n) if !is_func => u8::try_from(n.get()).ok().and_then(NonZeroU8::new), + _ => None, + }; + #[cfg(not(feature = "no_module"))] + return Expr::Variable((index, name.clone(), <_>::default(), 0).into(), idx, *pos); + #[cfg(feature = "no_module")] + return Expr::Variable((index, name.clone()).into(), idx, pos); + })); let expr = FnCallExpr { #[cfg(not(feature = "no_module"))] diff --git a/src/types/scope.rs b/src/types/scope.rs index 9e2130687..e0bade97b 100644 --- a/src/types/scope.rs +++ b/src/types/scope.rs @@ -855,21 +855,21 @@ impl Scope<'_> { let len = self.len(); let mut scope = Self::new(); - self.names.iter().rev().enumerate().for_each(|(i, name)| { + let name_len = self.names.len(); + for i in 0..name_len { + let name = &self.names[name_len - i - 1]; if scope.names.contains(name) { - return; + continue; } - let index = len - 1 - i; - let v1 = &self.values[index]; - + let v1 = &self.values[len - i - 1]; scope.push_entry(name.clone(), v1.access_mode(), v1.clone()); - if self.aliases.len() > index { + if self.aliases.len() > i { scope.aliases.resize(scope.len() - 1, <_>::default()); - scope.aliases.push(self.aliases[index].clone()); + scope.aliases.push(self.aliases[i].clone()); } - }); + } scope } @@ -939,14 +939,14 @@ impl Scope<'_> { #[inline] #[allow(dead_code)] pub(crate) fn remove_range(&mut self, start: usize, len: usize) { - self.values.drain(start..start + len).for_each(|_| {}); - self.names.drain(start..start + len).for_each(|_| {}); + self.values.drain(start..start + len); + self.names.drain(start..start + len); if self.aliases.len() > start { if self.aliases.len() <= start + len { self.aliases.truncate(start); } else { - self.aliases.drain(start..start + len).for_each(|_| {}); + self.aliases.drain(start..start + len); } } }