Use Engine's interner.

This commit is contained in:
Stephen Chung 2022-11-24 15:10:17 +08:00
parent 6791ef64da
commit d1913edf3c
8 changed files with 136 additions and 107 deletions

View File

@ -1,7 +1,6 @@
//! Module that defines the public compilation API of [`Engine`]. //! Module that defines the public compilation API of [`Engine`].
use crate::parser::{ParseResult, ParseState}; use crate::parser::{ParseResult, ParseState};
use crate::types::StringsInterner;
use crate::{Engine, OptimizationLevel, Scope, AST}; use crate::{Engine, OptimizationLevel, Scope, AST};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -222,7 +221,8 @@ impl Engine {
scripts.as_ref(), scripts.as_ref(),
self.token_mapper.as_ref().map(<_>::as_ref), self.token_mapper.as_ref().map(<_>::as_ref),
); );
let mut state = ParseState::new(self, scope, StringsInterner::default(), tokenizer_control); let interned_strings = &mut *self.interned_strings.borrow_mut();
let mut state = ParseState::new(self, scope, interned_strings, tokenizer_control);
let mut _ast = self.parse(&mut stream.peekable(), &mut state, optimization_level)?; let mut _ast = self.parse(&mut stream.peekable(), &mut state, optimization_level)?;
#[cfg(feature = "metadata")] #[cfg(feature = "metadata")]
_ast.set_doc(state.tokenizer_control.borrow().global_comments.join("\n")); _ast.set_doc(state.tokenizer_control.borrow().global_comments.join("\n"));
@ -295,7 +295,8 @@ impl Engine {
self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref)); self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref));
let mut peekable = stream.peekable(); let mut peekable = stream.peekable();
let mut state = ParseState::new(self, scope, StringsInterner::default(), tokenizer_control); let interned_strings = &mut *self.interned_strings.borrow_mut();
let mut state = ParseState::new(self, scope, interned_strings, tokenizer_control);
self.parse_global_expr(&mut peekable, &mut state, |_| {}, self.optimization_level) self.parse_global_expr(&mut peekable, &mut state, |_| {}, self.optimization_level)
} }
} }

View File

@ -2,7 +2,7 @@
use crate::eval::{Caches, GlobalRuntimeState}; use crate::eval::{Caches, GlobalRuntimeState};
use crate::parser::ParseState; use crate::parser::ParseState;
use crate::types::{dynamic::Variant, StringsInterner}; use crate::types::dynamic::Variant;
use crate::{ use crate::{
reify, Dynamic, Engine, OptimizationLevel, Position, RhaiResult, RhaiResultOf, Scope, AST, ERR, reify, Dynamic, Engine, OptimizationLevel, Position, RhaiResult, RhaiResultOf, Scope, AST, ERR,
}; };
@ -117,12 +117,16 @@ impl Engine {
script: &str, script: &str,
) -> RhaiResultOf<T> { ) -> RhaiResultOf<T> {
let scripts = [script]; let scripts = [script];
let ast = {
let interned_strings = &mut *self.interned_strings.borrow_mut();
let (stream, tokenizer_control) = let (stream, tokenizer_control) =
self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref)); self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref));
let mut state = ParseState::new(self, scope, StringsInterner::default(), tokenizer_control);
let mut state = ParseState::new(self, scope, interned_strings, tokenizer_control);
// No need to optimize a lone expression // No need to optimize a lone expression
let ast = self.parse_global_expr( self.parse_global_expr(
&mut stream.peekable(), &mut stream.peekable(),
&mut state, &mut state,
|_| {}, |_| {},
@ -130,7 +134,8 @@ impl Engine {
OptimizationLevel::None, OptimizationLevel::None,
#[cfg(feature = "no_optimize")] #[cfg(feature = "no_optimize")]
OptimizationLevel::default(), OptimizationLevel::default(),
)?; )?
};
self.eval_ast_with_scope(scope, &ast) self.eval_ast_with_scope(scope, &ast)
} }

View File

