Skip to main content

sim_kernel/library/
cx.rs

1use crate::{
2    LibId,
3    env::Cx,
4    error::{Error, Result},
5    library::{Lib, LibTarget, Version},
6};
7
8use super::claims::publish_loaded_lib_claims;
9use super::loaders::dependency_satisfied;
10
11impl Cx {
12    /// Loads a single library: checks its requested capabilities and dependency
13    /// versions, runs its [`Lib::load`](crate::library::Lib::load) against a
14    /// load transaction, commits the result, and publishes its load claims.
15    pub fn load_lib(&mut self, lib: &dyn Lib) -> Result<LibId> {
16        let manifest = lib.manifest();
17        for capability in &manifest.capabilities {
18            self.require(capability)?;
19        }
20        for dependency in &manifest.requires {
21            if let Some(loaded_manifest) = self.registry.manifest_by_symbol(&dependency.id)
22                && !dependency_satisfied(loaded_manifest, dependency)
23            {
24                return Err(Error::DependencyVersionMismatch {
25                    lib: manifest.id.clone(),
26                    dependency: dependency.id.clone(),
27                    required: dependency
28                        .minimum_version
29                        .clone()
30                        .unwrap_or_else(|| Version(String::from("0"))),
31                    loaded: loaded_manifest.version.clone(),
32                });
33            }
34        }
35        let trusted = matches!(manifest.target, LibTarget::HostRegistered);
36        let mut txn = self.registry.begin_load(manifest, trusted);
37        {
38            let mut load_cx = self.load_cx();
39            let mut linker = txn.linker();
40            lib.load(&mut load_cx, &mut linker)?;
41        }
42        let lib_id = self.registry.commit_load(txn)?;
43        let loaded = self
44            .registry
45            .libs()
46            .iter()
47            .find(|loaded| loaded.id == lib_id)
48            .cloned();
49        if let Some(loaded) = loaded {
50            let claim_ids = publish_loaded_lib_claims(self, &loaded)?;
51            self.record_load_claims(lib_id, claim_ids);
52        }
53        Ok(lib_id)
54    }
55
56    /// Loads several libraries in dependency order, returning their ids in load
57    /// order.
58    pub fn load_libs(&mut self, libs: &[&dyn Lib]) -> Result<Vec<LibId>> {
59        let manifests = libs.iter().map(|lib| lib.manifest()).collect::<Vec<_>>();
60        let ordered = self.registry.dependency_order(&manifests)?;
61        let mut ids = Vec::with_capacity(ordered.len());
62
63        for manifest in ordered {
64            let lib = libs
65                .iter()
66                .find(|candidate| candidate.manifest().id == manifest.id)
67                .ok_or_else(|| {
68                    Error::Lib(format!("missing lib implementation for {}", manifest.id))
69                })?;
70            ids.push(self.load_lib(*lib)?);
71        }
72
73        Ok(ids)
74    }
75
76    /// Unloads a loaded library by id and retracts the claims published for it.
77    ///
78    /// Already-live values may continue to exist, but fresh registry resolution
79    /// for the unloaded library's exports is removed.
80    pub fn unload_lib(&mut self, lib_id: LibId) -> Result<Vec<LibId>> {
81        let unloaded = self.registry.unload(lib_id)?;
82        self.remove_load_claims(&unloaded);
83        Ok(unloaded)
84    }
85
86    /// Unloads a library and every loaded dependent in reverse dependency
87    /// order, retracting the claims published for each unloaded lib.
88    pub fn unload_lib_cascade(&mut self, lib_id: LibId) -> Result<Vec<LibId>> {
89        let unloaded = self.registry.unload_cascade(lib_id)?;
90        self.remove_load_claims(&unloaded);
91        Ok(unloaded)
92    }
93}