Skip to main content

veryl_parser/
resource_table.rs

1use bimap::BiMap;
2use std::borrow::Borrow;
3use std::cell::RefCell;
4use std::collections::HashMap;
5use std::fmt;
6use std::hash::Hash;
7use std::path::{Path, PathBuf};
8
9#[derive(Default)]
10pub struct GlobalTable<T, U>
11where
12    T: Hash + Eq,
13    U: Hash + Eq,
14{
15    table: BiMap<T, U>,
16    last: U,
17}
18
19impl<T, U> Clone for GlobalTable<T, U>
20where
21    T: Hash + Eq + Clone,
22    U: Hash + Eq + Clone,
23{
24    fn clone(&self) -> Self {
25        Self {
26            table: self.table.clone(),
27            last: self.last.clone(),
28        }
29    }
30}
31
32impl<T, U> GlobalTable<T, U>
33where
34    T: Hash + Eq,
35    U: Hash + Eq + Copy + Incrementable,
36{
37    pub fn insert(&mut self, value: T) -> U {
38        if let Some(id) = self.table.get_by_left(&value) {
39            *id
40        } else {
41            let id = self.last;
42            self.table.insert(value, id);
43            self.last.inc();
44            id
45        }
46    }
47
48    pub fn get_value(&self, id: U) -> Option<&T> {
49        self.table.get_by_right(&id)
50    }
51
52    pub fn get_id<V: Borrow<T>>(&self, value: V) -> Option<U> {
53        self.table.get_by_left(value.borrow()).copied()
54    }
55}
56
57#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
58pub struct StrId(pub usize);
59#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
60pub struct PathId(pub usize);
61#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
62pub struct TokenId(pub usize);
63
64pub trait Incrementable {
65    fn inc(&mut self);
66}
67
68impl Incrementable for StrId {
69    fn inc(&mut self) {
70        self.0 += 1;
71    }
72}
73
74impl Incrementable for PathId {
75    fn inc(&mut self) {
76        self.0 += 1;
77    }
78}
79
80impl fmt::Display for StrId {
81    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
82        let text = get_str_value(*self).unwrap();
83        text.fmt(f)
84    }
85}
86
87impl fmt::Display for PathId {
88    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
89        let text = format!("{}", get_path_value(*self).unwrap().to_string_lossy());
90        text.fmt(f)
91    }
92}
93
94impl fmt::Display for TokenId {
95    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96        self.0.fmt(f)
97    }
98}
99
100impl From<&str> for StrId {
101    fn from(x: &str) -> Self {
102        insert_str(x)
103    }
104}
105
106thread_local!(static STRING_TABLE: RefCell<GlobalTable<String, StrId>> = RefCell::new(GlobalTable::default()));
107thread_local!(static PATHBUF_TABLE: RefCell<GlobalTable<PathBuf, PathId>> = RefCell::new(GlobalTable::default()));
108thread_local!(static TOKEN_ID: RefCell<usize> = const { RefCell::new(0) });
109thread_local!(static CANONICAL_CACHE: RefCell<HashMap<StrId, StrId>> = RefCell::new(HashMap::new()));
110
111pub fn insert_str(value: &str) -> StrId {
112    STRING_TABLE.with(|f| f.borrow_mut().insert(value.to_owned()))
113}
114
115pub fn insert_path(value: &Path) -> PathId {
116    PATHBUF_TABLE.with(|f| f.borrow_mut().insert(value.to_owned()))
117}
118
119pub fn get_str_value(id: StrId) -> Option<String> {
120    STRING_TABLE.with(|f| f.borrow().get_value(id).map(|x| x.to_owned()))
121}
122
123pub fn get_path_value(id: PathId) -> Option<PathBuf> {
124    PATHBUF_TABLE.with(|f| f.borrow().get_value(id).map(|x| x.to_owned()))
125}
126
127pub fn canonical_str_id(id: StrId) -> StrId {
128    CANONICAL_CACHE.with(|cache| {
129        if let Some(&cached) = cache.borrow().get(&id) {
130            return cached;
131        }
132        let canonical = if let Some(text) = get_str_value(id) {
133            if let Some(stripped) = text.strip_prefix("r#") {
134                insert_str(stripped)
135            } else {
136                id
137            }
138        } else {
139            id
140        };
141        cache.borrow_mut().insert(id, canonical);
142        canonical
143    })
144}
145
146pub fn get_str_id<T: Borrow<String>>(value: T) -> Option<StrId> {
147    STRING_TABLE.with(|f| f.borrow().get_id(value).map(|x| x.to_owned()))
148}
149
150pub fn get_path_id<T: Borrow<PathBuf>>(value: T) -> Option<PathId> {
151    PATHBUF_TABLE.with(|f| f.borrow().get_id(value).map(|x| x.to_owned()))
152}
153
154pub struct ResourceTableSnapshot {
155    string_table: GlobalTable<String, StrId>,
156    pathbuf_table: GlobalTable<PathBuf, PathId>,
157}
158
159pub fn export_tables() -> ResourceTableSnapshot {
160    ResourceTableSnapshot {
161        string_table: STRING_TABLE.with(|f| f.borrow().clone()),
162        pathbuf_table: PATHBUF_TABLE.with(|f| f.borrow().clone()),
163    }
164}
165
166pub fn import_tables(snapshot: &ResourceTableSnapshot) {
167    STRING_TABLE.with(|f| *f.borrow_mut() = snapshot.string_table.clone());
168    PATHBUF_TABLE.with(|f| *f.borrow_mut() = snapshot.pathbuf_table.clone());
169    CANONICAL_CACHE.with(|f| f.borrow_mut().clear());
170}
171
172pub fn new_token_id() -> TokenId {
173    TOKEN_ID.with(|f| {
174        let mut ret = f.borrow_mut();
175        *ret += 1;
176        TokenId(*ret)
177    })
178}