use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use std::sync::{Arc, OnceLock, RwLock};
thread_local! {
static LOCAL_TABLE: RefCell<HashMap<String, Arc<str>>> =
RefCell::new(HashMap::with_capacity(32));
}
fn table() -> &'static RwLock<HashSet<Arc<str>>> {
static TABLE: OnceLock<RwLock<HashSet<Arc<str>>>> = OnceLock::new();
TABLE.get_or_init(|| RwLock::new(HashSet::with_capacity(64)))
}
pub fn intern(s: &str) -> Arc<str> {
if let Some(existing) = LOCAL_TABLE.with(|local| local.borrow().get(s).cloned()) {
return existing;
}
let shared = intern_global(s);
LOCAL_TABLE.with(|local| {
local
.borrow_mut()
.insert(shared.as_ref().to_owned(), shared.clone());
});
shared
}
fn intern_global(s: &str) -> Arc<str> {
{
let guard = table().read().unwrap_or_else(|p| p.into_inner());
if let Some(existing) = guard.get(s) {
return existing.clone();
}
}
let mut guard = table().write().unwrap_or_else(|p| p.into_inner());
if let Some(existing) = guard.get(s) {
return existing.clone();
}
let fresh: Arc<str> = Arc::from(s);
guard.insert(fresh.clone());
fresh
}
pub fn intern_owned(s: String) -> Arc<str> {
if let Some(existing) = LOCAL_TABLE.with(|local| local.borrow().get(s.as_str()).cloned()) {
return existing;
}
let shared = intern_owned_global(s);
LOCAL_TABLE.with(|local| {
local
.borrow_mut()
.insert(shared.as_ref().to_owned(), shared.clone());
});
shared
}
fn intern_owned_global(s: String) -> Arc<str> {
{
let guard = table().read().unwrap_or_else(|p| p.into_inner());
if let Some(existing) = guard.get(s.as_str()) {
return existing.clone();
}
}
let mut guard = table().write().unwrap_or_else(|p| p.into_inner());
if let Some(existing) = guard.get(s.as_str()) {
return existing.clone();
}
let fresh: Arc<str> = Arc::from(s.into_boxed_str());
guard.insert(fresh.clone());
fresh
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn intern_returns_pointer_equal_arcs() {
let a = intern("first_name");
let b = intern("first_name");
assert!(Arc::ptr_eq(&a, &b));
}
#[test]
fn distinct_keys_get_distinct_arcs() {
let a = intern("alpha");
let b = intern("beta");
assert!(!Arc::ptr_eq(&a, &b));
assert_eq!(&*a, "alpha");
assert_eq!(&*b, "beta");
}
#[test]
fn intern_owned_dedups_with_intern() {
let a = intern("from_borrowed");
let b = intern_owned(String::from("from_borrowed"));
assert!(Arc::ptr_eq(&a, &b));
}
}