1use sim_kernel::{
4 AbiVersion, Export, Lib, LibManifest, LibTarget, Linker, LoadCx, Result, Symbol, Version,
5};
6
7use crate::parse_symbol;
8
9pub type InstallFn = for<'a> fn(&mut Linker<'a>) -> Result<()>;
11pub type ConformanceFn = fn(&mut sim_kernel::Cx) -> Result<()>;
13
14#[derive(Clone, Copy)]
20pub struct CitizenInfo {
21 pub symbol: &'static str,
23 pub version: u32,
25 pub crate_name: &'static str,
27 pub arity: usize,
29 pub install: InstallFn,
31 pub conformance: ConformanceFn,
33}
34
35inventory::collect!(CitizenInfo);
36
37pub fn registered_citizens() -> impl Iterator<Item = &'static CitizenInfo> {
39 inventory::iter::<CitizenInfo>.into_iter()
40}
41
42pub fn install_all(linker: &mut Linker<'_>) -> Result<()> {
44 for info in registered_citizens() {
45 (info.install)(linker)?;
46 }
47 Ok(())
48}
49
50pub fn install_namespace(linker: &mut Linker<'_>, namespace: &str) -> Result<()> {
52 for info in
53 registered_citizens().filter(|info| symbol_namespace(info.symbol) == Some(namespace))
54 {
55 (info.install)(linker)?;
56 }
57 Ok(())
58}
59
60#[derive(Clone, Copy, Debug, Default)]
66pub struct CitizenLib {
67 namespace: Option<&'static str>,
68}
69
70impl CitizenLib {
71 pub fn all() -> Self {
73 Self { namespace: None }
74 }
75
76 pub fn namespace(namespace: &'static str) -> Self {
78 Self {
79 namespace: Some(namespace),
80 }
81 }
82}
83
84impl Lib for CitizenLib {
85 fn manifest(&self) -> LibManifest {
86 let id = match self.namespace {
87 Some(namespace) => Symbol::qualified("citizen", namespace.to_owned()),
88 None => Symbol::qualified("citizen", "all"),
89 };
90 LibManifest {
91 id,
92 version: Version(env!("CARGO_PKG_VERSION").to_owned()),
93 abi: AbiVersion { major: 0, minor: 1 },
94 target: LibTarget::HostRegistered,
95 requires: Vec::new(),
96 capabilities: Vec::new(),
97 exports: registered_citizens()
98 .filter(|info| match self.namespace {
99 Some(namespace) => symbol_namespace(info.symbol) == Some(namespace),
100 None => true,
101 })
102 .map(|info| Export::Class {
103 symbol: parse_symbol(info.symbol),
104 class_id: None,
105 })
106 .collect(),
107 }
108 }
109
110 fn load(&self, _cx: &mut LoadCx, linker: &mut Linker<'_>) -> Result<()> {
111 match self.namespace {
112 Some(namespace) => install_namespace(linker, namespace),
113 None => install_all(linker),
114 }
115 }
116}
117
118fn symbol_namespace(symbol: &str) -> Option<&str> {
119 symbol.split_once('/').map(|(namespace, _)| namespace)
120}