Skip to main content

sim_kernel/library/registry/
query.rs

1use std::collections::BTreeSet;
2use std::sync::Arc;
3
4use crate::{
5    catalog::CatalogSnapshot,
6    id::{
7        ClassId, CodecId, FunctionId, MacroId, NumberDomainId, RuntimeId, ShapeId, SiteId, Symbol,
8    },
9    value::Value,
10};
11
12use super::Registry;
13use crate::library::{
14    ExportKind, LibBootDependency, LibBootReceipt, LibManifest, LibSourceSpec, LoadedLib,
15    RegisteredTest, Test,
16};
17
18impl Registry {
19    /// Returns a snapshot of the registry's identity catalog.
20    pub fn catalog_snapshot(&self) -> CatalogSnapshot {
21        CatalogSnapshot::from_store(&self.catalog)
22    }
23
24    /// All loaded libraries, in load order.
25    pub fn libs(&self) -> &[LoadedLib] {
26        &self.libs
27    }
28
29    /// Builds the data-only boot receipt for a loaded library id.
30    pub fn boot_receipt(
31        &self,
32        lib_id: crate::LibId,
33        requested_source: LibSourceSpec,
34        resolved_source: LibSourceSpec,
35    ) -> Option<LibBootReceipt> {
36        let loaded = self.libs.iter().find(|loaded| loaded.id == lib_id)?;
37        let dependencies = self
38            .load_dependencies
39            .get(&lib_id)
40            .into_iter()
41            .flat_map(|dependencies| dependencies.iter())
42            .filter_map(|dependency| {
43                let symbol = self
44                    .libs
45                    .iter()
46                    .find(|loaded| loaded.id == *dependency)?
47                    .manifest
48                    .id
49                    .clone();
50                Some(LibBootDependency {
51                    lib_id: *dependency,
52                    symbol,
53                })
54            })
55            .collect();
56        Some(LibBootReceipt {
57            lib_id,
58            requested_source,
59            resolved_source,
60            manifest: loaded.manifest.clone(),
61            dependencies,
62            exports: loaded.exports.clone(),
63        })
64    }
65
66    /// Returns a registry restricted to the named libraries and their exports.
67    pub fn subset_for_libs(&self, libs: &[Symbol]) -> Self {
68        if libs.is_empty() {
69            return Self::default();
70        }
71
72        let allowed = libs.iter().cloned().collect::<BTreeSet<_>>();
73        let mut registry = self.clone();
74        registry
75            .libs
76            .retain(|loaded| allowed.contains(&loaded.manifest.id));
77        registry
78            .libs_by_symbol
79            .retain(|symbol, _| allowed.contains(symbol));
80        let allowed_ids = registry
81            .libs
82            .iter()
83            .map(|loaded| loaded.id)
84            .collect::<BTreeSet<_>>();
85        registry
86            .load_deltas
87            .retain(|lib_id, _| allowed_ids.contains(lib_id));
88        registry.load_dependencies.retain(|lib_id, dependencies| {
89            if !allowed_ids.contains(lib_id) {
90                return false;
91            }
92            dependencies.retain(|dependency| allowed_ids.contains(dependency));
93            true
94        });
95
96        let exported_symbols = registry
97            .libs
98            .iter()
99            .flat_map(|loaded| loaded.exports.iter())
100            .map(|record| (record.kind.clone(), record.symbol.clone()))
101            .collect::<BTreeSet<_>>();
102
103        registry.export_symbols.retain(|kind, symbols| {
104            symbols.retain(|symbol, _| exported_symbols.contains(&(kind.clone(), symbol.clone())));
105            !symbols.is_empty()
106        });
107
108        registry.class_symbol_cache.retain(|symbol, _| {
109            exported_symbols.contains(&(ExportKind::named(ExportKind::CLASS), symbol.clone()))
110        });
111        registry.function_symbol_cache.retain(|symbol, _| {
112            exported_symbols.contains(&(ExportKind::named(ExportKind::FUNCTION), symbol.clone()))
113        });
114        registry.macro_symbol_cache.retain(|symbol, _| {
115            exported_symbols.contains(&(ExportKind::named(ExportKind::MACRO), symbol.clone()))
116        });
117        registry.shape_symbol_cache.retain(|symbol, _| {
118            exported_symbols.contains(&(ExportKind::named(ExportKind::SHAPE), symbol.clone()))
119        });
120        registry.codec_symbol_cache.retain(|symbol, _| {
121            exported_symbols.contains(&(ExportKind::named(ExportKind::CODEC), symbol.clone()))
122        });
123        registry.number_domain_symbol_cache.retain(|symbol, _| {
124            exported_symbols
125                .contains(&(ExportKind::named(ExportKind::NUMBER_DOMAIN), symbol.clone()))
126        });
127        registry.site_symbol_cache.retain(|symbol, _| {
128            exported_symbols.contains(&(ExportKind::named(ExportKind::SITE), symbol.clone()))
129        });
130        registry.plain_value_cache.retain(|symbol, _| {
131            exported_symbols.contains(&(ExportKind::named(ExportKind::VALUE), symbol.clone()))
132        });
133
134        registry.class_value_cache.retain(|id, _| {
135            registry
136                .class_symbol_cache
137                .values()
138                .any(|value| value == id)
139        });
140        registry.function_value_cache.retain(|id, _| {
141            registry
142                .function_symbol_cache
143                .values()
144                .any(|value| value == id)
145        });
146        registry.macro_value_cache.retain(|id, _| {
147            registry
148                .macro_symbol_cache
149                .values()
150                .any(|value| value == id)
151        });
152        registry.shape_value_cache.retain(|id, _| {
153            registry
154                .shape_symbol_cache
155                .values()
156                .any(|value| value == id)
157        });
158        registry.codec_value_cache.retain(|id, _| {
159            registry
160                .codec_symbol_cache
161                .values()
162                .any(|value| value == id)
163        });
164        registry.number_domain_value_cache.retain(|id, _| {
165            registry
166                .number_domain_symbol_cache
167                .values()
168                .any(|value| value == id)
169        });
170        registry
171            .site_value_cache
172            .retain(|id, _| registry.site_symbol_cache.values().any(|value| value == id));
173        registry.tests.retain(|_, test| allowed.contains(&test.lib));
174        registry
175            .tests_by_lib
176            .retain(|symbol, _| allowed.contains(symbol));
177        registry.retain_catalog_rows_for_subset();
178        registry.rebuild_projection_caches_from_catalog();
179        registry
180    }
181
182    /// Looks up a loaded library by symbol.
183    pub fn lib(&self, symbol: &Symbol) -> Option<&LoadedLib> {
184        let id = self.libs_by_symbol.get(symbol)?;
185        self.libs.iter().find(|loaded| loaded.id == *id)
186    }
187
188    pub(crate) fn lib_mut(&mut self, symbol: &Symbol) -> Option<&mut LoadedLib> {
189        let id = *self.libs_by_symbol.get(symbol)?;
190        self.libs.iter_mut().find(|loaded| loaded.id == id)
191    }
192
193    /// The full export index, keyed by kind then symbol.
194    pub fn export_symbols(
195        &self,
196    ) -> &std::collections::BTreeMap<ExportKind, std::collections::BTreeMap<Symbol, crate::RuntimeId>>
197    {
198        &self.export_symbols
199    }
200
201    /// The class symbol-to-id index.
202    pub fn classes(&self) -> &std::collections::BTreeMap<Symbol, ClassId> {
203        &self.class_symbol_cache
204    }
205
206    /// The function symbol-to-id index.
207    pub fn functions(&self) -> &std::collections::BTreeMap<Symbol, FunctionId> {
208        &self.function_symbol_cache
209    }
210
211    /// The macro symbol-to-id index.
212    pub fn macros(&self) -> &std::collections::BTreeMap<Symbol, MacroId> {
213        &self.macro_symbol_cache
214    }
215
216    /// The shape symbol-to-id index.
217    pub fn shapes(&self) -> &std::collections::BTreeMap<Symbol, ShapeId> {
218        &self.shape_symbol_cache
219    }
220
221    /// The codec symbol-to-id index.
222    pub fn codecs(&self) -> &std::collections::BTreeMap<Symbol, CodecId> {
223        &self.codec_symbol_cache
224    }
225
226    /// The number-domain symbol-to-id index.
227    pub fn number_domains(&self) -> &std::collections::BTreeMap<Symbol, NumberDomainId> {
228        &self.number_domain_symbol_cache
229    }
230
231    /// The site symbol-to-id index.
232    pub fn sites(&self) -> &std::collections::BTreeMap<Symbol, SiteId> {
233        &self.site_symbol_cache
234    }
235
236    /// All registered tests, keyed by symbol.
237    pub fn tests(&self) -> &std::collections::BTreeMap<Symbol, RegisteredTest> {
238        &self.tests
239    }
240
241    /// The symbols of tests owned by the given library, if any.
242    pub fn tests_for_lib(&self, symbol: &Symbol) -> Option<&[Symbol]> {
243        self.tests_by_lib.get(symbol).map(Vec::as_slice)
244    }
245
246    /// Resolves a class value by stable id.
247    pub fn class_value(&self, id: ClassId) -> Option<&Value> {
248        self.catalog_value_by_runtime_id(RuntimeId::Class(id))
249    }
250
251    /// Resolves a function value by stable id.
252    pub fn function_value(&self, id: FunctionId) -> Option<&Value> {
253        self.catalog_value_by_runtime_id(RuntimeId::Function(id))
254    }
255
256    /// Resolves a macro value by stable id.
257    pub fn macro_value(&self, id: MacroId) -> Option<&Value> {
258        self.catalog_value_by_runtime_id(RuntimeId::Macro(id))
259    }
260
261    /// Resolves a shape value by stable id.
262    pub fn shape_value(&self, id: ShapeId) -> Option<&Value> {
263        self.catalog_value_by_runtime_id(RuntimeId::Shape(id))
264    }
265
266    /// Resolves a codec value by stable id.
267    pub fn codec_value(&self, id: CodecId) -> Option<&Value> {
268        self.catalog_value_by_runtime_id(RuntimeId::Codec(id))
269    }
270
271    /// Resolves a number-domain value by stable id.
272    pub fn number_domain_value(&self, id: NumberDomainId) -> Option<&Value> {
273        self.catalog_value_by_runtime_id(RuntimeId::NumberDomain(id))
274    }
275
276    /// Resolves an opaque site value by runtime id.
277    pub fn site_value(&self, id: RuntimeId) -> Option<&Value> {
278        match id {
279            RuntimeId::Site(_) => self.catalog_value_by_runtime_id(id),
280            _ => None,
281        }
282    }
283
284    /// Resolves a class value by symbol.
285    pub fn class_by_symbol(&self, symbol: &Symbol) -> Option<&Value> {
286        self.catalog_value_by_export(&ExportKind::named(ExportKind::CLASS), symbol)
287    }
288
289    /// Resolves a function value by symbol.
290    pub fn function_by_symbol(&self, symbol: &Symbol) -> Option<&Value> {
291        self.catalog_value_by_export(&ExportKind::named(ExportKind::FUNCTION), symbol)
292    }
293
294    /// Resolves a macro value by symbol.
295    pub fn macro_by_symbol(&self, symbol: &Symbol) -> Option<&Value> {
296        self.catalog_value_by_export(&ExportKind::named(ExportKind::MACRO), symbol)
297    }
298
299    /// Resolves a shape value by symbol.
300    pub fn shape_by_symbol(&self, symbol: &Symbol) -> Option<&Value> {
301        self.catalog_value_by_export(&ExportKind::named(ExportKind::SHAPE), symbol)
302    }
303
304    /// Resolves a codec value by symbol.
305    pub fn codec_by_symbol(&self, symbol: &Symbol) -> Option<&Value> {
306        self.catalog_value_by_export(&ExportKind::named(ExportKind::CODEC), symbol)
307    }
308
309    /// Resolves a number-domain value by symbol.
310    pub fn number_domain_by_symbol(&self, symbol: &Symbol) -> Option<&Value> {
311        self.catalog_value_by_export(&ExportKind::named(ExportKind::NUMBER_DOMAIN), symbol)
312    }
313
314    /// Resolves an opaque site value by symbol.
315    pub fn site_by_symbol(&self, symbol: &Symbol) -> Option<&Value> {
316        self.catalog_value_by_export(&ExportKind::named(ExportKind::SITE), symbol)
317    }
318
319    /// Returns the manifest of a loaded library by symbol.
320    pub fn manifest_by_symbol(&self, symbol: &Symbol) -> Option<&LibManifest> {
321        self.lib(symbol).map(|loaded| &loaded.manifest)
322    }
323
324    /// Returns the test implementation registered under `symbol`.
325    pub fn test_by_symbol(&self, symbol: &Symbol) -> Option<&Arc<dyn Test>> {
326        self.tests.get(symbol).map(|test| &test.test)
327    }
328
329    /// Returns the full [`RegisteredTest`] record for `symbol`.
330    pub fn registered_test(&self, symbol: &Symbol) -> Option<&RegisteredTest> {
331        self.tests.get(symbol)
332    }
333
334    /// Resolves a plain value export by symbol.
335    pub fn value_by_symbol(&self, symbol: &Symbol) -> Option<&Value> {
336        self.catalog_value_by_export(&ExportKind::named(ExportKind::VALUE), symbol)
337    }
338
339    /// Returns the export symbol a registered value is bound under, searching
340    /// every export kind, if any.
341    pub fn export_symbol_for_value(&self, value: &Value) -> Option<Symbol> {
342        self.class_symbol_cache
343            .iter()
344            .find_map(|(symbol, id)| {
345                self.class_value_cache
346                    .get(id)
347                    .filter(|candidate| *candidate == value)
348                    .map(|_| symbol.clone())
349            })
350            .or_else(|| {
351                self.function_symbol_cache.iter().find_map(|(symbol, id)| {
352                    self.function_value_cache
353                        .get(id)
354                        .filter(|candidate| *candidate == value)
355                        .map(|_| symbol.clone())
356                })
357            })
358            .or_else(|| {
359                self.macro_symbol_cache.iter().find_map(|(symbol, id)| {
360                    self.macro_value_cache
361                        .get(id)
362                        .filter(|candidate| *candidate == value)
363                        .map(|_| symbol.clone())
364                })
365            })
366            .or_else(|| {
367                self.shape_symbol_cache.iter().find_map(|(symbol, id)| {
368                    self.shape_value_cache
369                        .get(id)
370                        .filter(|candidate| *candidate == value)
371                        .map(|_| symbol.clone())
372                })
373            })
374            .or_else(|| {
375                self.codec_symbol_cache.iter().find_map(|(symbol, id)| {
376                    self.codec_value_cache
377                        .get(id)
378                        .filter(|candidate| *candidate == value)
379                        .map(|_| symbol.clone())
380                })
381            })
382            .or_else(|| {
383                self.number_domain_symbol_cache
384                    .iter()
385                    .find_map(|(symbol, id)| {
386                        self.number_domain_value_cache
387                            .get(id)
388                            .filter(|candidate| *candidate == value)
389                            .map(|_| symbol.clone())
390                    })
391            })
392            .or_else(|| {
393                self.plain_value_cache
394                    .iter()
395                    .find_map(|(symbol, candidate)| (candidate == value).then(|| symbol.clone()))
396            })
397    }
398}