Skip to main content

veryl_parser/
text_table.rs

1use crate::resource_table::PathId;
2use std::cell::RefCell;
3use std::collections::HashMap;
4use std::sync::Arc;
5
6#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
7pub struct TextId(pub usize);
8
9thread_local!(static TEXT_ID: RefCell<usize> = const { RefCell::new(0) });
10
11pub fn new_text_id() -> TextId {
12    TEXT_ID.with(|f| {
13        let mut ret = f.borrow_mut();
14        *ret += 1;
15        TextId(*ret)
16    })
17}
18
19/// Returns the last issued text ID value. Used to delimit per-file ID
20/// windows for fragment caching.
21pub fn peek_text_id() -> usize {
22    TEXT_ID.with(|f| *f.borrow())
23}
24
25/// Reserves `count` consecutive text IDs and returns the value the counter
26/// had before the reservation. The reserved IDs are `base+1..=base+count`.
27pub fn reserve_text_ids(count: usize) -> usize {
28    TEXT_ID.with(|f| {
29        let mut ret = f.borrow_mut();
30        let base = *ret;
31        *ret += count;
32        base
33    })
34}
35
36/// Inserts a text entry under a caller-provided (reserved) ID without
37/// touching `current_text`. Used by fragment restore.
38pub fn insert_with_id(id: TextId, info: TextInfo) {
39    TEXT_TABLE.with(|f| {
40        f.borrow_mut().table.insert(id, Arc::new(info));
41    })
42}
43
44#[derive(Clone, Debug)]
45pub struct TextInfo {
46    pub text: String,
47    pub path: PathId,
48}
49
50#[derive(Clone, Default, Debug)]
51pub struct TextTable {
52    current_text: TextId,
53    // `Arc`-shared so `export_tables`/`import_tables` bumps refcounts
54    // instead of duplicating every source file (MB per entry on large designs).
55    table: HashMap<TextId, Arc<TextInfo>>,
56}
57
58impl TextTable {
59    pub fn set_current_text(&mut self, info: TextInfo) -> TextId {
60        let id = new_text_id();
61        self.table.insert(id, Arc::new(info));
62        self.current_text = id;
63        id
64    }
65
66    pub fn get_current_text(&self) -> TextId {
67        self.current_text
68    }
69
70    pub fn get(&self, id: TextId) -> Option<TextInfo> {
71        self.table.get(&id).map(|x| (**x).clone())
72    }
73
74    pub fn drop(&mut self, id: PathId) {
75        self.table.retain(|_, x| x.path != id);
76    }
77}
78
79thread_local!(static TEXT_TABLE: RefCell<TextTable> = RefCell::new(TextTable::default()));
80
81pub fn set_current_text(info: TextInfo) -> TextId {
82    TEXT_TABLE.with(|f| f.borrow_mut().set_current_text(info))
83}
84
85pub fn get_current_text() -> TextId {
86    TEXT_TABLE.with(|f| f.borrow().get_current_text())
87}
88
89pub fn get(id: TextId) -> Option<TextInfo> {
90    TEXT_TABLE.with(|f| f.borrow().get(id))
91}
92
93pub fn drop(id: PathId) {
94    TEXT_TABLE.with(|f| f.borrow_mut().drop(id))
95}
96
97/// Snapshot of the calling thread's `text_table`. Cheap to pass between
98/// threads — `TextInfo` payloads are `Arc`-shared.
99pub struct TextTableSnapshot {
100    text_table: TextTable,
101}
102
103pub fn export_tables() -> TextTableSnapshot {
104    TextTableSnapshot {
105        text_table: TEXT_TABLE.with(|f| f.borrow().clone()),
106    }
107}
108
109pub fn import_tables(snapshot: &TextTableSnapshot) {
110    TEXT_TABLE.with(|f| *f.borrow_mut() = snapshot.text_table.clone());
111}