use std::collections::BTreeMap;
#[derive(Debug, Default)]
pub struct HostFnRegistry {
specs: BTreeMap<String, HostFnSpec>,
}
#[derive(Debug, Clone)]
pub struct HostFnSpec {
pub name: String,
pub required_capability: Option<uni_plugin::Capability>,
pub docs: String,
}
impl HostFnRegistry {
#[must_use]
pub fn new() -> Self {
Self::default()
}
pub fn register(&mut self, spec: HostFnSpec) {
self.specs.insert(spec.name.clone(), spec);
}
#[must_use]
pub fn get(&self, name: &str) -> Option<&HostFnSpec> {
self.specs.get(name)
}
pub fn iter(&self) -> impl Iterator<Item = &HostFnSpec> {
self.specs.values()
}
#[must_use]
pub fn len(&self) -> usize {
self.specs.len()
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.specs.is_empty()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn registry_starts_empty() {
let r = HostFnRegistry::new();
assert!(r.is_empty());
assert_eq!(r.len(), 0);
}
#[test]
fn register_and_lookup_round_trip() {
let mut r = HostFnRegistry::new();
r.register(HostFnSpec {
name: "host_fs_read".to_owned(),
required_capability: Some(uni_plugin::Capability::Filesystem {
read: vec![],
write: vec![],
}),
docs: "Read a file from the host filesystem.".to_owned(),
});
let spec = r.get("host_fs_read").expect("registered");
assert!(matches!(
spec.required_capability,
Some(uni_plugin::Capability::Filesystem { .. })
));
assert_eq!(r.len(), 1);
}
#[test]
fn always_available_fns_have_no_required_capability() {
let mut r = HostFnRegistry::new();
r.register(HostFnSpec {
name: "host_log".to_owned(),
required_capability: None,
docs: "Emit a tracing event.".to_owned(),
});
let spec = r.get("host_log").expect("registered");
assert!(spec.required_capability.is_none());
}
#[test]
fn iter_yields_registered_specs() {
let mut r = HostFnRegistry::new();
r.register(HostFnSpec {
name: "a".to_owned(),
required_capability: None,
docs: String::new(),
});
r.register(HostFnSpec {
name: "b".to_owned(),
required_capability: Some(uni_plugin::Capability::Network { allow: vec![] }),
docs: String::new(),
});
let names: Vec<&str> = r.iter().map(|s| s.name.as_str()).collect();
assert_eq!(names, vec!["a", "b"]);
}
}