veryl_parser/
resource_table.rs1use 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}