Skip to main content

sim_lib_control/
runtime.rs

1use std::sync::Arc;
2
3use sim_kernel::{
4    AbiVersion, Cx, Export, Lib, LibManifest, LibTarget, Linker, Result, Symbol, Version,
5};
6
7use crate::{
8    claims::publish_control_organ_claims_for_lib,
9    ops::{ControlFunction, abort_symbol, capture_symbol, prompt_symbol, resume_symbol},
10    policy::install_control_policy,
11};
12
13const CONTROL_LIB_ID: &str = "control";
14
15/// The control organ as a loadable kernel [`Lib`].
16///
17/// Its manifest exports the `control/*` functions ([`control_exports`]) and its
18/// `load` installs them as callables, registering this crate's control behavior
19/// against the kernel's [`Lib`]/[`Linker`] contract.
20pub struct ControlLib;
21
22impl Lib for ControlLib {
23    fn manifest(&self) -> LibManifest {
24        LibManifest {
25            id: manifest_name(),
26            version: Version(env!("CARGO_PKG_VERSION").to_owned()),
27            abi: AbiVersion { major: 0, minor: 1 },
28            target: LibTarget::HostRegistered,
29            requires: Vec::new(),
30            capabilities: Vec::new(),
31            exports: control_exports(),
32        }
33    }
34
35    fn load(&self, cx: &mut sim_kernel::LoadCx, linker: &mut Linker<'_>) -> Result<()> {
36        for function in [
37            ControlFunction::prompt(),
38            ControlFunction::capture(),
39            ControlFunction::abort(),
40            ControlFunction::resume(),
41        ] {
42            linker.function_value(function.symbol(), cx.factory().opaque(Arc::new(function))?)?;
43        }
44        Ok(())
45    }
46}
47
48/// Installs the control organ into `cx`: loads [`ControlLib`] idempotently,
49/// installs the default control policy, and publishes the organ's claims.
50///
51/// This is the first-reach entry point for the crate; everything else hangs off
52/// the functions and policy it registers.
53///
54/// # Examples
55///
56/// ```
57/// use std::sync::Arc;
58///
59/// use sim_kernel::{Cx, DefaultFactory, NoopEvalPolicy};
60/// use sim_lib_control::install_control_lib;
61///
62/// let mut cx = Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
63/// install_control_lib(&mut cx).expect("install control organ");
64/// // Idempotent: installing twice is a no-op on the second call.
65/// install_control_lib(&mut cx).expect("reinstall is idempotent");
66/// ```
67pub fn install_control_lib(cx: &mut Cx) -> Result<()> {
68    let lib_id = match sim_lib_core::install_once_id(cx, &ControlLib)? {
69        Some(lib_id) => lib_id,
70        None => sim_lib_core::installed_lib_id(cx, &ControlLib).expect("control lib is loaded"),
71    };
72    install_control_policy(cx);
73    publish_control_organ_claims_for_lib(cx, lib_id)
74}
75
76/// Returns the lib's exported `control/*` functions as kernel [`Export`]s.
77pub fn control_exports() -> Vec<Export> {
78    [
79        prompt_symbol(),
80        capture_symbol(),
81        abort_symbol(),
82        resume_symbol(),
83    ]
84    .into_iter()
85    .map(|symbol| Export::Function {
86        symbol,
87        function_id: None,
88    })
89    .collect()
90}
91
92/// Returns the `sim/control` manifest id under which this lib registers.
93pub fn manifest_name() -> Symbol {
94    Symbol::qualified("sim", CONTROL_LIB_ID)
95}