diff --git a/src/api/compile.rs b/src/api/compile.rs index a23efc11..5accd0bc 100644 --- a/src/api/compile.rs +++ b/src/api/compile.rs @@ -193,10 +193,10 @@ impl Engine { /// # } /// ``` #[inline(always)] - pub fn compile_scripts_with_scope( + pub fn compile_scripts_with_scope>( &self, scope: &Scope, - scripts: &[impl AsRef], + scripts: impl AsRef<[S]>, ) -> ParseResult { self.compile_with_scope_and_optimization_level( scope, @@ -213,14 +213,16 @@ impl Engine { /// throughout the script _including_ functions. This allows functions to be optimized based on /// dynamic global constants. #[inline] - pub(crate) fn compile_with_scope_and_optimization_level( + pub(crate) fn compile_with_scope_and_optimization_level>( &self, scope: &Scope, - scripts: &[impl AsRef], + scripts: impl AsRef<[S]>, #[cfg(not(feature = "no_optimize"))] optimization_level: crate::OptimizationLevel, ) -> ParseResult { - let (stream, tokenizer_control) = - self.lex_raw(scripts, self.token_mapper.as_ref().map(Box::as_ref)); + let (stream, tokenizer_control) = self.lex_raw( + scripts.as_ref(), + self.token_mapper.as_ref().map(Box::as_ref), + ); let mut state = ParseState::new(self, tokenizer_control); self.parse( &mut stream.peekable(), diff --git a/src/api/custom_syntax.rs b/src/api/custom_syntax.rs index 782b6034..0558673d 100644 --- a/src/api/custom_syntax.rs +++ b/src/api/custom_syntax.rs @@ -209,9 +209,9 @@ impl Engine { /// Replacing one variable with another (i.e. adding a new variable and removing one variable at /// the same time so that the total _size_ of the [`Scope`][crate::Scope] is unchanged) also /// does NOT count, so `false` should be passed. - pub fn register_custom_syntax( + pub fn register_custom_syntax + Into>( &mut self, - symbols: &[impl AsRef + Into], + symbols: impl AsRef<[S]>, scope_may_be_changed: bool, func: impl Fn(&mut EvalContext, &[Expression]) -> RhaiResult + SendSync + 'static, ) -> ParseResult<&mut Self> { @@ -219,7 +219,7 @@ impl Engine { let mut segments = StaticVec::::new(); - for s in symbols { + for s in symbols.as_ref() { let s = s.as_ref().trim(); // Skip empty symbols diff --git a/src/api/mod.rs b/src/api/mod.rs index e42a489a..39045da7 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -213,7 +213,7 @@ impl Engine { /// ``` pub fn register_custom_operator( &mut self, - keyword: impl AsRef + Into, + keyword: impl AsRef, precedence: u8, ) -> Result<&mut Self, String> { let precedence = Precedence::new(precedence); @@ -247,7 +247,8 @@ impl Engine { } // Add to custom keywords - self.custom_keywords.insert(keyword.into(), precedence); + self.custom_keywords + .insert(keyword.as_ref().into(), precedence); Ok(self) } diff --git a/src/api/register.rs b/src/api/register.rs index e369ab0c..605192a7 100644 --- a/src/api/register.rs +++ b/src/api/register.rs @@ -165,7 +165,7 @@ impl Engine { pub fn register_raw_fn( &mut self, name: N, - arg_types: &[TypeId], + arg_types: impl AsRef<[TypeId]>, func: impl Fn(NativeCallContext, &mut FnCallArgs) -> RhaiResultOf + SendSync + 'static, ) -> &mut Self where @@ -346,7 +346,7 @@ impl Engine { name: impl AsRef, get_fn: impl Fn(&mut T) -> V + SendSync + 'static, ) -> &mut Self { - self.register_fn(&crate::engine::make_getter(name.as_ref()), get_fn) + self.register_fn(crate::engine::make_getter(name.as_ref()).as_str(), get_fn) } /// Register a getter function for a member of a registered type with the [`Engine`]. /// @@ -395,7 +395,7 @@ impl Engine { name: impl AsRef, get_fn: impl Fn(&mut T) -> RhaiResultOf + SendSync + 'static, ) -> &mut Self { - self.register_result_fn(&crate::engine::make_getter(name.as_ref()), get_fn) + self.register_result_fn(crate::engine::make_getter(name.as_ref()).as_str(), get_fn) } /// Register a setter function for a member of a registered type with the [`Engine`]. /// @@ -445,7 +445,7 @@ impl Engine { name: impl AsRef, set_fn: impl Fn(&mut T, V) + SendSync + 'static, ) -> &mut Self { - self.register_fn(&crate::engine::make_setter(name.as_ref()), set_fn) + self.register_fn(crate::engine::make_setter(name.as_ref()).as_str(), set_fn) } /// Register a setter function for a member of a registered type with the [`Engine`]. /// @@ -496,7 +496,7 @@ impl Engine { name: impl AsRef, set_fn: impl Fn(&mut T, V) -> RhaiResultOf<()> + SendSync + 'static, ) -> &mut Self { - self.register_result_fn(&crate::engine::make_setter(name.as_ref()), set_fn) + self.register_result_fn(crate::engine::make_setter(name.as_ref()).as_str(), set_fn) } /// Short-hand for registering both getter and setter functions /// of a registered type with the [`Engine`]. @@ -975,17 +975,17 @@ impl Engine { #[cfg(not(feature = "no_module"))] pub fn register_static_module( &mut self, - name: impl AsRef + Into, + name: impl AsRef, module: Shared, ) -> &mut Self { fn register_static_module_raw( root: &mut std::collections::BTreeMap>, - name: impl AsRef + Into, + name: &str, module: Shared, ) { let separator = crate::tokenizer::Token::DoubleColon.syntax(); - if !name.as_ref().contains(separator.as_ref()) { + if !name.contains(separator.as_ref()) { if !module.is_indexed() { // Index the module (making a clone copy if necessary) if it is not indexed let mut module = crate::func::native::shared_take_or_clone(module); @@ -995,7 +995,7 @@ impl Engine { root.insert(name.into(), module); } } else { - let mut iter = name.as_ref().splitn(2, separator.as_ref()); + let mut iter = name.splitn(2, separator.as_ref()); let sub_module = iter.next().expect("contains separator").trim(); let remainder = iter.next().expect("contains separator").trim(); @@ -1014,7 +1014,7 @@ impl Engine { } } - register_static_module_raw(&mut self.global_sub_modules, name, module); + register_static_module_raw(&mut self.global_sub_modules, name.as_ref(), module); self } /// _(metadata)_ Generate a list of all registered functions. diff --git a/src/engine.rs b/src/engine.rs index c6d44849..6754b9e9 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -626,8 +626,7 @@ impl GlobalRuntimeState { /// Get the index of a globally-imported [module][Module] by name. #[inline] #[must_use] - pub fn find_module(&self, name: impl AsRef) -> Option { - let name = name.as_ref(); + pub fn find_module(&self, name: &str) -> Option { let len = self.keys.len(); self.keys.iter().rev().enumerate().find_map(|(i, key)| { @@ -1041,26 +1040,32 @@ impl Default for Engine { /// Make getter function #[cfg(not(feature = "no_object"))] -#[inline] +#[inline(always)] #[must_use] -pub fn make_getter(id: &str) -> String { - format!("{}{}", FN_GET, id) +pub fn make_getter(id: &str) -> Identifier { + let mut buf = Identifier::new_const(); + buf.push_str(FN_GET); + buf.push_str(id); + buf } /// Make setter function #[cfg(not(feature = "no_object"))] -#[inline] +#[inline(always)] #[must_use] -pub fn make_setter(id: &str) -> String { - format!("{}{}", FN_SET, id) +pub fn make_setter(id: &str) -> Identifier { + let mut buf = Identifier::new_const(); + buf.push_str(FN_SET); + buf.push_str(id); + buf } /// Is this function an anonymous function? #[cfg(not(feature = "no_function"))] #[inline(always)] #[must_use] -pub fn is_anonymous_fn(fn_name: impl AsRef) -> bool { - fn_name.as_ref().starts_with(FN_ANONYMOUS) +pub fn is_anonymous_fn(fn_name: &str) -> bool { + fn_name.starts_with(FN_ANONYMOUS) } /// Print to `stdout` diff --git a/src/func/call.rs b/src/func/call.rs index fcc252fa..3bbe0e74 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -105,7 +105,7 @@ impl Drop for ArgBackup<'_> { #[cfg(not(feature = "no_closure"))] #[inline] pub fn ensure_no_data_race( - fn_name: impl AsRef, + fn_name: &str, args: &FnCallArgs, is_method_call: bool, ) -> RhaiResultOf<()> { @@ -116,7 +116,7 @@ pub fn ensure_no_data_race( .find(|(_, a)| a.is_locked()) { return Err(ERR::ErrorDataRace( - format!("argument #{} of function '{}'", n + 1, fn_name.as_ref()), + format!("argument #{} of function '{}'", n + 1, fn_name), Position::NONE, ) .into()); @@ -150,7 +150,7 @@ impl Engine { fn gen_call_signature( &self, namespace: Option<&Namespace>, - fn_name: impl AsRef, + fn_name: &str, args: &[&mut Dynamic], ) -> String { format!( @@ -161,7 +161,7 @@ impl Engine { } else { "" }, - fn_name.as_ref(), + fn_name, args.iter() .map(|a| if a.is::() { "&str | ImmutableString | String" @@ -187,7 +187,7 @@ impl Engine { global: &GlobalRuntimeState, state: &'s mut EvalState, lib: &[&Module], - fn_name: impl AsRef, + fn_name: &str, hash_script: u64, args: Option<&mut FnCallArgs>, allow_dynamic: bool, @@ -197,8 +197,6 @@ impl Engine { return None; } - let fn_name = fn_name.as_ref(); - let mut hash = args.as_ref().map_or(hash_script, |args| { combine_hashes( hash_script, @@ -332,7 +330,7 @@ impl Engine { global: &mut GlobalRuntimeState, state: &mut EvalState, lib: &[&Module], - name: impl AsRef, + name: &str, hash: u64, args: &mut FnCallArgs, is_ref_mut: bool, @@ -342,7 +340,6 @@ impl Engine { #[cfg(not(feature = "unchecked"))] self.inc_operations(&mut global.num_operations, pos)?; - let name = name.as_ref(); let parent_source = global.source.clone(); // Check if function access already in the cache @@ -521,7 +518,7 @@ impl Engine { global: &mut GlobalRuntimeState, state: &mut EvalState, lib: &[&Module], - fn_name: impl AsRef, + fn_name: &str, hashes: FnCallHashes, args: &mut FnCallArgs, is_ref_mut: bool, @@ -535,8 +532,6 @@ impl Engine { Err(ERR::ErrorRuntime(msg.into(), pos).into()) } - let fn_name = fn_name.as_ref(); - // Check for data race. #[cfg(not(feature = "no_closure"))] ensure_no_data_race(fn_name, args, is_ref_mut)?; @@ -717,14 +712,13 @@ impl Engine { global: &mut GlobalRuntimeState, state: &mut EvalState, lib: &[&Module], - fn_name: impl AsRef, + fn_name: &str, mut hash: FnCallHashes, target: &mut crate::engine::Target, (call_args, call_arg_pos): &mut (FnArgsVec, Position), pos: Position, level: usize, ) -> RhaiResultOf<(Dynamic, bool)> { - let fn_name = fn_name.as_ref(); let is_ref_mut = target.is_ref(); let (result, updated) = match fn_name { @@ -902,7 +896,7 @@ impl Engine { state: &mut EvalState, lib: &[&Module], this_ptr: &mut Option<&mut Dynamic>, - fn_name: impl AsRef, + fn_name: &str, args_expr: &[Expr], constants: &[Dynamic], hashes: FnCallHashes, @@ -910,7 +904,6 @@ impl Engine { capture_scope: bool, level: usize, ) -> RhaiResult { - let fn_name = fn_name.as_ref(); let mut a_expr = args_expr; let mut total_args = a_expr.len(); let mut curry = FnArgsVec::new_const(); @@ -1179,14 +1172,13 @@ impl Engine { lib: &[&Module], this_ptr: &mut Option<&mut Dynamic>, namespace: &Namespace, - fn_name: impl AsRef, + fn_name: &str, args_expr: &[Expr], constants: &[Dynamic], hash: u64, pos: Position, level: usize, ) -> RhaiResult { - let fn_name = fn_name.as_ref(); let mut arg_values = FnArgsVec::with_capacity(args_expr.len()); let mut args = FnArgsVec::with_capacity(args_expr.len()); let mut first_arg_value = None; @@ -1324,14 +1316,17 @@ impl Engine { global: &mut GlobalRuntimeState, state: &mut EvalState, lib: &[&Module], - script: impl AsRef, - _pos: Position, + script: &str, + pos: Position, level: usize, ) -> RhaiResult { + let _pos = pos; + #[cfg(not(feature = "unchecked"))] self.inc_operations(&mut global.num_operations, _pos)?; - let script = script.as_ref().trim(); + let script = script.trim(); + if script.is_empty() { return Ok(Dynamic::UNIT); } diff --git a/src/func/hashing.rs b/src/func/hashing.rs index 38a8b636..96bdba56 100644 --- a/src/func/hashing.rs +++ b/src/func/hashing.rs @@ -87,10 +87,7 @@ pub fn get_hasher() -> ahash::AHasher { /// The first module name is skipped. Hashing starts from the _second_ module in the chain. #[inline] #[must_use] -pub fn calc_qualified_var_hash<'a>( - modules: impl Iterator + 'a>, - var_name: impl AsRef, -) -> u64 { +pub fn calc_qualified_var_hash<'a>(modules: impl Iterator, var_name: &str) -> u64 { let s = &mut get_hasher(); // We always skip the first module @@ -98,9 +95,9 @@ pub fn calc_qualified_var_hash<'a>( modules .inspect(|_| len += 1) .skip(1) - .for_each(|m| m.as_ref().hash(s)); + .for_each(|m| m.hash(s)); len.hash(s); - var_name.as_ref().hash(s); + var_name.hash(s); match s.finish() { 0 => ALT_ZERO_HASH, @@ -123,9 +120,9 @@ pub fn calc_qualified_var_hash<'a>( /// The first module name is skipped. Hashing starts from the _second_ module in the chain. #[inline] #[must_use] -pub fn calc_qualified_fn_hash( - modules: impl Iterator>, - fn_name: impl AsRef, +pub fn calc_qualified_fn_hash<'a>( + modules: impl Iterator, + fn_name: &str, num: usize, ) -> u64 { let s = &mut get_hasher(); @@ -135,9 +132,9 @@ pub fn calc_qualified_fn_hash( modules .inspect(|_| len += 1) .skip(1) - .for_each(|m| m.as_ref().hash(s)); + .for_each(|m| m.hash(s)); len.hash(s); - fn_name.as_ref().hash(s); + fn_name.hash(s); num.hash(s); match s.finish() { @@ -156,8 +153,8 @@ pub fn calc_qualified_fn_hash( /// If the hash happens to be zero, it is mapped to `DEFAULT_HASH`. #[inline(always)] #[must_use] -pub fn calc_fn_hash(fn_name: impl AsRef, num: usize) -> u64 { - calc_qualified_fn_hash(empty::<&str>(), fn_name, num) +pub fn calc_fn_hash(fn_name: &str, num: usize) -> u64 { + calc_qualified_fn_hash(empty(), fn_name, num) } /// Calculate a non-zero [`u64`] hash key from a list of parameter types. diff --git a/src/func/native.rs b/src/func/native.rs index 1736bc8d..7d49fc84 100644 --- a/src/func/native.rs +++ b/src/func/native.rs @@ -287,15 +287,16 @@ impl<'a> NativeCallContext<'a> { args: &mut [&mut Dynamic], ) -> RhaiResult { let fn_name = fn_name.as_ref(); + let len = args.len(); let hash = if is_method_call { FnCallHashes::from_all( #[cfg(not(feature = "no_function"))] - calc_fn_hash(fn_name, args.len() - 1), - calc_fn_hash(fn_name, args.len()), + calc_fn_hash(fn_name, len - 1), + calc_fn_hash(fn_name, len), ) } else { - calc_fn_hash(fn_name, args.len()).into() + calc_fn_hash(fn_name, len).into() }; self.engine() diff --git a/src/module/mod.rs b/src/module/mod.rs index 9ac02eaf..3842c9ba 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -116,12 +116,12 @@ impl FuncInfo { /// /// The first module name is skipped. Hashing starts from the _second_ module in the chain. #[inline] -pub fn calc_native_fn_hash( - modules: impl Iterator>, - fn_name: impl AsRef, +pub fn calc_native_fn_hash<'a>( + modules: impl Iterator, + fn_name: &str, params: &[TypeId], ) -> u64 { - let hash_script = calc_qualified_fn_hash(modules, fn_name.as_ref(), params.len()); + let hash_script = calc_qualified_fn_hash(modules, fn_name, params.len()); let hash_params = calc_fn_params_hash(params.iter().cloned()); combine_hashes(hash_script, hash_params) } @@ -644,8 +644,13 @@ impl Module { /// In other words, the number of entries should be one larger than the number of parameters. #[cfg(feature = "metadata")] #[inline] - pub fn update_fn_metadata(&mut self, hash_fn: u64, arg_names: &[impl AsRef]) -> &mut Self { + pub fn update_fn_metadata>( + &mut self, + hash_fn: u64, + arg_names: impl AsRef<[S]>, + ) -> &mut Self { let mut param_names: StaticVec<_> = arg_names + .as_ref() .iter() .map(|name| self.interner.get("", name.as_ref()).into()) .collect(); @@ -689,17 +694,23 @@ impl Module { /// doc-comment leader: `///` or `/**`. #[cfg(feature = "metadata")] #[inline] - pub fn update_fn_metadata_with_comments( + pub fn update_fn_metadata_with_comments, C: AsRef>( &mut self, hash_fn: u64, - arg_names: &[impl AsRef], - comments: &[impl AsRef], + arg_names: impl AsRef<[A]>, + comments: impl AsRef<[C]>, ) -> &mut Self { self.update_fn_metadata(hash_fn, arg_names); - if !comments.is_empty() { + if !comments.as_ref().is_empty() { let f = self.functions.get_mut(&hash_fn).expect("exists"); - f.comments = Some(comments.iter().map(|s| s.as_ref().into()).collect()); + f.comments = Some( + comments + .as_ref() + .iter() + .map(|s| s.as_ref().into()) + .collect(), + ); } self @@ -756,17 +767,18 @@ impl Module { #[inline] pub fn set_fn( &mut self, - name: impl AsRef + Into, + name: impl AsRef, namespace: FnNamespace, access: FnAccess, arg_names: Option<&[&str]>, - arg_types: &[TypeId], + arg_types: impl AsRef<[TypeId]>, func: CallableFunction, ) -> u64 { let _arg_names = arg_names; let is_method = func.is_method(); let mut param_types: StaticVec<_> = arg_types + .as_ref() .iter() .cloned() .enumerate() @@ -781,7 +793,7 @@ impl Module { .flat_map(|&p| p.iter()) .map(|&arg| self.interner.get("", arg).into()) .collect::>(); - let return_type = if names.len() > arg_types.len() { + let return_type = if names.len() > arg_types.as_ref().len() { names.pop().expect("exists") } else { Default::default() @@ -795,7 +807,7 @@ impl Module { self.functions.insert( hash_fn, FuncInfo { - name: self.interner.get("", name.as_ref()).into(), + name: self.interner.get("", name).into(), namespace, access, params: param_types.len(), @@ -845,21 +857,27 @@ impl Module { /// doc-comment leader: `///` or `/**`. #[cfg(feature = "metadata")] #[inline] - pub fn set_fn_with_comments( + pub fn set_fn_with_comments>( &mut self, - name: impl AsRef + Into, + name: impl AsRef, namespace: FnNamespace, access: FnAccess, arg_names: Option<&[&str]>, - arg_types: &[TypeId], - comments: &[impl AsRef], + arg_types: impl AsRef<[TypeId]>, + comments: impl AsRef<[S]>, func: CallableFunction, ) -> u64 { let hash = self.set_fn(name, namespace, access, arg_names, arg_types, func); - if !comments.is_empty() { + if !comments.as_ref().is_empty() { let f = self.functions.get_mut(&hash).expect("exists"); - f.comments = Some(comments.iter().map(|s| s.as_ref().into()).collect()); + f.comments = Some( + comments + .as_ref() + .iter() + .map(|s| s.as_ref().into()) + .collect(), + ); } hash @@ -932,16 +950,15 @@ impl Module { /// assert!(module.contains_fn(hash)); /// ``` #[inline(always)] - pub fn set_raw_fn( + pub fn set_raw_fn( &mut self, - name: N, + name: impl AsRef, namespace: FnNamespace, access: FnAccess, - arg_types: &[TypeId], + arg_types: impl AsRef<[TypeId]>, func: F, ) -> u64 where - N: AsRef + Into, T: Variant + Clone, F: Fn(NativeCallContext, &mut FnCallArgs) -> RhaiResultOf + SendSync + 'static, { @@ -1025,7 +1042,7 @@ impl Module { F: Fn(&mut A) -> RhaiResultOf + SendSync + 'static, { self.set_fn( - &crate::engine::make_getter(name.as_ref()), + crate::engine::make_getter(name.as_ref()).as_str(), FnNamespace::Global, FnAccess::Public, None, @@ -1067,7 +1084,7 @@ impl Module { F: Fn(&mut A, B) -> RhaiResultOf<()> + SendSync + 'static, { self.set_fn( - &crate::engine::make_setter(name.as_ref()), + crate::engine::make_setter(name.as_ref()).as_str(), FnNamespace::Global, FnAccess::Public, None, diff --git a/src/optimizer.rs b/src/optimizer.rs index 64d3037d..95c5c2d8 100644 --- a/src/optimizer.rs +++ b/src/optimizer.rs @@ -110,13 +110,11 @@ impl<'a> OptimizerState<'a> { } /// Look up a constant from the list. #[inline] - pub fn find_constant(&self, name: impl AsRef) -> Option<&Dynamic> { + pub fn find_constant(&self, name: &str) -> Option<&Dynamic> { if !self.propagate_constants { return None; } - let name = name.as_ref(); - for (n, access, value) in self.variables.iter().rev() { if n == name { return match access { @@ -132,7 +130,7 @@ impl<'a> OptimizerState<'a> { #[inline] pub fn call_fn_with_constant_arguments( &self, - fn_name: impl AsRef, + fn_name: &str, arg_values: &mut [Dynamic], ) -> Option { #[cfg(not(feature = "no_function"))] @@ -145,7 +143,7 @@ impl<'a> OptimizerState<'a> { &mut GlobalRuntimeState::new(), &mut EvalState::new(), lib, - &fn_name, + fn_name, calc_fn_hash(&fn_name, arg_values.len()), &mut arg_values.iter_mut().collect::>(), false, @@ -158,8 +156,12 @@ impl<'a> OptimizerState<'a> { } // Has a system function a Rust-native override? -fn has_native_fn_override(engine: &Engine, hash_script: u64, arg_types: &[TypeId]) -> bool { - let hash_params = calc_fn_params_hash(arg_types.iter().cloned()); +fn has_native_fn_override( + engine: &Engine, + hash_script: u64, + arg_types: impl AsRef<[TypeId]>, +) -> bool { + let hash_params = calc_fn_params_hash(arg_types.as_ref().iter().cloned()); let hash = combine_hashes(hash_script, hash_params); // First check the global namespace and packages, but skip modules that are standard because diff --git a/src/parser.rs b/src/parser.rs index 348845d1..b3a1a9f1 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -108,8 +108,7 @@ impl<'e> ParseState<'e> { /// Return `None` when the variable name is not found in the `stack`. #[inline] #[must_use] - pub fn access_var(&mut self, name: impl AsRef, pos: Position) -> Option { - let name = name.as_ref(); + pub fn access_var(&mut self, name: &str, pos: Position) -> Option { let mut barrier = false; let _pos = pos; @@ -158,9 +157,7 @@ impl<'e> ParseState<'e> { #[cfg(not(feature = "no_module"))] #[inline] #[must_use] - pub fn find_module(&self, name: impl AsRef) -> Option { - let name = name.as_ref(); - + pub fn find_module(&self, name: &str) -> Option { self.modules .iter() .rev() @@ -172,11 +169,7 @@ impl<'e> ParseState<'e> { /// Get an interned identifier, creating one if it is not yet interned. #[inline(always)] #[must_use] - pub fn get_identifier( - &mut self, - prefix: &'static str, - text: impl AsRef + Into + Into, - ) -> Identifier { + pub fn get_identifier(&mut self, prefix: impl AsRef, text: impl AsRef) -> Identifier { self.interned_strings.get(prefix, text).into() } @@ -186,8 +179,8 @@ impl<'e> ParseState<'e> { #[must_use] pub fn get_interned_string( &mut self, - prefix: &'static str, - text: impl AsRef + Into + Into, + prefix: impl AsRef, + text: impl AsRef, ) -> ImmutableString { self.interned_strings.get(prefix, text) } @@ -259,15 +252,15 @@ impl Expr { match self { Self::Variable(_, pos, x) if x.1.is_none() => { let ident = x.2; - let getter = state.get_identifier(crate::engine::FN_GET, ident.as_str()); + let getter = state.get_identifier(crate::engine::FN_GET, &ident); let hash_get = calc_fn_hash(&getter, 1); - let setter = state.get_identifier(crate::engine::FN_SET, ident.as_str()); + let setter = state.get_identifier(crate::engine::FN_SET, &ident); let hash_set = calc_fn_hash(&setter, 2); Self::Property(Box::new(( (getter, hash_get), (setter, hash_set), - (state.get_interned_string("", ident.as_str()), pos), + (state.get_interned_string("", &ident), pos), ))) } _ => self, @@ -1159,7 +1152,7 @@ fn parse_primary( Token::IntegerConstant(x) => Expr::IntegerConstant(x, settings.pos), Token::CharConstant(c) => Expr::CharConstant(c, settings.pos), Token::StringConstant(s) => { - Expr::StringConstant(state.get_identifier("", s).into(), settings.pos) + Expr::StringConstant(state.get_interned_string("", s), settings.pos) } Token::True => Expr::BoolConstant(true, settings.pos), Token::False => Expr::BoolConstant(false, settings.pos), @@ -1998,7 +1991,7 @@ fn parse_binary_op( let hash = calc_fn_hash(&op, 2); let op_base = FnCallExpr { - name: state.get_identifier("", op.as_ref()), + name: state.get_identifier("", op), hashes: FnCallHashes::from_native(hash), ..Default::default() }; @@ -2125,7 +2118,7 @@ fn parse_custom_syntax( && seg.len() > CUSTOM_SYNTAX_MARKER_SYNTAX_VARIANT.len() => { inputs.push(Expr::StringConstant( - state.get_identifier("", seg).into(), + state.get_interned_string("", seg), pos, )); break; @@ -2145,7 +2138,7 @@ fn parse_custom_syntax( } CUSTOM_SYNTAX_MARKER_SYMBOL => { let (symbol, pos) = parse_symbol(input)?; - let symbol: ImmutableString = state.get_identifier("", symbol).into(); + let symbol = state.get_interned_string("", symbol); segments.push(symbol.clone()); tokens.push(state.get_identifier("", CUSTOM_SYNTAX_MARKER_SYMBOL)); inputs.push(Expr::StringConstant(symbol, pos)); @@ -2168,7 +2161,7 @@ fn parse_custom_syntax( CUSTOM_SYNTAX_MARKER_BOOL => match input.next().expect(NEVER_ENDS) { (b @ Token::True, pos) | (b @ Token::False, pos) => { inputs.push(Expr::BoolConstant(b == Token::True, pos)); - segments.push(state.get_identifier("", b.literal_syntax()).into()); + segments.push(state.get_interned_string("", b.literal_syntax())); tokens.push(state.get_identifier("", CUSTOM_SYNTAX_MARKER_BOOL)); } (_, pos) => { @@ -2207,7 +2200,7 @@ fn parse_custom_syntax( }, CUSTOM_SYNTAX_MARKER_STRING => match input.next().expect(NEVER_ENDS) { (Token::StringConstant(s), pos) => { - let s: ImmutableString = state.get_identifier("", s).into(); + let s = state.get_interned_string("", s); inputs.push(Expr::StringConstant(s.clone(), pos)); segments.push(s); tokens.push(state.get_identifier("", CUSTOM_SYNTAX_MARKER_STRING)); @@ -3268,11 +3261,7 @@ fn parse_anon_fn( params.iter().for_each(|p| p.hash(hasher)); body.hash(hasher); let hash = hasher.finish(); - - let fn_name = state.get_identifier( - "", - &(format!("{}{:016x}", crate::engine::FN_ANONYMOUS, hash)), - ); + let fn_name = state.get_identifier("", format!("{}{:016x}", crate::engine::FN_ANONYMOUS, hash)); // Define the function let script = ScriptFnDef { diff --git a/src/tokenizer.rs b/src/tokenizer.rs index 2a86927e..b3410186 100644 --- a/src/tokenizer.rs +++ b/src/tokenizer.rs @@ -694,11 +694,9 @@ impl Token { /// Reverse lookup a token from a piece of syntax. #[must_use] - pub fn lookup_from_syntax(syntax: impl AsRef) -> Option { + pub fn lookup_from_syntax(syntax: &str) -> Option { use Token::*; - let syntax = syntax.as_ref(); - Some(match syntax { "{" => LeftBrace, "}" => RightBrace, @@ -1355,9 +1353,7 @@ fn is_numeric_digit(c: char) -> bool { #[cfg(feature = "metadata")] #[inline] #[must_use] -pub fn is_doc_comment(comment: impl AsRef) -> bool { - let comment = comment.as_ref(); - +pub fn is_doc_comment(comment: &str) -> bool { (comment.starts_with("///") && !comment.starts_with("////")) || (comment.starts_with("/**") && !comment.starts_with("/***")) } @@ -2018,8 +2014,8 @@ fn get_identifier( /// Is this keyword allowed as a function? #[inline] #[must_use] -pub fn is_keyword_function(name: impl AsRef) -> bool { - match name.as_ref() { +pub fn is_keyword_function(name: &str) -> bool { + match name { KEYWORD_PRINT | KEYWORD_DEBUG | KEYWORD_TYPE_OF | KEYWORD_EVAL | KEYWORD_FN_PTR | KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_IS_DEF_VAR => true, @@ -2051,8 +2047,8 @@ pub fn is_valid_identifier(name: impl Iterator) -> bool { /// Is a text string a valid script-defined function name? #[inline(always)] #[must_use] -pub fn is_valid_function_name(name: impl AsRef) -> bool { - is_valid_identifier(name.as_ref().chars()) +pub fn is_valid_function_name(name: &str) -> bool { + is_valid_identifier(name.chars()) } /// Is a character valid to start an identifier? diff --git a/src/types/interner.rs b/src/types/interner.rs index a9908cd7..b6617829 100644 --- a/src/types/interner.rs +++ b/src/types/interner.rs @@ -8,12 +8,11 @@ use std::prelude::v1::*; /// _(internals)_ A factory of identifiers from text strings. /// Exported under the `internals` feature only. /// -/// Normal identifiers are not interned since they use `SmartString` because most identifiers in -/// Rhai are short and ASCII-based. Thus copying is relatively fast. -/// -/// Property getters and setters are interned separately. +/// Normal identifiers, property getters and setters are interned separately. #[derive(Debug, Clone, Default, Hash)] pub struct StringsInterner { + /// Normal strings. + strings: std::collections::BTreeMap, /// Property getters. #[cfg(not(feature = "no_object"))] getters: std::collections::BTreeMap, @@ -28,6 +27,7 @@ impl StringsInterner { #[must_use] pub fn new() -> Self { Self { + strings: std::collections::BTreeMap::new(), #[cfg(not(feature = "no_object"))] getters: std::collections::BTreeMap::new(), #[cfg(not(feature = "no_object"))] @@ -36,39 +36,37 @@ impl StringsInterner { } /// Get an identifier from a text string and prefix, adding it to the interner if necessary. /// + /// # Prefix + /// + /// Currently recognized prefixes are: + /// + /// * `""` - None (normal string) + /// * `"get$"` - Property getter, not available under `no_object` + /// * `"set$"` - Property setter, not available under `no_object` + /// /// # Panics /// /// Panics if the prefix is not recognized. #[inline] #[must_use] - pub fn get( - &mut self, - prefix: &'static str, - text: impl AsRef + Into + Into, - ) -> ImmutableString { - #[cfg(not(feature = "no_object"))] - { - let (dict, mapper) = match prefix { - "" => return text.into(), - FN_GET => (&mut self.getters, make_getter as fn(&str) -> String), - FN_SET => (&mut self.setters, make_setter as fn(&str) -> String), - _ => unreachable!("unsupported prefix {}", prefix), - }; + pub fn get(&mut self, prefix: impl AsRef, text: impl AsRef) -> ImmutableString { + let (dict, mapper): (_, fn(&str) -> Identifier) = match prefix.as_ref() { + "" => (&mut self.strings, |s| s.into()), - if dict.contains_key(text.as_ref()) { - self.getters.get(text.as_ref()).expect("exists").clone() - } else { - let value: ImmutableString = mapper(text.as_ref()).into(); - let text = text.into(); - dict.insert(text, value.clone()); - value - } - } + #[cfg(not(feature = "no_object"))] + FN_GET => (&mut self.getters, |s| make_getter(s)), + #[cfg(not(feature = "no_object"))] + FN_SET => (&mut self.setters, |s| make_setter(s)), - #[cfg(feature = "no_object")] - match prefix { - "" => return text.into(), - _ => unreachable!("unsupported prefix {}", prefix), + _ => unreachable!("unsupported prefix {}", prefix.as_ref()), + }; + + if dict.contains_key(text.as_ref()) { + dict.get(text.as_ref()).expect("exists").clone() + } else { + let value: ImmutableString = mapper(text.as_ref()).into(); + dict.insert(text.as_ref().into(), value.clone()); + value } } } @@ -76,27 +74,24 @@ impl StringsInterner { impl AddAssign for StringsInterner { #[inline(always)] fn add_assign(&mut self, rhs: Self) { - let _rhs = rhs; - + self.strings.extend(rhs.strings.into_iter()); #[cfg(not(feature = "no_object"))] - { - self.getters.extend(_rhs.getters.into_iter()); - self.setters.extend(_rhs.setters.into_iter()); - } + self.getters.extend(rhs.getters.into_iter()); + #[cfg(not(feature = "no_object"))] + self.setters.extend(rhs.setters.into_iter()); } } impl AddAssign<&Self> for StringsInterner { #[inline(always)] fn add_assign(&mut self, rhs: &Self) { - let _rhs = rhs; - + self.strings + .extend(rhs.strings.iter().map(|(k, v)| (k.clone(), v.clone()))); #[cfg(not(feature = "no_object"))] - { - self.getters - .extend(_rhs.getters.iter().map(|(k, v)| (k.clone(), v.clone()))); - self.setters - .extend(_rhs.setters.iter().map(|(k, v)| (k.clone(), v.clone()))); - } + self.getters + .extend(rhs.getters.iter().map(|(k, v)| (k.clone(), v.clone()))); + #[cfg(not(feature = "no_object"))] + self.setters + .extend(rhs.setters.iter().map(|(k, v)| (k.clone(), v.clone()))); } }