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