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;
10use std::collections::BTreeMap;
11
12impl Cx {
13 pub fn activate_lib(&mut self, expected: Option<LibId>, lib: &dyn Lib) -> Result<LibId> {
20 let manifest = lib.manifest();
21 let current = self.registry.lib(&manifest.id).cloned();
22 match (expected, current.as_ref()) {
23 (None, None) => {}
24 (None, Some(_)) => {
25 return Err(Error::DuplicateLib {
26 symbol: manifest.id.clone(),
27 });
28 }
29 (Some(id), Some(loaded)) if loaded.id == id => {}
30 (Some(id), _) => {
31 return Err(Error::Lib(format!(
32 "activation expected library id {id:?} for {}",
33 manifest.id
34 )));
35 }
36 }
37
38 if expected.is_none() {
39 let mut staged = self.library_state();
40 let id = self.with_library_state(&mut staged, |cx| cx.load_lib(lib))?;
41 self.commit_library_state(staged);
42 return Ok(id);
43 }
44
45 let loaded = current.expect("validated loaded replacement");
46 let id = loaded.id;
47 let stable_exports = loaded
48 .exports
49 .iter()
50 .filter_map(|record| match record.state {
51 crate::library::ExportState::Resolved { id } => {
52 Some(((record.kind.clone(), record.symbol.clone()), id))
53 }
54 _ => None,
55 })
56 .collect::<BTreeMap<_, _>>();
57 let mut staged = self.library_state();
58 let result = self.with_library_state(&mut staged, |cx| {
59 for capability in &manifest.capabilities {
60 cx.require(capability)?;
61 }
62 for dependency in &manifest.requires {
63 if let Some(found) = cx.registry.manifest_by_symbol(&dependency.id)
64 && !dependency_satisfied(found, dependency)
65 {
66 return Err(Error::DependencyVersionMismatch {
67 lib: manifest.id.clone(),
68 dependency: dependency.id.clone(),
69 required: dependency
70 .minimum_version
71 .clone()
72 .unwrap_or_else(|| Version(String::from("0"))),
73 loaded: found.version.clone(),
74 });
75 }
76 }
77 let sequence_floor = cx.registry.catalog_sequence_snapshot();
78 cx.registry.unload(id)?;
79 cx.remove_load_claims(&[id]);
80 cx.registry.retain_sequence_floor(&sequence_floor)?;
81 let trusted = matches!(manifest.target, LibTarget::HostRegistered);
82 let mut txn = cx.registry.try_begin_load(manifest.clone(), trusted)?;
83 txn.lib_id = id;
84 txn.stable_exports = stable_exports;
85 {
86 let mut load_cx = cx.load_cx();
87 lib.load(&mut load_cx, &mut txn.linker())?;
88 }
89 let committed = cx.registry.commit_load(txn)?;
90 let loaded = cx
91 .registry
92 .libs()
93 .iter()
94 .find(|item| item.id == committed)
95 .cloned()
96 .ok_or_else(|| Error::Lib("activated library missing after commit".to_owned()))?;
97 let claims = publish_loaded_lib_claims(cx, &loaded)?;
98 cx.record_load_claims(committed, claims);
99 Ok(committed)
100 })?;
101 self.commit_library_state(staged);
102 Ok(result)
103 }
104
105 pub fn load_lib(&mut self, lib: &dyn Lib) -> Result<LibId> {
109 let manifest = lib.manifest();
110 for capability in &manifest.capabilities {
111 self.require(capability)?;
112 }
113 for dependency in &manifest.requires {
114 if let Some(loaded_manifest) = self.registry.manifest_by_symbol(&dependency.id)
115 && !dependency_satisfied(loaded_manifest, dependency)
116 {
117 return Err(Error::DependencyVersionMismatch {
118 lib: manifest.id.clone(),
119 dependency: dependency.id.clone(),
120 required: dependency
121 .minimum_version
122 .clone()
123 .unwrap_or_else(|| Version(String::from("0"))),
124 loaded: loaded_manifest.version.clone(),
125 });
126 }
127 }
128 let trusted = matches!(manifest.target, LibTarget::HostRegistered);
129 let mut txn = self.registry.try_begin_load(manifest, trusted)?;
130 {
131 let mut load_cx = self.load_cx();
132 let mut linker = txn.linker();
133 lib.load(&mut load_cx, &mut linker)?;
134 }
135 let lib_id = self.registry.commit_load(txn)?;
136 let loaded = self
137 .registry
138 .libs()
139 .iter()
140 .find(|loaded| loaded.id == lib_id)
141 .cloned();
142 if let Some(loaded) = loaded {
143 let claim_ids = publish_loaded_lib_claims(self, &loaded)?;
144 self.record_load_claims(lib_id, claim_ids);
145 }
146 Ok(lib_id)
147 }
148
149 pub fn load_libs(&mut self, libs: &[&dyn Lib]) -> Result<Vec<LibId>> {
152 let manifests = libs.iter().map(|lib| lib.manifest()).collect::<Vec<_>>();
153 let ordered = self.registry.dependency_order(&manifests)?;
154 let mut ids = Vec::with_capacity(ordered.len());
155
156 for manifest in ordered {
157 let lib = libs
158 .iter()
159 .find(|candidate| candidate.manifest().id == manifest.id)
160 .ok_or_else(|| {
161 Error::Lib(format!("missing lib implementation for {}", manifest.id))
162 })?;
163 ids.push(self.load_lib(*lib)?);
164 }
165
166 Ok(ids)
167 }
168
169 pub fn unload_lib(&mut self, lib_id: LibId) -> Result<Vec<LibId>> {
174 let unloaded = self.registry.unload(lib_id)?;
175 self.remove_load_claims(&unloaded);
176 Ok(unloaded)
177 }
178
179 pub fn unload_lib_cascade(&mut self, lib_id: LibId) -> Result<Vec<LibId>> {
182 let unloaded = self.registry.unload_cascade(lib_id)?;
183 self.remove_load_claims(&unloaded);
184 Ok(unloaded)
185 }
186}