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            ControlFunction::physical_sensing_trace(),
43        ] {
44            linker.function_value(function.symbol(), cx.factory().opaque(Arc::new(function))?)?;
45        }
46        linker.function_value(IfForm::symbol(), cx.factory().opaque(Arc::new(IfForm))?)?;
47        Ok(())
48    }
49}
50
51/// Installs the control organ into `cx`: loads [`ControlLib`] idempotently,
52/// installs the default control policy, and publishes the organ's claims.
53///
54/// This is the first-reach entry point for the crate; everything else hangs off
55/// the functions and policy it registers.
56///
57/// # Examples
58///
59/// ```
60/// use std::sync::Arc;
61///
62/// use sim_kernel::{Cx, DefaultFactory, NoopEvalPolicy};
63/// use sim_lib_control::install_control_lib;
64///
65/// let mut cx = Cx::new(Arc::new(NoopEvalPolicy), Arc::new(DefaultFactory));
66/// install_control_lib(&mut cx).expect("install control organ");
67/// // Idempotent: installing twice is a no-op on the second call.
68/// install_control_lib(&mut cx).expect("reinstall is idempotent");
69/// ```
70pub fn install_control_lib(cx: &mut Cx) -> Result<()> {
71    let lib_id = match sim_lib_core::install_once_id(cx, &ControlLib)? {
72        Some(lib_id) => lib_id,
73        None => sim_lib_core::installed_lib_id(cx, &ControlLib).expect("control lib is loaded"),
74    };
75    install_control_policy(cx);
76    publish_control_organ_claims_for_lib(cx, lib_id)
77}
78
79/// Returns the lib's exported `control/*` functions as kernel [`Export`]s.
80pub fn control_exports() -> Vec<Export> {
81    [
82        prompt_symbol(),
83        capture_symbol(),
84        abort_symbol(),
85        resume_symbol(),
86        IfForm::symbol(),
87        crate::physical_sensing_trace_symbol(),
88    ]
89    .into_iter()
90    .map(|symbol| Export::Function {
91        symbol,
92        function_id: None,
93    })
94    .collect()
95}
96
97/// Returns the `sim/control` manifest id under which this lib registers.
98pub fn manifest_name() -> Symbol {
99    Symbol::qualified("sim", CONTROL_LIB_ID)
100}