Skip to main content

sim_kernel/library/registry/
query.rs

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