rune/compile/
pool.rs
1use core::cell::Cell;
2use core::fmt;
3
4use crate as rune;
5use crate::alloc::prelude::*;
6use crate::alloc::try_vec;
7use crate::alloc::{self, HashMap, Vec};
8#[cfg(feature = "emit")]
9use crate::compile::Location;
10use crate::compile::{self, Visibility};
11use crate::parse::{Parse, Parser};
12use crate::{Hash, Item, ItemBuf};
13
14#[derive(Default, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
16#[try_clone(copy)]
17#[repr(transparent)]
18pub(crate) struct ModId(u32);
19
20impl fmt::Display for ModId {
21 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
22 self.0.fmt(f)
23 }
24}
25
26impl fmt::Debug for ModId {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 self.0.fmt(f)
29 }
30}
31
32#[derive(Default, TryClone, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
34#[try_clone(copy)]
35#[repr(transparent)]
36pub struct ItemId(u32);
37
38impl ItemId {
39 pub(crate) const ROOT: ItemId = ItemId(0);
41}
42
43impl Parse for ItemId {
44 #[inline]
45 fn parse(_: &mut Parser<'_>) -> compile::Result<Self> {
46 Ok(ItemId::ROOT)
47 }
48}
49
50impl fmt::Debug for ItemId {
51 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
52 self.0.fmt(f)
53 }
54}
55
56impl fmt::Display for ItemId {
57 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
58 self.0.fmt(f)
59 }
60}
61
62#[derive(Debug)]
64#[non_exhaustive]
65pub(crate) struct ModMeta {
66 #[cfg(feature = "emit")]
68 pub(crate) location: Location,
69 pub(crate) item: ItemId,
71 pub(crate) visibility: Visibility,
73 pub(crate) parent: Option<ModId>,
75}
76
77impl ModMeta {
78 pub(crate) fn is_public(&self, pool: &Pool) -> bool {
80 let mut current = Some(self);
81
82 while let Some(m) = current.take() {
83 if !m.visibility.is_public() {
84 return false;
85 }
86
87 current = m.parent.map(|id| pool.module(id));
88 }
89
90 true
91 }
92}
93
94macro_rules! alloc_item {
95 ($self:expr, $item:expr) => {{
96 let item = $item;
97 let hash = Hash::type_hash(item);
98
99 match $self.hash_to_item.get(&hash) {
100 Some(id) => *id,
101 None => {
102 let id = ItemId(u32::try_from($self.items.len()).expect("ran out of item ids"));
103 let item = $item.try_to_owned()?;
104 $self.items.try_push(ItemStorage {
105 hash,
106 item,
107 ids: Cell::new(0),
108 })?;
109 $self.hash_to_item.try_insert(hash, id)?;
110 id
111 }
112 }
113 }};
114}
115
116struct ItemStorage {
117 hash: Hash,
118 item: ItemBuf,
119 ids: Cell<usize>,
121}
122
123pub(crate) struct Pool {
125 modules: Vec<ModMeta>,
126 items: Vec<ItemStorage>,
127 item_to_mod: HashMap<ItemId, ModId>,
128 hash_to_item: HashMap<Hash, ItemId>,
129}
130
131impl Pool {
132 pub fn new() -> alloc::Result<Self> {
133 let root_hash: Hash = Hash::type_hash(Item::new());
134
135 Ok(Self {
136 modules: Vec::new(),
137 items: try_vec![ItemStorage {
138 hash: root_hash,
139 item: ItemBuf::new(),
140 ids: Cell::new(0),
141 }],
142 item_to_mod: HashMap::new(),
143 hash_to_item: HashMap::try_from_iter([(root_hash, ItemId(0))])?,
144 })
145 }
146
147 pub(crate) fn next_id(&self, id: ItemId) -> usize {
149 let storage = self.item_storage(id);
150 let id = storage.ids.get();
151 storage.ids.set(id + 1);
152 id
153 }
154
155 pub(crate) fn item(&self, id: ItemId) -> &Item {
157 &self.item_storage(id).item
158 }
159
160 pub(crate) fn item_type_hash(&self, id: ItemId) -> Hash {
162 self.item_storage(id).hash
163 }
164
165 pub(crate) fn module(&self, ModId(id): ModId) -> &ModMeta {
167 let id = usize::try_from(id).expect("module id overflow");
168
169 match self.modules.get(id) {
170 Some(item) => item,
171 None => panic!("missing module by id {id}"),
172 }
173 }
174
175 pub(crate) fn module_item(&self, id: ModId) -> &Item {
177 let id = self.module(id).item;
178 self.item(id)
179 }
180
181 pub(crate) fn module_item_hash(&self, id: ModId) -> Hash {
183 let id = self.module(id).item;
184 self.item_type_hash(id)
185 }
186
187 pub(crate) fn module_by_item(&self, id: ItemId) -> Option<&ModMeta> {
189 Some(self.module(*self.item_to_mod.get(&id)?))
190 }
191
192 pub(crate) fn alloc_module(&mut self, item: ModMeta) -> alloc::Result<ModId> {
194 if let Some(id) = self.item_to_mod.get(&item.item) {
195 return Ok(*id);
196 }
197
198 let id = ModId(u32::try_from(self.modules.len()).expect("ran out of item ids"));
199 self.item_to_mod.try_insert(item.item, id)?;
200 self.modules.try_push(item)?;
201 Ok(id)
202 }
203
204 pub(crate) fn alloc_item<T>(&mut self, item: T) -> alloc::Result<ItemId>
206 where
207 T: AsRef<Item>,
208 {
209 Ok(alloc_item!(self, item.as_ref()))
210 }
211
212 pub(crate) fn try_map_alloc<M>(&mut self, id: ItemId, m: M) -> alloc::Result<Option<ItemId>>
214 where
215 M: FnOnce(&Item) -> Option<&Item>,
216 {
217 let Some(item) = m(self.item(id)) else {
218 return Ok(None);
219 };
220
221 Ok(Some(alloc_item!(self, item)))
222 }
223
224 fn item_storage(&self, ItemId(id): ItemId) -> &ItemStorage {
225 let id = usize::try_from(id).expect("item id overflow");
226
227 match self.items.get(id) {
228 Some(item) => item,
229 None => panic!("missing item by id {id}"),
230 }
231 }
232}