sim_kernel/library/registry/
unload.rs1use std::collections::BTreeSet;
2
3use crate::{
4 Error, LibId, Result, RuntimeId, Symbol,
5 library::{ExportState, LoadedLib},
6};
7
8use super::{
9 DeltaRange, LoadDelta, Registry,
10 catalog::{
11 SEQ_CASE, SEQ_CLASS, SEQ_CODEC, SEQ_FUNCTION, SEQ_LIB, SEQ_MACRO, SEQ_NUMBER_DOMAIN,
12 SEQ_SHAPE, SEQ_SITE, export_key, export_record_key, exports_table, lib_key, libs_table,
13 number_binary_op_row, number_ops_table, number_reduction_op_row, number_unary_op_row,
14 plain_value_key, promotion_rule_row, promotion_rules_table, runtime_key, runtime_table,
15 test_key, tests_table, value_number_binary_op_row, value_number_reduction_op_row,
16 value_number_unary_op_row, value_promotion_rule_row, value_promotion_rules_table,
17 },
18};
19
20impl Registry {
21 pub fn unload(&mut self, lib_id: LibId) -> Result<Vec<LibId>> {
28 let Some(lib) = self.loaded_lib(lib_id) else {
29 return Ok(Vec::new());
30 };
31 let dependents = self.dependent_ids_for(lib_id);
32 if !dependents.is_empty() {
33 return Err(Error::LibHasDependents {
34 lib: lib.manifest.id.clone(),
35 dependents: self.symbols_for_lib_ids(&dependents),
36 });
37 }
38 Ok(self.unload_one(lib_id)?.into_iter().collect())
39 }
40
41 pub fn unload_cascade(&mut self, lib_id: LibId) -> Result<Vec<LibId>> {
47 if self.loaded_lib(lib_id).is_none() {
48 return Ok(Vec::new());
49 }
50 let mut selected = BTreeSet::new();
51 self.collect_dependents(lib_id, &mut selected);
52 selected.insert(lib_id);
53
54 let mut ordered = self
55 .libs
56 .iter()
57 .filter_map(|loaded| selected.contains(&loaded.id).then_some(loaded.id))
58 .collect::<Vec<_>>();
59 ordered.reverse();
60
61 let mut unloaded = Vec::with_capacity(ordered.len());
62 for id in ordered {
63 if let Some(id) = self.unload_one(id)? {
64 unloaded.push(id);
65 }
66 }
67 Ok(unloaded)
68 }
69
70 fn unload_one(&mut self, lib_id: LibId) -> Result<Option<LibId>> {
71 let Some(index) = self.libs.iter().position(|loaded| loaded.id == lib_id) else {
72 return Ok(None);
73 };
74 let loaded = self.libs.remove(index);
75 let delta = self.load_deltas.remove(&lib_id).unwrap_or_default();
76 self.load_dependencies.remove(&lib_id);
77 for dependencies in self.load_dependencies.values_mut() {
78 dependencies.remove(&lib_id);
79 }
80
81 self.delete_loaded_catalog_rows(&loaded);
82 self.delete_registered_tests_for_lib(&loaded.manifest.id);
83 self.remove_number_delta(delta);
84 self.rebuild_number_catalog_rows();
85 self.rebuild_projection_caches_from_catalog();
86 self.recompute_sequence_rows()?;
87 Ok(Some(lib_id))
88 }
89
90 fn loaded_lib(&self, lib_id: LibId) -> Option<&LoadedLib> {
91 self.libs.iter().find(|loaded| loaded.id == lib_id)
92 }
93
94 fn dependent_ids_for(&self, lib_id: LibId) -> Vec<LibId> {
95 self.load_dependencies
96 .iter()
97 .filter_map(|(dependent, dependencies)| {
98 dependencies.contains(&lib_id).then_some(*dependent)
99 })
100 .filter(|dependent| self.loaded_lib(*dependent).is_some())
101 .collect()
102 }
103
104 fn collect_dependents(&self, lib_id: LibId, selected: &mut BTreeSet<LibId>) {
105 for dependent in self.dependent_ids_for(lib_id) {
106 if selected.insert(dependent) {
107 self.collect_dependents(dependent, selected);
108 }
109 }
110 }
111
112 fn symbols_for_lib_ids(&self, ids: &[LibId]) -> Vec<Symbol> {
113 ids.iter()
114 .filter_map(|id| {
115 self.loaded_lib(*id)
116 .map(|loaded| loaded.manifest.id.clone())
117 })
118 .collect()
119 }
120
121 fn delete_loaded_catalog_rows(&mut self, loaded: &LoadedLib) {
122 self.catalog
123 .delete_row(&libs_table(), &lib_key(&loaded.manifest.id));
124 for record in &loaded.exports {
125 self.catalog.delete_row(
126 &exports_table(),
127 &export_catalog_key(&loaded.manifest.id, record),
128 );
129 if let ExportState::Resolved { id } = record.state {
130 self.catalog
131 .delete_row(&runtime_table(), &runtime_catalog_key(id, &record.symbol));
132 }
133 }
134 }
135
136 fn delete_registered_tests_for_lib(&mut self, lib: &Symbol) {
137 let test_kind = Symbol::new("test");
138 let symbols = self.tests_by_lib.get(lib).cloned().unwrap_or_default();
139 for symbol in symbols {
140 self.catalog.delete_row(&tests_table(), &test_key(&symbol));
141 self.catalog.delete_row(
142 &exports_table(),
143 &export_record_key(lib, &test_kind, &symbol),
144 );
145 }
146 }
147
148 fn remove_number_delta(&mut self, removed: LoadDelta) {
149 drain_range(&mut self.number_unary_ops, removed.number_unary_ops);
150 drain_range(&mut self.number_reduction_ops, removed.number_reduction_ops);
151 drain_range(&mut self.number_binary_ops, removed.number_binary_ops);
152 drain_range(
153 &mut self.value_number_unary_ops,
154 removed.value_number_unary_ops,
155 );
156 drain_range(
157 &mut self.value_number_reduction_ops,
158 removed.value_number_reduction_ops,
159 );
160 drain_range(
161 &mut self.value_number_binary_ops,
162 removed.value_number_binary_ops,
163 );
164 drain_range(&mut self.promotion_rules, removed.promotion_rules);
165 drain_range(
166 &mut self.value_promotion_rules,
167 removed.value_promotion_rules,
168 );
169
170 for delta in self.load_deltas.values_mut() {
171 delta
172 .number_unary_ops
173 .adjust_after_removed(removed.number_unary_ops);
174 delta
175 .number_reduction_ops
176 .adjust_after_removed(removed.number_reduction_ops);
177 delta
178 .number_binary_ops
179 .adjust_after_removed(removed.number_binary_ops);
180 delta
181 .value_number_unary_ops
182 .adjust_after_removed(removed.value_number_unary_ops);
183 delta
184 .value_number_reduction_ops
185 .adjust_after_removed(removed.value_number_reduction_ops);
186 delta
187 .value_number_binary_ops
188 .adjust_after_removed(removed.value_number_binary_ops);
189 delta
190 .promotion_rules
191 .adjust_after_removed(removed.promotion_rules);
192 delta
193 .value_promotion_rules
194 .adjust_after_removed(removed.value_promotion_rules);
195 }
196 }
197
198 fn rebuild_number_catalog_rows(&mut self) {
199 clear_table(self, &number_ops_table());
200 clear_table(self, &promotion_rules_table());
201 clear_table(self, &value_promotion_rules_table());
202
203 for (index, op) in self.number_unary_ops.iter().cloned().enumerate() {
204 self.catalog.put_row(number_unary_op_row(index as u64, op));
205 }
206 for (index, op) in self.number_reduction_ops.iter().cloned().enumerate() {
207 self.catalog
208 .put_row(number_reduction_op_row(index as u64, op));
209 }
210 for (index, op) in self.number_binary_ops.iter().cloned().enumerate() {
211 self.catalog.put_row(number_binary_op_row(index as u64, op));
212 }
213 for (index, op) in self.value_number_unary_ops.iter().cloned().enumerate() {
214 self.catalog
215 .put_row(value_number_unary_op_row(index as u64, op));
216 }
217 for (index, op) in self.value_number_reduction_ops.iter().cloned().enumerate() {
218 self.catalog
219 .put_row(value_number_reduction_op_row(index as u64, op));
220 }
221 for (index, op) in self.value_number_binary_ops.iter().cloned().enumerate() {
222 self.catalog
223 .put_row(value_number_binary_op_row(index as u64, op));
224 }
225 for (index, rule) in self.promotion_rules.iter().cloned().enumerate() {
226 self.catalog.put_row(promotion_rule_row(index as u64, rule));
227 }
228 for (index, rule) in self.value_promotion_rules.iter().cloned().enumerate() {
229 self.catalog
230 .put_row(value_promotion_rule_row(index as u64, rule));
231 }
232 }
233
234 fn recompute_sequence_rows(&mut self) -> Result<()> {
235 for kind in [
236 SEQ_LIB,
237 SEQ_CLASS,
238 SEQ_FUNCTION,
239 SEQ_MACRO,
240 SEQ_CASE,
241 SEQ_SHAPE,
242 SEQ_CODEC,
243 SEQ_NUMBER_DOMAIN,
244 SEQ_SITE,
245 ] {
246 self.set_catalog_sequence_next(kind, self.sequence_next_after_unload(kind))?;
247 }
248 Ok(())
249 }
250
251 fn sequence_next_after_unload(&self, kind: &'static str) -> u64 {
252 let symbol = Symbol::new(kind);
253 let mut next = self
254 .load_deltas
255 .values()
256 .filter_map(|delta| delta.sequence_after.get(&symbol).copied())
257 .max()
258 .unwrap_or(1);
259 next = next.max(match kind {
260 SEQ_LIB => max_id_next(self.libs.iter().map(|loaded| loaded.id.0)),
261 SEQ_CLASS => max_id_next(self.class_symbol_cache.values().map(|id| id.0)),
262 SEQ_FUNCTION => max_id_next(self.function_symbol_cache.values().map(|id| id.0)),
263 SEQ_MACRO => max_id_next(self.macro_symbol_cache.values().map(|id| id.0)),
264 SEQ_SHAPE => max_id_next(self.shape_symbol_cache.values().map(|id| id.0)),
265 SEQ_CODEC => max_id_next(self.codec_symbol_cache.values().map(|id| id.0)),
266 SEQ_NUMBER_DOMAIN => {
267 max_id_next(self.number_domain_symbol_cache.values().map(|id| id.0))
268 }
269 SEQ_SITE => max_id_next(self.site_symbol_cache.values().map(|id| id.0)),
270 SEQ_CASE => 1,
271 _ => 1,
272 });
273 next
274 }
275}
276
277fn export_catalog_key(lib: &Symbol, record: &crate::ExportRecord) -> Symbol {
278 match record.state {
279 ExportState::Resolved { .. } => export_key(record.kind.symbol(), &record.symbol),
280 _ => export_record_key(lib, record.kind.symbol(), &record.symbol),
281 }
282}
283
284fn runtime_catalog_key(runtime_id: RuntimeId, symbol: &Symbol) -> Symbol {
285 match runtime_id {
286 RuntimeId::Class(id) => runtime_key(&Symbol::new(SEQ_CLASS), u64::from(id.0)),
287 RuntimeId::Function(id) => runtime_key(&Symbol::new(SEQ_FUNCTION), u64::from(id.0)),
288 RuntimeId::Macro(id) => runtime_key(&Symbol::new(SEQ_MACRO), u64::from(id.0)),
289 RuntimeId::Shape(id) => runtime_key(&Symbol::new(SEQ_SHAPE), u64::from(id.0)),
290 RuntimeId::Codec(id) => runtime_key(&Symbol::new(SEQ_CODEC), u64::from(id.0)),
291 RuntimeId::NumberDomain(id) => {
292 runtime_key(&Symbol::new(SEQ_NUMBER_DOMAIN), u64::from(id.0))
293 }
294 RuntimeId::Site(id) => runtime_key(&Symbol::new(SEQ_SITE), u64::from(id.0)),
295 RuntimeId::Value => plain_value_key(symbol),
296 }
297}
298
299fn drain_range<T>(items: &mut Vec<T>, range: DeltaRange) {
300 if range.is_empty() {
301 return;
302 }
303 items.drain(range.start..range.end());
304}
305
306fn clear_table(registry: &mut Registry, table: &Symbol) {
307 let keys = registry
308 .catalog
309 .rows(table)
310 .map(|rows| rows.keys().cloned().collect::<Vec<_>>())
311 .unwrap_or_default();
312 for key in keys {
313 registry.catalog.delete_row(table, &key);
314 }
315}
316
317fn max_id_next(ids: impl Iterator<Item = u32>) -> u64 {
318 ids.map(u64::from)
319 .max()
320 .and_then(|id| id.checked_add(1))
321 .unwrap_or(1)
322}