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