#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, vec::Vec};
#[cfg(feature = "std")]
use lasso::{Key, Rodeo, Spur};
#[cfg(feature = "std")]
use std::{boxed::Box, vec::Vec};
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct SymbolId(pub u32);
#[cfg(feature = "std")]
pub struct StringInterner {
rodeo: Rodeo<Spur>,
}
#[cfg(feature = "std")]
impl StringInterner {
#[must_use]
pub fn new() -> Self {
Self {
rodeo: Rodeo::new(),
}
}
pub fn intern(&mut self, s: &str) -> SymbolId {
let key = self.rodeo.get_or_intern(s);
SymbolId(u32::try_from(key.into_usize()).unwrap_or(0))
}
#[must_use]
pub fn finish(self) -> StringTable {
let mut pool: Vec<Box<str>> = vec![Box::<str>::from(""); self.rodeo.len()];
for (key, s) in self.rodeo.iter() {
let idx = key.into_usize();
if idx < pool.len() {
pool[idx] = s.into();
}
}
StringTable::Owned(pool)
}
#[must_use]
pub fn resolve(&self, id: SymbolId) -> &str {
Spur::try_from_usize(id.0 as usize)
.and_then(|k| self.rodeo.try_resolve(&k))
.unwrap_or("?")
}
}
#[cfg(feature = "std")]
impl Default for StringInterner {
fn default() -> Self {
Self::new()
}
}
#[derive(Clone, Debug)]
pub enum StringTable {
Owned(Vec<Box<str>>),
Static(&'static [&'static str]),
}
impl StringTable {
#[must_use]
pub fn resolve(&self, id: SymbolId) -> &str {
match self {
Self::Owned(v) => v
.get(id.0 as usize)
.map_or("?", core::convert::AsRef::as_ref),
Self::Static(s) => s.get(id.0 as usize).copied().unwrap_or("?"),
}
}
#[must_use]
pub fn pool_strings_for_codegen(&self) -> Vec<&str> {
match self {
Self::Owned(v) => v.iter().map(core::convert::AsRef::as_ref).collect(),
Self::Static(s) => s.to_vec(),
}
}
#[must_use]
pub const fn from_static_pool(pool: &'static [&'static str]) -> Self {
Self::Static(pool)
}
}