1use std::cell::RefCell;
2
3use string_interner::backend::DefaultBackend;
4use string_interner::symbol::DefaultSymbol;
5use string_interner::StringInterner;
6
7pub type InternedStr = DefaultSymbol;
9
10#[derive(Debug)]
12pub struct InternPool {
13 inner: RefCell<StringInterner<DefaultBackend>>,
14}
15
16impl Default for InternPool {
17 fn default() -> Self {
18 Self {
19 inner: RefCell::new(StringInterner::new()),
20 }
21 }
22}
23
24impl InternPool {
25 pub fn intern<S>(&self, value: S) -> InternedStr
27 where
28 S: AsRef<str>,
29 {
30 self.inner.borrow_mut().get_or_intern(value.as_ref())
31 }
32
33 pub fn resolve_owned(&self, symbol: InternedStr) -> Option<String> {
37 self.inner.borrow().resolve(symbol).map(|s| s.to_owned())
38 }
39
40 pub fn with_resolved<R, F>(&self, symbol: InternedStr, f: F) -> Option<R>
42 where
43 F: FnOnce(&str) -> R,
44 {
45 self.inner.borrow().resolve(symbol).map(f)
46 }
47}
48
49#[cfg(test)]
50mod tests {
51 use super::*;
52
53 #[test]
54 fn interning_returns_stable_symbol() {
55 let pool = InternPool::default();
56 let first = pool.intern("foo");
57 let second = pool.intern("foo");
58 assert_eq!(
59 first, second,
60 "Interned symbols should be stable for the same string"
61 );
62 }
63
64 #[test]
65 fn resolve_owned_recovers_string() {
66 let pool = InternPool::default();
67 let sym = pool.intern("bar");
68 let resolved = pool
69 .resolve_owned(sym)
70 .expect("symbol should resolve to a string");
71 assert_eq!(resolved, "bar");
72 }
73
74 #[test]
75 fn with_resolved_provides_borrowed_str() {
76 let pool = InternPool::default();
77 let sym = pool.intern("baz");
78 let length = pool
79 .with_resolved(sym, |s| s.len())
80 .expect("symbol should resolve to a closure result");
81 assert_eq!(length, 3);
82 }
83}