lalrpop_intern/
lib.rs

1use std::collections::HashMap;
2use std::cell::RefCell;
3use std::fmt::{Debug, Display, Error, Formatter};
4use std::cmp::{Ord, Ordering, PartialOrd};
5
6#[cfg(test)]
7mod test;
8
9thread_local! {
10    static INTERNER_TLS: RefCell<Interner> =
11        RefCell::new(Interner::new())
12}
13
14pub struct Interner {
15    map: HashMap<String, InternedString>,
16    strings: Vec<String>,
17}
18
19#[derive(Copy, Clone, Hash, Eq, PartialEq)]
20pub struct InternedString {
21    index: u32,
22}
23
24pub fn intern(s: &str) -> InternedString {
25    write(|interner| {
26        match interner.map.get(s) {
27            Some(&v) => {
28                return v;
29            }
30            None => {}
31        }
32
33        let index = interner.strings.len() as u32;
34        let result = InternedString { index: index };
35        interner.map.insert(s.to_string(), result);
36        interner.strings.push(s.to_string());
37        return result;
38    })
39}
40
41pub fn read<F, R>(f: F) -> R
42where
43    F: FnOnce(&Interner) -> R,
44{
45    INTERNER_TLS.with(|interner| f(&*interner.borrow()))
46}
47
48fn write<F, R>(f: F) -> R
49where
50    F: FnOnce(&mut Interner) -> R,
51{
52    INTERNER_TLS.with(|interner| f(&mut *interner.borrow_mut()))
53}
54
55impl Interner {
56    fn new() -> Interner {
57        Interner {
58            map: HashMap::new(),
59            strings: vec![],
60        }
61    }
62
63    pub fn data(&self, i: InternedString) -> &str {
64        &self.strings[i.index()]
65    }
66}
67
68impl InternedString {
69    fn index(&self) -> usize {
70        self.index as usize
71    }
72
73    pub fn len(&self) -> usize {
74        read(|interner| interner.data(*self).len())
75    }
76}
77
78impl Debug for InternedString {
79    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
80        read(|interner| Debug::fmt(&interner.data(*self), fmt))
81    }
82}
83
84impl Display for InternedString {
85    fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
86        read(|interner| Display::fmt(&interner.data(*self), fmt))
87    }
88}
89
90impl PartialOrd<InternedString> for InternedString {
91    fn partial_cmp(&self, other: &InternedString) -> Option<Ordering> {
92        read(|interner| PartialOrd::partial_cmp(interner.data(*self), interner.data(*other)))
93    }
94}
95
96impl Ord for InternedString {
97    fn cmp(&self, other: &InternedString) -> Ordering {
98        read(|interner| Ord::cmp(interner.data(*self), interner.data(*other)))
99    }
100}