use lasso::{Key, Spur, ThreadedRodeo};
use rustc_hash::FxBuildHasher;
use std::sync::{LazyLock, OnceLock};
pub static INTERNER: LazyLock<ThreadedRodeo<Spur, FxBuildHasher>> =
LazyLock::new(|| ThreadedRodeo::with_hasher(FxBuildHasher));
const MAX_RETRIES: usize = 1024;
#[inline(always)]
pub fn intern(s: &str) -> Spur {
for _ in 0..MAX_RETRIES {
match INTERNER.try_get_or_intern(s) {
Ok(key) => return key,
Err(_) => std::thread::yield_now(),
}
}
panic!("string interner failed after {MAX_RETRIES} attempts for {s:?}");
}
#[inline(always)]
pub fn resolve(key: Spur) -> &'static str {
INTERNER.resolve(&key)
}
static RESOLVED: OnceLock<Box<[&'static str]>> = OnceLock::new();
fn build_snapshot() -> Box<[&'static str]> {
let mut table: Vec<&'static str> = vec![""; INTERNER.len()];
for (key, string) in INTERNER.iter() {
table[key.into_usize()] = string;
}
table.into_boxed_slice()
}
#[inline]
pub fn resolve_out(key: Spur) -> &'static str {
let table = RESOLVED.get_or_init(build_snapshot);
match table.get(key.into_usize()) {
Some(&string) => string,
None => resolve(key),
}
}