#![deny(missing_docs)]
use lasso::{Key, Rodeo, Spur};
#[derive(Debug, Clone, Default)]
pub struct StringInterner(Rodeo);
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct InternKey(Spur);
impl StringInterner {
pub fn get_or_intern(&mut self, s: &str) -> InternKey {
InternKey(self.0.get_or_intern(s))
}
pub fn resolve(&self, key: &InternKey) -> &str {
self.0.resolve(&key.0)
}
pub fn strings(&self) -> impl Iterator<Item = &str> {
self.0.strings()
}
pub fn len(&self) -> usize {
self.0.len()
}
}
impl InternKey {
pub(crate) fn to_index(self) -> usize {
self.0.into_usize()
}
pub(crate) fn from_index(index: usize) -> Option<Self> {
Spur::try_from_usize(index).map(InternKey)
}
}
pub fn intern_option(interner: &mut StringInterner, s: Option<&str>) -> Option<InternKey> {
s.map(|val| interner.get_or_intern(val))
}
pub fn resolve_option(interner: &StringInterner, key: Option<InternKey>) -> Option<String> {
key.map(|k| interner.resolve(&k).to_string())
}
pub fn intern_vec(interner: &mut StringInterner, strings: &[String]) -> Vec<InternKey> {
strings
.iter()
.map(|s| interner.get_or_intern(s.as_str()))
.collect()
}
pub fn resolve_vec(interner: &StringInterner, keys: &[InternKey]) -> Vec<String> {
keys
.iter()
.map(|k| interner.resolve(k).to_string())
.collect()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_intern_option_some() {
let mut interner = StringInterner::default();
let key = intern_option(&mut interner, Some("test"));
assert!(key.is_some());
assert_eq!(resolve_option(&interner, key), Some("test".to_string()));
}
#[test]
fn test_intern_option_none() {
let mut interner = StringInterner::default();
let key = intern_option(&mut interner, None);
assert!(key.is_none());
assert_eq!(resolve_option(&interner, key), None);
}
#[test]
fn test_intern_vec() {
let mut interner = StringInterner::default();
let strings = vec!["a".to_string(), "b".to_string(), "c".to_string()];
let keys = intern_vec(&mut interner, &strings);
assert_eq!(keys.len(), 3);
assert_eq!(resolve_vec(&interner, &keys), strings);
}
#[test]
fn test_intern_vec_empty() {
let mut interner = StringInterner::default();
let strings: Vec<String> = vec![];
let keys = intern_vec(&mut interner, &strings);
assert!(keys.is_empty());
assert!(resolve_vec(&interner, &keys).is_empty());
}
#[test]
fn test_deduplication() {
let mut interner = StringInterner::default();
let key1 = interner.get_or_intern("duplicate");
let key2 = interner.get_or_intern("duplicate");
assert_eq!(key1, key2);
assert_eq!(interner.resolve(&key1), "duplicate");
}
#[test]
fn test_multiple_strings() {
let mut interner = StringInterner::default();
let key_a = interner.get_or_intern("a");
let key_b = interner.get_or_intern("b");
let key_a2 = interner.get_or_intern("a");
assert_eq!(key_a, key_a2);
assert_ne!(key_a, key_b);
assert_eq!(interner.resolve(&key_b), "b");
}
}