@ -3,7 +3,6 @@
use crate::parser::{ParseSettingFlags, ParseState}; use crate::parser::{ParseSettingFlags, ParseState};
use crate::tokenizer::Token; use crate::tokenizer::Token;
use crate::types::StringsInterner;
use crate::{Engine, LexError, Map, OptimizationLevel, RhaiResultOf, Scope}; use crate::{Engine, LexError, Map, OptimizationLevel, RhaiResultOf, Scope};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -117,11 +116,12 @@ impl Engine {
}, },
); );
let ast = {
let scope = Scope::new(); let scope = Scope::new();
let mut state = let interned_strings = &mut *self.interned_strings.borrow_mut();
ParseState::new(self, &scope, StringsInterner::default(), tokenizer_control); let mut state = ParseState::new(self, &scope, interned_strings, tokenizer_control);
let ast = self.parse_global_expr( self.parse_global_expr(
&mut stream.peekable(), &mut stream.peekable(),
&mut state, &mut state,
|s| s.flags |= ParseSettingFlags::DISALLOW_UNQUOTED_MAP_PROPERTIES, |s| s.flags |= ParseSettingFlags::DISALLOW_UNQUOTED_MAP_PROPERTIES,
@ -129,7 +129,8 @@ impl Engine {
OptimizationLevel::None, OptimizationLevel::None,
#[cfg(feature = "no_optimize")] #[cfg(feature = "no_optimize")]
OptimizationLevel::default(), OptimizationLevel::default(),
)?; )?
};
self.eval_ast(&ast) self.eval_ast(&ast)
} }

View File

@ -2,7 +2,6 @@
use crate::eval::{Caches, GlobalRuntimeState}; use crate::eval::{Caches, GlobalRuntimeState};
use crate::parser::ParseState; use crate::parser::ParseState;
use crate::types::StringsInterner;
use crate::{Engine, RhaiResultOf, Scope, AST}; use crate::{Engine, RhaiResultOf, Scope, AST};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
@ -57,10 +56,16 @@ impl Engine {
#[inline] #[inline]
pub fn run_with_scope(&self, scope: &mut Scope, script: &str) -> RhaiResultOf<()> { pub fn run_with_scope(&self, scope: &mut Scope, script: &str) -> RhaiResultOf<()> {
let scripts = [script]; let scripts = [script];
let ast = {
let interned_strings = &mut *self.interned_strings.borrow_mut();
let (stream, tokenizer_control) = let (stream, tokenizer_control) =
self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref)); self.lex_raw(&scripts, self.token_mapper.as_ref().map(<_>::as_ref));
let mut state = ParseState::new(self, scope, StringsInterner::default(), tokenizer_control);
let ast = self.parse(&mut stream.peekable(), &mut state, self.optimization_level)?; let mut state = ParseState::new(self, scope, interned_strings, tokenizer_control);
self.parse(&mut stream.peekable(), &mut state, self.optimization_level)?
};
self.run_ast_with_scope(scope, &ast) self.run_ast_with_scope(scope, &ast)
} }
/// Evaluate an [`AST`]. /// Evaluate an [`AST`].

View File

