Skip to main content

sim_platform_ubuntu_pc/
loader.rs

1//! Ubuntu realization of the run-owned loader domain port.
2
3use sim_kernel::{Cx, Error, LibLoader, Result, Symbol};
4use sim_run_loaders::{
5    BinaryPackLoader, LispSourceLoader, LoadOutcome, LoadRequest, LoaderKind, LoaderPort,
6    NativeDylibLoader, StaticRegistry, WasmLoader,
7};
8use std::sync::Arc;
9
10const NATIVE: &str = "native-v1";
11const WASM: &str = "wasm-v1";
12const SOURCE: &str = "source-v1";
13const STATIC: &str = "static-v1";
14fn kind(name: &str) -> LoaderKind {
15    LoaderKind::new(Symbol::qualified("loader", name))
16}
17
18/// Full loader service installed by an Ubuntu capsule after bootstrap.
19pub struct UbuntuLoaderPort {
20    native: NativeDylibLoader,
21    wasm: WasmLoader,
22    source: LispSourceLoader,
23    binary: BinaryPackLoader,
24    static_registry: StaticRegistry,
25}
26
27impl Default for UbuntuLoaderPort {
28    fn default() -> Self {
29        Self {
30            native: NativeDylibLoader,
31            wasm: WasmLoader::new(Arc::new(sim_wasm_abi::WasmiRuntime::new())),
32            source: LispSourceLoader::default(),
33            binary: BinaryPackLoader,
34            static_registry: StaticRegistry::default(),
35        }
36    }
37}
38
39impl UbuntuLoaderPort {
40    /// Registers an exact AOT artifact factory as capsule data.
41    pub fn register_static(
42        &self,
43        artifact: Symbol,
44        factory: impl Fn() -> Box<dyn sim_kernel::Lib> + Send + Sync + 'static,
45    ) {
46        self.static_registry.register(artifact, factory);
47    }
48    fn mechanism(&self, request: &LoadRequest) -> Result<&dyn LibLoader> {
49        if request.kind == kind(NATIVE) {
50            Ok(&self.native)
51        } else if request.kind == kind(WASM) {
52            Ok(&self.wasm)
53        } else if request.kind == kind(SOURCE) && self.source.can_load(&request.source) {
54            Ok(&self.source)
55        } else if request.kind == kind(SOURCE) && self.binary.can_load(&request.source) {
56            Ok(&self.binary)
57        } else {
58            Err(Error::HostError(format!(
59                "Ubuntu capsule rejected loader kind {} or its exact source",
60                request.kind.symbol()
61            )))
62        }
63    }
64}
65
66impl LoaderPort for UbuntuLoaderPort {
67    fn loader_kinds(&self) -> Vec<LoaderKind> {
68        [NATIVE, WASM, SOURCE, STATIC]
69            .into_iter()
70            .map(kind)
71            .collect()
72    }
73    fn realize(&self, cx: &mut Cx, request: LoadRequest) -> Result<LoadOutcome> {
74        if request.kind == kind(STATIC) {
75            let artifact = sim_run_loaders::static_artifact(&request.source)?.ok_or_else(|| {
76                Error::HostError("Ubuntu static loader rejected the exact source".into())
77            })?;
78            return self.static_registry.realize(&artifact);
79        }
80        let mechanism = self.mechanism(&request)?;
81        if !mechanism.can_load(&request.source) {
82            return Err(Error::HostError(format!(
83                "loader kind {} rejected the exact source",
84                request.kind.symbol()
85            )));
86        }
87        let library = mechanism.load(cx, request.source)?;
88        let manifest = library.manifest();
89        Ok(LoadOutcome { manifest, library })
90    }
91    fn inspect(
92        &self,
93        cx: &mut Cx,
94        request: &LoadRequest,
95    ) -> Result<Option<sim_kernel::LibManifest>> {
96        if request.kind == kind(STATIC) {
97            let artifact = sim_run_loaders::static_artifact(&request.source)?.ok_or_else(|| {
98                Error::HostError("Ubuntu static loader rejected the exact source".into())
99            })?;
100            return self
101                .static_registry
102                .realize(&artifact)
103                .map(|outcome| Some(outcome.manifest));
104        }
105        self.mechanism(request)?
106            .inspect_manifest(cx, &request.source)
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113    use sim_kernel::testing::bare_cx as cx;
114    use sim_kernel::{AbiVersion, Lib, LibManifest, LibSource, LibTarget, Linker, LoadCx, Version};
115    struct TestLib;
116    impl Lib for TestLib {
117        fn manifest(&self) -> LibManifest {
118            LibManifest {
119                id: Symbol::qualified("test", "ubuntu-static"),
120                version: Version("1.0.0".into()),
121                abi: AbiVersion { major: 0, minor: 1 },
122                target: LibTarget::HostRegistered,
123                requires: vec![],
124                capabilities: vec![],
125                exports: vec![],
126            }
127        }
128        fn load(&self, _: &mut LoadCx, _: &mut Linker<'_>) -> Result<()> {
129            Ok(())
130        }
131    }
132    #[test]
133    fn advertises_exact_kinds_and_fails_closed() {
134        let port = UbuntuLoaderPort::default();
135        assert_eq!(
136            port.loader_kinds(),
137            [NATIVE, WASM, SOURCE, STATIC]
138                .into_iter()
139                .map(kind)
140                .collect::<Vec<_>>()
141        );
142        let mut cx = cx();
143        assert!(
144            port.realize(
145                &mut cx,
146                LoadRequest {
147                    kind: kind("invented-v1"),
148                    source: sim_run_loaders::static_source(Symbol::qualified("artifact", "x"))
149                }
150            )
151            .is_err()
152        );
153        assert!(
154            port.realize(
155                &mut cx,
156                LoadRequest {
157                    kind: kind(STATIC),
158                    source: LibSource::open(
159                        Symbol::qualified("loader", "static-artifact"),
160                        sim_kernel::Datum::Bytes(vec![])
161                    )
162                }
163            )
164            .is_err()
165        );
166    }
167    #[test]
168    fn static_libraries_keep_ordinary_manifest_behavior() {
169        let port = UbuntuLoaderPort::default();
170        let artifact = Symbol::qualified("artifact", "ubuntu-static");
171        port.register_static(artifact.clone(), || Box::new(TestLib));
172        let mut cx = cx();
173        let outcome = port
174            .realize(
175                &mut cx,
176                LoadRequest {
177                    kind: kind(STATIC),
178                    source: sim_run_loaders::static_source(artifact),
179                },
180            )
181            .unwrap();
182        assert_eq!(outcome.manifest, outcome.library.manifest());
183    }
184}