Skip to main content

sim_kernel/library/registry/
unload.rs

1use 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    /// Unloads a single library by stable id.
22    ///
23    /// This is a bare unload: if any loaded library depends on `lib_id`, the
24    /// call refuses with [`Error::LibHasDependents`]. Passing an absent id is a
25    /// no-op and returns an empty list. On success the returned list contains
26    /// the unloaded id.
27    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    /// Unloads a library and its dependents in reverse load order.
42    ///
43    /// Passing an absent id is a no-op and returns an empty list. The returned
44    /// ids are ordered by the actual unload sequence, with dependents before
45    /// their dependencies.
46    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}