Skip to main content

sim_lib_auto_core/
runtime.rs

1//! Loadable library wiring for the automotive core exports.
2
3use sim_citizen::CitizenInfo;
4use sim_kernel::{
5    AbiVersion, Cx, Export, Lib, LibManifest, LibTarget, Linker, LoadCx, Result, Symbol, Version,
6};
7
8use crate::auto_capability_texts;
9
10const AUTO_CITIZENS: &[&str] = &[
11    "auto/VehicleId",
12    "auto/Dtc",
13    "auto/DtcStatus",
14    "auto/BrandCaps",
15    "auto/AutoLane",
16    "auto/EffectClass",
17    "auto/OpCap",
18    "auto/TransportSpec",
19    "auto/SiteManifest",
20];
21
22const AUTO_LANES: &[&str] = &[
23    "diagnostics",
24    "telemetry",
25    "manifest",
26    "read",
27    "info",
28    "parts",
29    "service",
30    "control",
31    "flash",
32];
33
34/// Loadable library that contributes SIM automotive core citizens and values.
35#[derive(Clone, Copy, Debug, Default)]
36pub struct AutoCoreLib;
37
38impl Lib for AutoCoreLib {
39    fn manifest(&self) -> LibManifest {
40        let mut exports = auto_citizen_symbols()
41            .into_iter()
42            .map(|symbol| Export::Class {
43                symbol,
44                class_id: None,
45            })
46            .collect::<Vec<_>>();
47        exports.extend([
48            Export::Value {
49                symbol: auto_caps_symbol(),
50            },
51            Export::Value {
52                symbol: auto_lanes_symbol(),
53            },
54            Export::Value {
55                symbol: manifest_shape_symbol(),
56            },
57        ]);
58        LibManifest {
59            id: Symbol::qualified("auto", "core"),
60            version: Version(env!("CARGO_PKG_VERSION").to_owned()),
61            abi: AbiVersion { major: 0, minor: 1 },
62            target: LibTarget::HostRegistered,
63            requires: Vec::new(),
64            capabilities: Vec::new(),
65            exports,
66        }
67    }
68
69    fn load(&self, cx: &mut LoadCx, linker: &mut Linker<'_>) -> Result<()> {
70        sim_citizen::install_namespace(linker, "auto")?;
71        linker.value(
72            auto_caps_symbol(),
73            string_list(cx, auto_capability_texts())?,
74        )?;
75        linker.value(auto_lanes_symbol(), string_list(cx, AUTO_LANES)?)?;
76        linker.value(
77            manifest_shape_symbol(),
78            cx.factory().string(
79                "auto/SiteManifest v0 site vehicle brand makes lanes transports operations op-caps ceiling"
80                    .to_owned(),
81            )?,
82        )?;
83        Ok(())
84    }
85}
86
87/// Installs the automotive core library into a context once.
88pub fn install_auto_core_lib(cx: &mut Cx) -> Result<()> {
89    if cx
90        .registry()
91        .lib(&Symbol::qualified("auto", "core"))
92        .is_some()
93    {
94        return Ok(());
95    }
96    cx.load_lib(&AutoCoreLib).map(|_| ())
97}
98
99/// Returns the inventory rows for automotive core citizens.
100pub fn auto_citizen_registry() -> Vec<&'static CitizenInfo> {
101    sim_citizen::registered_citizens()
102        .filter(|info| AUTO_CITIZENS.contains(&info.symbol))
103        .collect()
104}
105
106/// Returns the automotive citizen symbols exported by the core library.
107pub fn auto_citizen_symbols() -> Vec<Symbol> {
108    AUTO_CITIZENS
109        .iter()
110        .map(|symbol| parse_symbol(symbol))
111        .collect()
112}
113
114/// Symbol for the exported automotive capability list.
115pub fn auto_caps_symbol() -> Symbol {
116    Symbol::qualified("auto", "caps")
117}
118
119/// Symbol for the exported automotive lane list.
120pub fn auto_lanes_symbol() -> Symbol {
121    Symbol::qualified("auto", "lanes")
122}
123
124/// Symbol for the exported automotive manifest shape descriptor.
125pub fn manifest_shape_symbol() -> Symbol {
126    Symbol::qualified("auto", "manifest-shape")
127}
128
129fn string_list(cx: &mut LoadCx, items: &[&str]) -> Result<sim_kernel::Value> {
130    cx.factory().list(
131        items
132            .iter()
133            .map(|item| cx.factory().string((*item).to_owned()))
134            .collect::<Result<Vec<_>>>()?,
135    )
136}
137
138fn parse_symbol(text: &str) -> Symbol {
139    if let Some((namespace, name)) = text.split_once('/') {
140        Symbol::qualified(namespace, name)
141    } else {
142        Symbol::new(text)
143    }
144}