From 4958d0fe405c94898205aca9e899d2baa77605ea Mon Sep 17 00:00:00 2001 From: jedel1043 Date: Tue, 28 Jun 2022 03:30:42 -0500 Subject: [PATCH] Implement custom string interner --- Cargo.lock | 36 +--- boa_interner/Cargo.toml | 3 +- boa_interner/src/interned_str.rs | 70 +++++++ boa_interner/src/lib.rs | 319 +++++++++---------------------- boa_interner/src/sym.rs | 149 +++++++++++++++ boa_interner/src/tests.rs | 40 +--- 6 files changed, 321 insertions(+), 296 deletions(-) create mode 100644 boa_interner/src/interned_str.rs create mode 100644 boa_interner/src/sym.rs diff --git a/Cargo.lock b/Cargo.lock index daba6e167b6..8986762fc9f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,17 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "ahash" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" -dependencies = [ - "getrandom", - "once_cell", - "version_check", -] - [[package]] name = "aho-corasick" version = "0.7.18" @@ -145,8 +134,9 @@ name = "boa_interner" version = "0.15.0" dependencies = [ "gc", + "phf", + "rustc-hash", "serde", - "string-interner", ] [[package]] @@ -622,15 +612,6 @@ version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" -[[package]] -name = "hashbrown" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" -dependencies = [ - "ahash", -] - [[package]] name = "hashbrown" version = "0.12.1" @@ -797,7 +778,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e" dependencies = [ "autocfg", - "hashbrown 0.12.1", + "hashbrown", ] [[package]] @@ -1528,17 +1509,6 @@ version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e08d8363704e6c71fc928674353e6b7c23dcea9d82d7012c8faf2a3a025f8d0" -[[package]] -name = "string-interner" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e2531d8525b29b514d25e275a43581320d587b86db302b9a7e464bac579648" -dependencies = [ - "cfg-if", - "hashbrown 0.11.2", - "serde", -] - [[package]] name = "strsim" version = "0.8.0" diff --git a/boa_interner/Cargo.toml b/boa_interner/Cargo.toml index 803a4c5b684..04eb8877c2c 100644 --- a/boa_interner/Cargo.toml +++ b/boa_interner/Cargo.toml @@ -11,6 +11,7 @@ categories = ["data-structures"] license = "Unlicense/MIT" [dependencies] -string-interner = "0.14.0" serde = { version = "1.0.137", features = ["derive"], optional = true } gc = { version = "0.4.1", features = ["derive"] } +phf = { version = "0.10.1", features = ["macros"] } +rustc-hash = "1.1.0" diff --git a/boa_interner/src/interned_str.rs b/boa_interner/src/interned_str.rs new file mode 100644 index 00000000000..ccaf50a2a48 --- /dev/null +++ b/boa_interner/src/interned_str.rs @@ -0,0 +1,70 @@ +use std::{borrow::Borrow, ptr::NonNull}; + +/// Wrapper for an interned str pointer, required to +/// quickly check using a hash if a string is inside an [`Interner`]. +/// +/// # Safety +/// +/// This struct could cause Undefined Behaviour on: +/// - Use without ensuring the referenced memory is still allocated. +/// - Construction of an [`InternedStr`] from an invalid [`NonNull`]. +/// +/// In general, this should not be used outside of an [`Interner`]. +#[derive(Debug, Clone)] +pub(super) struct InternedStr { + ptr: NonNull, +} + +impl InternedStr { + /// Create a new interned string from the given `str`. + /// + /// # Safety + /// + /// Not maintaining the invariants specified on the struct definition + /// could cause Undefined Behaviour. + #[inline] + pub(super) unsafe fn new(ptr: NonNull) -> Self { + Self { ptr } + } + + /// Returns a shared reference to the underlying string. + /// + /// # Safety + /// + /// Not maintaining the invariants specified on the struct definition + /// could cause Undefined Behaviour. + #[inline] + pub(super) unsafe fn as_str(&self) -> &str { + // SAFETY: The user must verify the invariants + // specified on the struct definition. + unsafe { self.ptr.as_ref() } + } +} + +impl std::hash::Hash for InternedStr { + fn hash(&self, state: &mut H) { + // SAFETY: The user must verify the invariants + // specified in the struct definition. + unsafe { + self.as_str().hash(state); + } + } +} + +impl Eq for InternedStr {} + +impl PartialEq for InternedStr { + fn eq(&self, other: &Self) -> bool { + // SAFETY: The user must verify the invariants + // specified in the struct definition. + unsafe { self.as_str() == other.as_str() } + } +} + +impl Borrow for InternedStr { + fn borrow(&self) -> &str { + // SAFETY: The user must verify the invariants + // specified in the struct definition. + unsafe { self.as_str() } + } +} diff --git a/boa_interner/src/lib.rs b/boa_interner/src/lib.rs index 11cf49b3ebd..aa13ab269dd 100644 --- a/boa_interner/src/lib.rs +++ b/boa_interner/src/lib.rs @@ -49,6 +49,7 @@ rust_2018_idioms, future_incompatible, nonstandard_style, + unsafe_op_in_unsafe_fn )] #![allow( clippy::module_name_repetitions, @@ -69,46 +70,56 @@ rustdoc::missing_doc_code_examples )] +mod interned_str; +mod sym; #[cfg(test)] mod tests; -use std::{fmt::Display, num::NonZeroUsize}; +pub use sym::*; -use gc::{unsafe_empty_trace, Finalize, Trace}; -#[cfg(feature = "serde")] -use serde::{Deserialize, Serialize}; -use string_interner::{backend::BucketBackend, StringInterner, Symbol}; +use std::{ + fmt::{Debug, Display}, + ptr::NonNull, +}; -/// Backend of the string interner. -type Backend = BucketBackend; +use interned_str::InternedStr; +use rustc_hash::FxHashMap; /// The string interner for Boa. -/// -/// This is a type alias that makes it easier to reference it in the code. -#[derive(Debug)] +#[derive(Debug, Default)] pub struct Interner { - inner: StringInterner, + symbols: FxHashMap, + spans: Vec, + head: String, + full: Vec, } impl Interner { - /// Creates a new `StringInterner` with the given initial capacity. + /// Creates a new `StringInterner`. #[inline] - pub fn with_capacity(cap: usize) -> Self { + pub fn new() -> Self { + Self::default() + } + + pub fn with_capacity(capacity: usize) -> Self { Self { - inner: StringInterner::with_capacity(cap), + symbols: FxHashMap::default(), + spans: Vec::with_capacity(capacity), + head: String::with_capacity(capacity), + full: Vec::new(), } } /// Returns the number of strings interned by the interner. #[inline] pub fn len(&self) -> usize { - self.inner.len() + COMMON_STRINGS.len() + self.spans.len() } - /// Returns `true` if the string interner has no interned strings. #[inline] + /// Returns `true` if the [`Interner`] contains no interned strings. pub fn is_empty(&self) -> bool { - self.inner.is_empty() + COMMON_STRINGS.is_empty() && self.spans.is_empty() } /// Returns the symbol for the given string if any. @@ -119,7 +130,7 @@ impl Interner { T: AsRef, { let string = string.as_ref(); - Self::get_static(string).or_else(|| self.inner.get(string)) + Self::get_common(string).or_else(|| self.symbols.get(string).copied()) } /// Interns the given string. @@ -127,13 +138,34 @@ impl Interner { /// Returns a symbol for resolution into the original string. /// /// # Panics + /// /// If the interner already interns the maximum number of strings possible by the chosen symbol type. pub fn get_or_intern(&mut self, string: T) -> Sym where T: AsRef, { let string = string.as_ref(); - Self::get_static(string).unwrap_or_else(|| self.inner.get_or_intern(string)) + if let Some(sym) = self.get(string) { + return sym; + } + + let capacity = self.head.capacity(); + + if capacity < self.head.len() + string.len() { + let new_cap = (usize::max(capacity, string.len()) + 1).next_power_of_two(); + let new_head = String::with_capacity(new_cap); + let old_head = std::mem::replace(&mut self.head, new_head); + self.full.push(old_head); + } + + let old_len = self.head.len(); + self.head.push_str(string); + let interned_str = NonNull::from(&self.head[old_len..self.head.len()]); + + // SAFETY: We are obtaining a pointer to the internal memory of + // `head`, which is alive through the whole life of `Interner`, so + // this is safe. + unsafe { self.generate_symbol(interned_str) } } /// Interns the given `'static` string. @@ -150,24 +182,26 @@ impl Interner { /// If the interner already interns the maximum number of strings possible /// by the chosen symbol type. pub fn get_or_intern_static(&mut self, string: &'static str) -> Sym { - Self::get_static(string).unwrap_or_else(|| self.inner.get_or_intern_static(string)) - } - - /// Shrink backend capacity to fit the interned strings exactly. - #[inline] - pub fn shrink_to_fit(&mut self) { - self.inner.shrink_to_fit(); + self.get(string).unwrap_or_else(|| { + // SAFETY: a static `str` is always alive, so its pointer + // should therefore always be valid. + unsafe { self.generate_symbol(NonNull::from(string)) } + }) } /// Returns the string for the given symbol if any. #[inline] pub fn resolve(&self, symbol: Sym) -> Option<&str> { - let index = symbol.as_raw().get(); - if index <= Self::STATIC_STRINGS.len() { - Some(Self::STATIC_STRINGS[index - 1]) - } else { - self.inner.resolve(symbol) - } + let index = symbol.get(); + + COMMON_STRINGS.index(index - 1).copied().or_else(|| { + self.spans + .get(symbol.get() - COMMON_STRINGS.len() - 1) + .map(|ptr| + // SAFETY: We always ensure the stored `InternedStr`s always + // reference memory inside `head` and `full` + unsafe {ptr.as_str()}) + }) } /// Returns the string for the given symbol. @@ -180,178 +214,37 @@ impl Interner { self.resolve(symbol).expect("string disappeared") } - /// Gets the symbol of the static string if one of them - fn get_static(string: &str) -> Option { - Self::STATIC_STRINGS - .into_iter() - .enumerate() - .find(|&(_i, s)| string == s) - .map(|(i, _str)| { - let raw = NonZeroUsize::new(i.wrapping_add(1)).expect("static array too big"); - Sym::from_raw(raw) + /// Gets the symbol of the common string if one of them + fn get_common(string: &str) -> Option { + COMMON_STRINGS.get_index(string).map(|idx| + // SAFETY: `idx >= 0`, since it's an `usize`, + // and `idx + 1 > 0` (considering no overflows, but + // an overflow would panic on debug anyways). + unsafe { + Sym::new_unchecked(idx + 1) }) } -} - -impl FromIterator for Interner -where - T: AsRef, -{ - #[inline] - fn from_iter(iter: I) -> Self - where - I: IntoIterator, - { - Self { - inner: StringInterner::from_iter(iter), - } - } -} - -impl Extend for Interner -where - T: AsRef, -{ - #[inline] - fn extend(&mut self, iter: I) - where - I: IntoIterator, - { - self.inner.extend(iter); - } -} - -impl<'a> IntoIterator for &'a Interner { - type Item = (Sym, &'a str); - type IntoIter = <&'a Backend as IntoIterator>::IntoIter; - - #[inline] - fn into_iter(self) -> Self::IntoIter { - self.inner.into_iter() - } -} - -impl Default for Interner { - fn default() -> Self { - Self { - inner: StringInterner::new(), + /// Generates a new symbol for the provided [`str`] pointer. + /// + /// # Safety + /// + /// The caller must ensure `string` points to a valid + /// memory inside `head` and that it won't be invalidated + /// by allocations and deallocations. + unsafe fn generate_symbol(&mut self, string: NonNull) -> Sym { + // SAFETY: a static `str` lives throughout the entirety of the + // program, so an `InternedStr` pointing to it + // is always safe to use. + let next = Sym::new(self.len() + 1).expect("Adding one makes `self.len()` always `> 0`"); + unsafe { + let interned = InternedStr::new(string); + self.spans.push(interned.clone()); + self.symbols.insert(interned, next); } + next } } -/// The string symbol type for Boa. -/// -/// This symbol type is internally a `NonZeroUsize`, which makes it pointer-width in size and it's -/// optimized so that it can occupy 1 pointer width even in an `Option` type. -#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Finalize)] -#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] -#[cfg_attr(feature = "serde", serde(transparent))] -#[allow(clippy::unsafe_derive_deserialize)] -pub struct Sym { - value: NonZeroUsize, -} - -impl Sym { - /// Padding for the symbol internal value. - const PADDING: usize = Interner::STATIC_STRINGS.len() + 1; - - /// Symbol for the empty string (`""`). - pub const EMPTY_STRING: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(1)) }; - - /// Symbol for the `"arguments"` string. - pub const ARGUMENTS: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(2)) }; - - /// Symbol for the `"await"` string. - pub const AWAIT: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(3)) }; - - /// Symbol for the `"yield"` string. - pub const YIELD: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(4)) }; - - /// Symbol for the `"eval"` string. - pub const EVAL: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(5)) }; - - /// Symbol for the `"default"` string. - pub const DEFAULT: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(6)) }; - - /// Symbol for the `"null"` string. - pub const NULL: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(7)) }; - - /// Symbol for the `"RegExp"` string. - pub const REGEXP: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(8)) }; - - /// Symbol for the `"get"` string. - pub const GET: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(9)) }; - - /// Symbol for the `"set"` string. - pub const SET: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(10)) }; - - /// Symbol for the `"
"` string. - pub const MAIN: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(11)) }; - - /// Symbol for the `"raw"` string. - pub const RAW: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(12)) }; - - /// Symbol for the `"static"` string. - pub const STATIC: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(13)) }; - - /// Symbol for the `"prototype"` string. - pub const PROTOTYPE: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(14)) }; - - /// Symbol for the `"constructor"` string. - pub const CONSTRUCTOR: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(15)) }; - - /// Symbol for the `"implements"` string. - pub const IMPLEMENTS: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(16)) }; - - /// Symbol for the `"interface"` string. - pub const INTERFACE: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(17)) }; - - /// Symbol for the `"let"` string. - pub const LET: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(18)) }; - - /// Symbol for the `"package"` string. - pub const PACKAGE: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(19)) }; - - /// Symbol for the `"private"` string. - pub const PRIVATE: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(20)) }; - - /// Symbol for the `"protected"` string. - pub const PROTECTED: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(21)) }; - - /// Symbol for the `"public"` string. - pub const PUBLIC: Self = unsafe { Self::from_raw(NonZeroUsize::new_unchecked(22)) }; - - /// Creates a `Sym` from a raw `NonZeroUsize`. - const fn from_raw(value: NonZeroUsize) -> Self { - Self { value } - } - - /// Retrieves the raw `NonZeroUsize` for this symbol. - const fn as_raw(self) -> NonZeroUsize { - self.value - } -} - -impl Symbol for Sym { - #[inline] - fn try_from_usize(index: usize) -> Option { - index - .checked_add(Self::PADDING) - .and_then(NonZeroUsize::new) - .map(|value| Self { value }) - } - - #[inline] - fn to_usize(self) -> usize { - self.value.get() - Self::PADDING - } -} - -// Safe because `Sym` implements `Copy`. -unsafe impl Trace for Sym { - unsafe_empty_trace!(); -} - /// Converts a given element to a string using an interner. pub trait ToInternedString { /// Converts a given element to a string using an interner. @@ -366,33 +259,3 @@ where self.to_string() } } - -impl Interner { - /// List of commonly used static strings. - /// - /// Make sure that any string added as a `Sym` constant is also added here. - const STATIC_STRINGS: [&'static str; 22] = [ - "", - "arguments", - "await", - "yield", - "eval", - "default", - "null", - "RegExp", - "get", - "set", - "
", - "raw", - "static", - "prototype", - "constructor", - "implements", - "interface", - "let", - "package", - "private", - "protected", - "public", - ]; -} diff --git a/boa_interner/src/sym.rs b/boa_interner/src/sym.rs new file mode 100644 index 00000000000..d2f2c9c21b8 --- /dev/null +++ b/boa_interner/src/sym.rs @@ -0,0 +1,149 @@ +use std::num::NonZeroUsize; + +use gc::{unsafe_empty_trace, Finalize, Trace}; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; + +/// The string symbol type for Boa. +/// +/// This symbol type is internally a `NonZeroUsize`, which makes it pointer-width in size and it's +/// optimized so that it can occupy 1 pointer width even in an `Option` type. +#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Finalize)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +#[cfg_attr(feature = "serde", serde(transparent))] +#[allow(clippy::unsafe_derive_deserialize)] +pub struct Sym { + value: NonZeroUsize, +} + +impl Sym { + /// Symbol for the empty string (`""`). + pub const EMPTY_STRING: Self = unsafe { Self::new_unchecked(1) }; + + /// Symbol for the `"arguments"` string. + pub const ARGUMENTS: Self = unsafe { Self::new_unchecked(2) }; + + /// Symbol for the `"await"` string. + pub const AWAIT: Self = unsafe { Self::new_unchecked(3) }; + + /// Symbol for the `"yield"` string. + pub const YIELD: Self = unsafe { Self::new_unchecked(4) }; + + /// Symbol for the `"eval"` string. + pub const EVAL: Self = unsafe { Self::new_unchecked(5) }; + + /// Symbol for the `"default"` string. + pub const DEFAULT: Self = unsafe { Self::new_unchecked(6) }; + + /// Symbol for the `"null"` string. + pub const NULL: Self = unsafe { Self::new_unchecked(7) }; + + /// Symbol for the `"RegExp"` string. + pub const REGEXP: Self = unsafe { Self::new_unchecked(8) }; + + /// Symbol for the `"get"` string. + pub const GET: Self = unsafe { Self::new_unchecked(9) }; + + /// Symbol for the `"set"` string. + pub const SET: Self = unsafe { Self::new_unchecked(10) }; + + /// Symbol for the `"
"` string. + pub const MAIN: Self = unsafe { Self::new_unchecked(11) }; + + /// Symbol for the `"raw"` string. + pub const RAW: Self = unsafe { Self::new_unchecked(12) }; + + /// Symbol for the `"static"` string. + pub const STATIC: Self = unsafe { Self::new_unchecked(13) }; + + /// Symbol for the `"prototype"` string. + pub const PROTOTYPE: Self = unsafe { Self::new_unchecked(14) }; + + /// Symbol for the `"constructor"` string. + pub const CONSTRUCTOR: Self = unsafe { Self::new_unchecked(15) }; + + /// Symbol for the `"implements"` string. + pub const IMPLEMENTS: Self = unsafe { Self::new_unchecked(16) }; + + /// Symbol for the `"interface"` string. + pub const INTERFACE: Self = unsafe { Self::new_unchecked(17) }; + + /// Symbol for the `"let"` string. + pub const LET: Self = unsafe { Self::new_unchecked(18) }; + + /// Symbol for the `"package"` string. + pub const PACKAGE: Self = unsafe { Self::new_unchecked(19) }; + + /// Symbol for the `"private"` string. + pub const PRIVATE: Self = unsafe { Self::new_unchecked(20) }; + + /// Symbol for the `"protected"` string. + pub const PROTECTED: Self = unsafe { Self::new_unchecked(21) }; + + /// Symbol for the `"public"` string. + pub const PUBLIC: Self = unsafe { Self::new_unchecked(22) }; + + #[inline] + /// Creates a new [`Sym`] from the provided `value`, or returns `None` if `index` is zero. + pub(super) fn new(value: usize) -> Option { + NonZeroUsize::new(value).map(|value| Self { value }) + } + + #[inline] + /// Creates a new [`Sym`] from the provided `value`, without checking if `value` is not zero + /// + /// # Safety + /// + /// `value` must not be zero. + pub(super) const unsafe fn new_unchecked(value: usize) -> Self { + Self { + value: + // SAFETY: The user must ensure the invariants of the function. + unsafe { + NonZeroUsize::new_unchecked(value) + }, + } + } + + #[inline] + /// Returns the internal value of the [`Sym`] + pub(super) const fn get(self) -> usize { + self.value.get() + } +} + +// Safe because `Sym` implements `Copy`. +unsafe impl Trace for Sym { + unsafe_empty_trace!(); +} + +/// Ordered set of commonly used static strings. +/// +/// # Note +/// +/// `COMMON_STRINGS` and the constants defined in [`Sym`] must always +/// be in sync. +pub(super) static COMMON_STRINGS: phf::OrderedSet<&'static str> = phf::phf_ordered_set! { + "", + "arguments", + "await", + "yield", + "eval", + "default", + "null", + "RegExp", + "get", + "set", + "
", + "raw", + "static", + "prototype", + "constructor", + "implements", + "interface", + "let", + "package", + "private", + "protected", + "public", +}; diff --git a/boa_interner/src/tests.rs b/boa_interner/src/tests.rs index 3df0fd194f5..d42d5b9bf2f 100644 --- a/boa_interner/src/tests.rs +++ b/boa_interner/src/tests.rs @@ -1,53 +1,24 @@ -use crate::{Interner, Sym}; -use std::num::NonZeroUsize; +use crate::{Interner, Sym, COMMON_STRINGS}; #[track_caller] fn sym_from_usize(index: usize) -> Sym { - Sym::from_raw(NonZeroUsize::new(index).expect("Invalid NonZeroUsize")) + Sym::new(index).expect("Invalid NonZeroUsize") } #[test] fn check_static_strings() { let mut interner = Interner::default(); - for (i, str) in Interner::STATIC_STRINGS.into_iter().enumerate() { + for (i, str) in COMMON_STRINGS.into_iter().enumerate() { assert_eq!(interner.get_or_intern(str), sym_from_usize(i + 1)); } } -#[test] -fn check_constants() { - assert_eq!(Sym::EMPTY_STRING, sym_from_usize(1)); - assert_eq!(Sym::ARGUMENTS, sym_from_usize(2)); - assert_eq!(Sym::AWAIT, sym_from_usize(3)); - assert_eq!(Sym::YIELD, sym_from_usize(4)); - assert_eq!(Sym::EVAL, sym_from_usize(5)); - assert_eq!(Sym::DEFAULT, sym_from_usize(6)); - assert_eq!(Sym::NULL, sym_from_usize(7)); - assert_eq!(Sym::REGEXP, sym_from_usize(8)); - assert_eq!(Sym::GET, sym_from_usize(9)); - assert_eq!(Sym::SET, sym_from_usize(10)); - assert_eq!(Sym::MAIN, sym_from_usize(11)); - assert_eq!(Sym::RAW, sym_from_usize(12)); - assert_eq!(Sym::STATIC, sym_from_usize(13)); - assert_eq!(Sym::PROTOTYPE, sym_from_usize(14)); - assert_eq!(Sym::CONSTRUCTOR, sym_from_usize(15)); - assert_eq!(Sym::IMPLEMENTS, sym_from_usize(16)); - assert_eq!(Sym::INTERFACE, sym_from_usize(17)); - assert_eq!(Sym::LET, sym_from_usize(18)); - assert_eq!(Sym::PACKAGE, sym_from_usize(19)); - assert_eq!(Sym::PRIVATE, sym_from_usize(20)); - assert_eq!(Sym::PROTECTED, sym_from_usize(21)); - assert_eq!(Sym::PUBLIC, sym_from_usize(22)); -} - #[test] fn check_new_string() { let mut interner = Interner::default(); - assert!( - interner.get_or_intern("my test string").as_raw().get() > Interner::STATIC_STRINGS.len() - ); + assert!(interner.get_or_intern("my test string").get() > COMMON_STRINGS.len()); } #[test] @@ -71,8 +42,9 @@ fn check_resolve() { fn check_static_resolve() { let mut interner = Interner::default(); - for string in Interner::STATIC_STRINGS + for string in COMMON_STRINGS .into_iter() + .copied() .chain(["my test str", "hello world", ";"].into_iter()) { let sym = interner.get_or_intern_static(string);