@ -103,7 +103,7 @@ pub struct Engine {
pub(crate) module_resolver: Box<dyn crate::ModuleResolver>, pub(crate) module_resolver: Box<dyn crate::ModuleResolver>,
/// An empty [`ImmutableString`] for cloning purposes. /// An empty [`ImmutableString`] for cloning purposes.
pub(crate) interned_strings: Locked<StringsInterner<'static>>, pub(crate) interned_strings: Locked<StringsInterner>,
/// A set of symbols to disable. /// A set of symbols to disable.
pub(crate) disabled_symbols: BTreeSet<Identifier>, pub(crate) disabled_symbols: BTreeSet<Identifier>,

View File

@ -6,6 +6,9 @@ use crate::{Dynamic, RhaiResultOf, ERR, INT};
#[cfg(feature = "no_std")] #[cfg(feature = "no_std")]
use std::prelude::v1::*; use std::prelude::v1::*;
#[cfg(not(feature = "no_float"))]
use crate::FLOAT;
def_package! { def_package! {
/// Package of core language features. /// Package of core language features.
pub LanguageCorePackage(lib) { pub LanguageCorePackage(lib) {
@ -76,10 +79,17 @@ mod core_functions {
} }
/// Block the current thread for a particular number of `seconds`. /// Block the current thread for a particular number of `seconds`.
///
/// # Example
///
/// ```rhai
/// // Do nothing for 10 seconds!
/// sleep(10.0);
/// ```
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
#[rhai_fn(name = "sleep")] #[rhai_fn(name = "sleep")]
pub fn sleep_float(seconds: crate::FLOAT) { pub fn sleep_float(seconds: FLOAT) {
if seconds <= 0.0 { if seconds <= 0.0 {
return; return;
} }
@ -90,6 +100,13 @@ mod core_functions {
std::thread::sleep(std::time::Duration::from_secs_f32(seconds)); std::thread::sleep(std::time::Duration::from_secs_f32(seconds));
} }
/// Block the current thread for a particular number of `seconds`. /// Block the current thread for a particular number of `seconds`.
///
/// # Example
///
/// ```rhai
/// // Do nothing for 10 seconds!
/// sleep(10);
/// ```
#[cfg(not(feature = "no_std"))] #[cfg(not(feature = "no_std"))]
pub fn sleep(seconds: INT) { pub fn sleep(seconds: INT) {
if seconds <= 0 { if seconds <= 0 {
@ -121,17 +138,24 @@ mod core_functions {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
#[export_module] #[export_module]
mod reflection_functions { mod reflection_functions {
pub fn get_fn_metadata_list(ctx: NativeCallContext) -> crate::Array { use crate::Array;
/// Return an array of object maps containing metadata of all script-defined functions.
pub fn get_fn_metadata_list(ctx: NativeCallContext) -> Array {
collect_fn_metadata(ctx, |_, _, _, _, _| true) collect_fn_metadata(ctx, |_, _, _, _, _| true)
} }
/// Return an array of object maps containing metadata of all script-defined functions
/// matching the specified name.
#[rhai_fn(name = "get_fn_metadata_list")] #[rhai_fn(name = "get_fn_metadata_list")]
pub fn get_fn_metadata(ctx: NativeCallContext, name: &str) -> crate::Array { pub fn get_fn_metadata(ctx: NativeCallContext, name: &str) -> Array {
collect_fn_metadata(ctx, |_, _, n, _, _| n == name) collect_fn_metadata(ctx, |_, _, n, _, _| n == name)
} }
/// Return an array of object maps containing metadata of all script-defined functions
/// matching the specified name and arity (number of parameters).
#[rhai_fn(name = "get_fn_metadata_list")] #[rhai_fn(name = "get_fn_metadata_list")]
pub fn get_fn_metadata2(ctx: NativeCallContext, name: &str, params: INT) -> crate::Array { pub fn get_fn_metadata2(ctx: NativeCallContext, name: &str, params: INT) -> Array {
if params < 0 || params > crate::MAX_USIZE_INT { if params < 0 || params > crate::MAX_USIZE_INT {
crate::Array::new() Array::new()
} else { } else {
collect_fn_metadata(ctx, |_, _, n, p, _| p == (params as usize) && n == name) collect_fn_metadata(ctx, |_, _, n, p, _| p == (params as usize) && n == name)
} }
@ -146,24 +170,33 @@ fn collect_fn_metadata(
filter: impl Fn(FnNamespace, FnAccess, &str, usize, &crate::Shared<crate::ast::ScriptFnDef>) -> bool filter: impl Fn(FnNamespace, FnAccess, &str, usize, &crate::Shared<crate::ast::ScriptFnDef>) -> bool
+ Copy, + Copy,
) -> crate::Array { ) -> crate::Array {
use crate::{ast::ScriptFnDef, Array, Map}; #[cfg(not(feature = "no_module"))]
use crate::Identifier;
use crate::{ast::ScriptFnDef, engine::FN_ANONYMOUS, Array, Map};
// Create a metadata record for a function. // Create a metadata record for a function.
fn make_metadata( fn make_metadata(
dict: &mut crate::types::StringsInterner, engine: &Engine,
#[cfg(not(feature = "no_module"))] namespace: crate::Identifier, #[cfg(not(feature = "no_module"))] namespace: Identifier,
func: &ScriptFnDef, func: &ScriptFnDef,
) -> Map { ) -> Map {
let mut map = Map::new(); let mut map = Map::new();
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
if !namespace.is_empty() { if !namespace.is_empty() {
map.insert("namespace".into(), dict.get(namespace).into()); map.insert(
"namespace".into(),
engine.get_interned_string(namespace).into(),
);
} }
map.insert("name".into(), dict.get(func.name.as_str()).into()); map.insert(
"name".into(),
engine.get_interned_string(func.name.clone()).into(),
);
map.insert( map.insert(
"access".into(), "access".into(),
dict.get(match func.access { engine
.get_interned_string(match func.access {
FnAccess::Public => "public", FnAccess::Public => "public",
FnAccess::Private => "private", FnAccess::Private => "private",
}) })
@ -171,13 +204,13 @@ fn collect_fn_metadata(
); );
map.insert( map.insert(
"is_anonymous".into(), "is_anonymous".into(),
func.name.starts_with(crate::engine::FN_ANONYMOUS).into(), func.name.starts_with(FN_ANONYMOUS).into(),
); );
map.insert( map.insert(
"params".into(), "params".into(),
func.params func.params
.iter() .iter()
.map(|p| dict.get(p.as_str()).into()) .map(|p| engine.get_interned_string(p.clone()).into())
.collect::<Array>() .collect::<Array>()
.into(), .into(),
); );
@ -187,7 +220,7 @@ fn collect_fn_metadata(
"comments".into(), "comments".into(),
func.comments func.comments
.iter() .iter()
.map(|s| dict.get(s.as_ref()).into()) .map(|s| engine.get_interned_string(s.as_ref()).into())
.collect::<Array>() .collect::<Array>()
.into(), .into(),
); );
@ -196,7 +229,7 @@ fn collect_fn_metadata(
map map
} }
let dict = &mut crate::types::StringsInterner::new(); let engine = ctx.engine();
let mut list = Array::new(); let mut list = Array::new();
ctx.iter_namespaces() ctx.iter_namespaces()
@ -205,9 +238,9 @@ fn collect_fn_metadata(
.for_each(|(.., f)| { .for_each(|(.., f)| {
list.push( list.push(
make_metadata( make_metadata(
dict, engine,
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
crate::Identifier::new_const(), Identifier::new_const(),
f, f,
) )
.into(), .into(),
@ -222,9 +255,9 @@ fn collect_fn_metadata(
.for_each(|(.., f)| { .for_each(|(.., f)| {
list.push( list.push(
make_metadata( make_metadata(
dict, engine,
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
crate::Identifier::new_const(), Identifier::new_const(),
f, f,
) )
.into(), .into(),
@ -240,9 +273,9 @@ fn collect_fn_metadata(
.for_each(|(.., f)| { .for_each(|(.., f)| {
list.push( list.push(
make_metadata( make_metadata(
dict, engine,
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
crate::Identifier::new_const(), Identifier::new_const(),
f, f,
) )
.into(), .into(),
@ -251,41 +284,31 @@ fn collect_fn_metadata(
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
{ {
use crate::{tokenizer::Token::DoubleColon, Shared, SmartString};
// Recursively scan modules for script-defined functions. // Recursively scan modules for script-defined functions.
fn scan_module( fn scan_module(
dict: &mut crate::types::StringsInterner, engine: &Engine,
list: &mut Array, list: &mut Array,
namespace: &str, namespace: &str,
module: &Module, module: &Module,
filter: impl Fn( filter: impl Fn(FnNamespace, FnAccess, &str, usize, &Shared<ScriptFnDef>) -> bool + Copy,
FnNamespace,
FnAccess,
&str,
usize,
&crate::Shared<crate::ast::ScriptFnDef>,
) -> bool
+ Copy,
) { ) {
module module
.iter_script_fn() .iter_script_fn()
.filter(|(s, a, n, p, f)| filter(*s, *a, n, *p, f)) .filter(|(s, a, n, p, f)| filter(*s, *a, n, *p, f))
.for_each(|(.., f)| list.push(make_metadata(dict, namespace.into(), f).into())); .for_each(|(.., f)| list.push(make_metadata(engine, namespace.into(), f).into()));
for (name, m) in module.iter_sub_modules() { for (name, m) in module.iter_sub_modules() {
use std::fmt::Write; use std::fmt::Write;
let mut ns = crate::SmartString::new_const(); let mut ns = SmartString::new_const();
write!( write!(&mut ns, "{namespace}{}{name}", DoubleColon.literal_syntax()).unwrap();
&mut ns, scan_module(engine, list, &ns, &**m, filter);
"{namespace}{}{name}",
crate::tokenizer::Token::DoubleColon.literal_syntax()
)
.unwrap();
scan_module(dict, list, &ns, &**m, filter);
} }
} }
for (ns, m) in ctx.iter_imports_raw() { for (ns, m) in ctx.iter_imports_raw() {
scan_module(dict, &mut list, ns, &**m, filter); scan_module(engine, &mut list, ns, &**m, filter);
} }
} }

View File

@ -46,13 +46,13 @@ const SMALL_SWITCH_RANGE: INT = 16;
/// _(internals)_ A type that encapsulates the current state of the parser. /// _(internals)_ A type that encapsulates the current state of the parser.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
pub struct ParseState<'e> { pub struct ParseState<'e, 's> {
/// Input stream buffer containing the next character to read. /// Input stream buffer containing the next character to read.
pub tokenizer_control: TokenizerControl, pub tokenizer_control: TokenizerControl,
/// Controls whether parsing of an expression should stop given the next token. /// Controls whether parsing of an expression should stop given the next token.
pub expr_filter: fn(&Token) -> bool, pub expr_filter: fn(&Token) -> bool,
/// String interners. /// String interners.
interned_strings: StringsInterner<'e>, interned_strings: &'s mut StringsInterner,
/// External [scope][Scope] with constants. /// External [scope][Scope] with constants.
pub scope: &'e Scope<'e>, pub scope: &'e Scope<'e>,
/// Global runtime state. /// Global runtime state.
@ -81,7 +81,7 @@ pub struct ParseState<'e> {
pub max_expr_depth: usize, pub max_expr_depth: usize,
} }
impl fmt::Debug for ParseState<'_> { impl fmt::Debug for ParseState<'_, '_> {
#[cold] #[cold]
#[inline(never)] #[inline(never)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -105,14 +105,14 @@ impl fmt::Debug for ParseState<'_> {
} }
} }
impl<'e> ParseState<'e> { impl<'e, 's> ParseState<'e, 's> {
/// Create a new [`ParseState`]. /// Create a new [`ParseState`].
#[inline] #[inline]
#[must_use] #[must_use]
pub fn new( pub fn new(
engine: &Engine, engine: &Engine,
scope: &'e Scope, scope: &'e Scope,
interned_strings: StringsInterner<'e>, interned_strings: &'s mut StringsInterner,
tokenizer_control: TokenizerControl, tokenizer_control: TokenizerControl,
) -> Self { ) -> Self {
Self { Self {
@ -1422,15 +1422,17 @@ impl Engine {
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
Token::Pipe | Token::Or if settings.has_option(LangOptions::ANON_FN) => { Token::Pipe | Token::Or if settings.has_option(LangOptions::ANON_FN) => {
// Build new parse state // Build new parse state
let interned_strings = std::mem::take(&mut state.interned_strings); let new_interner = &mut StringsInterner::new();
let mut new_state = ParseState::new( let mut new_state = ParseState::new(
self, self,
state.scope, state.scope,
interned_strings, new_interner,
state.tokenizer_control.clone(), state.tokenizer_control.clone(),
); );
// We move the strings interner to the new parse state object by swapping it...
std::mem::swap(state.interned_strings, new_state.interned_strings);
#[cfg(not(feature = "no_module"))] #[cfg(not(feature = "no_module"))]
{ {
// Do not allow storing an index to a globally-imported module // Do not allow storing an index to a globally-imported module
@ -1471,8 +1473,8 @@ impl Engine {
let result = self.parse_anon_fn(input, &mut new_state, state, lib, new_settings); let result = self.parse_anon_fn(input, &mut new_state, state, lib, new_settings);
// Restore parse state // Restore the strings interner by swapping it back
state.interned_strings = new_state.interned_strings; std::mem::swap(state.interned_strings, new_state.interned_strings);
let (expr, func) = result?; let (expr, func) = result?;
@ -3301,12 +3303,10 @@ impl Engine {
match input.next().expect(NEVER_ENDS) { match input.next().expect(NEVER_ENDS) {
(Token::Fn, pos) => { (Token::Fn, pos) => {
// Build new parse state // Build new parse state
let interned_strings = std::mem::take(&mut state.interned_strings);
let mut new_state = ParseState::new( let mut new_state = ParseState::new(
self, self,
state.scope, state.scope,
interned_strings, state.interned_strings,
state.tokenizer_control.clone(), state.tokenizer_control.clone(),
); );
@ -3353,8 +3353,6 @@ impl Engine {
); );
// Restore parse state // Restore parse state
state.interned_strings = new_state.interned_strings;
let func = func?; let func = func?;
let hash = calc_fn_hash(None, &func.name, func.params.len()); let hash = calc_fn_hash(None, &func.name, func.params.len());

View File

@ -12,7 +12,6 @@ use std::prelude::v1::*;
use std::{ use std::{
fmt, fmt,
hash::{Hash, Hasher}, hash::{Hash, Hasher},
marker::PhantomData,
ops::AddAssign, ops::AddAssign,
}; };
@ -24,7 +23,9 @@ pub const MAX_STRING_LEN: usize = 24;
/// _(internals)_ A cache for interned strings. /// _(internals)_ A cache for interned strings.
/// Exported under the `internals` feature only. /// Exported under the `internals` feature only.
pub struct StringsInterner<'a> { #[derive(Clone)]
#[must_use]
pub struct StringsInterner {
/// Maximum number of strings interned. /// Maximum number of strings interned.
pub capacity: usize, pub capacity: usize,
/// Maximum string length. /// Maximum string length.
@ -33,19 +34,16 @@ pub struct StringsInterner<'a> {
cache: StraightHashMap<ImmutableString>, cache: StraightHashMap<ImmutableString>,
/// Bloom filter to avoid caching "one-hit wonders". /// Bloom filter to avoid caching "one-hit wonders".
filter: BloomFilterU64, filter: BloomFilterU64,
/// Take care of the lifetime parameter.
dummy: PhantomData<&'a ()>,
} }
impl Default for StringsInterner<'_> { impl Default for StringsInterner {
#[inline(always)] #[inline(always)]
#[must_use]
fn default() -> Self { fn default() -> Self {
Self::new() Self::new()
} }
} }
impl fmt::Debug for StringsInterner<'_> { impl fmt::Debug for StringsInterner {
#[cold] #[cold]
#[inline(never)] #[inline(never)]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@ -53,17 +51,15 @@ impl fmt::Debug for StringsInterner<'_> {
} }
} }
impl StringsInterner<'_> { impl StringsInterner {
/// Create a new [`StringsInterner`]. /// Create a new [`StringsInterner`].
#[inline(always)] #[inline(always)]
#[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
capacity: MAX_INTERNED_STRINGS, capacity: MAX_INTERNED_STRINGS,
max_string_len: MAX_STRING_LEN, max_string_len: MAX_STRING_LEN,
cache: StraightHashMap::default(), cache: StraightHashMap::default(),
filter: BloomFilterU64::new(), filter: BloomFilterU64::new(),
dummy: PhantomData,
} }
} }
@ -169,14 +165,14 @@ impl StringsInterner<'_> {
} }
} }
impl AddAssign<Self> for StringsInterner<'_> { impl AddAssign<Self> for StringsInterner {
#[inline(always)] #[inline(always)]
fn add_assign(&mut self, rhs: Self) { fn add_assign(&mut self, rhs: Self) {
self.cache.extend(rhs.cache.into_iter()); self.cache.extend(rhs.cache.into_iter());
} }
} }
impl AddAssign<&Self> for StringsInterner<'_> { impl AddAssign<&Self> for StringsInterner {
#[inline(always)] #[inline(always)]
fn add_assign(&mut self, rhs: &Self) { fn add_assign(&mut self, rhs: &Self) {
self.cache self.cache