sim_kernel/library/registry/
load.rs1use std::cmp::Ordering;
2use std::collections::{BTreeMap, BTreeSet};
3
4use crate::{
5 error::{Error, Result},
6 id::LibId,
7 library::{Export, ExportRecord, LibManifest, LoadTransaction, Version},
8};
9
10use super::Registry;
11use super::commit::commit_loaded_lib;
12use crate::library::loaders::compare_version_text;
13use crate::library::transaction::PendingExports;
14
15impl Registry {
16 pub fn dependency_order(&self, manifests: &[LibManifest]) -> Result<Vec<LibManifest>> {
25 let mut remaining = manifests.to_vec();
26 remaining.sort_by(|left, right| left.id.cmp(&right.id));
27 let mut loaded = self.libs_by_symbol.keys().cloned().collect::<BTreeSet<_>>();
28 let mut loaded_versions = self
29 .libs
30 .iter()
31 .map(|loaded| (loaded.manifest.id.clone(), loaded.manifest.version.clone()))
32 .collect::<BTreeMap<_, _>>();
33 let mut ordered = Vec::with_capacity(remaining.len());
34
35 while !remaining.is_empty() {
36 let mut progressed = false;
37 let mut index = 0;
38 while index < remaining.len() {
39 let ready = remaining[index].requires.iter().all(|dependency| {
40 if !loaded.contains(&dependency.id) {
41 return false;
42 }
43 match (
44 loaded_versions.get(&dependency.id),
45 dependency.minimum_version.as_ref(),
46 ) {
47 (Some(loaded_version), Some(required_version)) => {
48 compare_version_text(&loaded_version.0, &required_version.0)
49 != Ordering::Less
50 }
51 _ => true,
52 }
53 });
54 if ready {
55 let manifest = remaining.remove(index);
56 loaded.insert(manifest.id.clone());
57 loaded_versions.insert(manifest.id.clone(), manifest.version.clone());
58 ordered.push(manifest);
59 progressed = true;
60 } else {
61 index += 1;
62 }
63 }
64
65 if !progressed {
66 let blocked = &remaining[0];
67 if let Some(dependency) = blocked.requires.iter().find(|dependency| {
68 loaded_versions
69 .get(&dependency.id)
70 .zip(dependency.minimum_version.as_ref())
71 .is_some_and(|(loaded_version, minimum)| {
72 compare_version_text(&loaded_version.0, &minimum.0) == Ordering::Less
73 })
74 }) {
75 return Err(Error::DependencyVersionMismatch {
76 lib: blocked.id.clone(),
77 dependency: dependency.id.clone(),
78 required: dependency
79 .minimum_version
80 .clone()
81 .unwrap_or_else(|| Version(String::from("0"))),
82 loaded: loaded_versions
83 .get(&dependency.id)
84 .cloned()
85 .unwrap_or_else(|| Version(String::from("0"))),
86 });
87 }
88 let missing = blocked
89 .requires
90 .iter()
91 .find(|dependency| !loaded.contains(&dependency.id))
92 .map(|dependency| dependency.id.clone())
93 .unwrap_or_else(|| blocked.id.clone());
94 return Err(if missing == blocked.id {
95 Error::CyclicDependency {
96 symbol: blocked.id.clone(),
97 }
98 } else {
99 Error::MissingDependency {
100 lib: blocked.id.clone(),
101 dependency: missing,
102 }
103 });
104 }
105 }
106
107 Ok(ordered)
108 }
109
110 pub fn begin_load(&self, manifest: LibManifest, trusted: bool) -> LoadTransaction {
150 let mut registry = self.clone();
151 let lib_id = registry.fresh_lib_id();
152 LoadTransaction {
153 lib_id,
154 manifest,
155 trusted,
156 registry,
157 pending: PendingExports::default(),
158 }
159 }
160
161 pub fn commit_load(&mut self, txn: LoadTransaction) -> Result<LibId> {
164 let lib_id = txn.lib_id;
165 let mut registry = txn.registry;
166 let sequence_before = self.catalog_sequence_snapshot();
167 commit_loaded_lib(
168 txn.lib_id,
169 &mut registry,
170 txn.manifest,
171 txn.trusted,
172 txn.pending,
173 sequence_before,
174 )?;
175 *self = registry;
176 Ok(lib_id)
177 }
178
179 pub(crate) fn ensure_export_available(&self, export: &Export) -> Result<()> {
180 let duplicate = self
181 .export_symbols
182 .get(&export.kind_symbol())
183 .is_some_and(|entries| entries.contains_key(export.symbol()));
184 if duplicate {
185 Err(Error::DuplicateExport {
186 kind: export.kind(),
187 symbol: export.symbol().clone(),
188 })
189 } else {
190 Ok(())
191 }
192 }
193
194 pub(crate) fn validate_export_record_against_manifest(
195 manifest: &LibManifest,
196 record: &ExportRecord,
197 ) -> Result<()> {
198 let declared = manifest
199 .exports
200 .iter()
201 .any(|export| export.kind_symbol() == record.kind && export.symbol() == &record.symbol);
202 if declared {
203 Ok(())
204 } else {
205 Err(Error::UndeclaredExportRecord {
206 kind: record.kind.clone(),
207 symbol: record.symbol.clone(),
208 })
209 }
210 }
211}