use crate::data;
use gantz_ca::{ContentAddr, NodeData};
use std::collections::{BTreeMap, HashMap};
#[derive(Clone, Debug)]
pub struct Builtin {
pub name: &'static str,
pub node: NodeData,
}
#[derive(Clone, Debug, Default)]
pub struct Builtins {
by_name: BTreeMap<&'static str, NodeData>,
addr_by_name: BTreeMap<&'static str, ContentAddr>,
name_by_addr: HashMap<ContentAddr, &'static str>,
}
impl Builtin {
pub fn new<T>(name: &'static str, node: &T) -> Self
where
T: gantz_nodetag::NodeTag + serde::Serialize + crate::Node,
{
let node = data::erase_node_typed(node)
.unwrap_or_else(|e| panic!("builtin `{name}` failed to erase: {e}"));
Self { name, node }
}
}
impl Builtins {
pub fn from_specs(specs: impl IntoIterator<Item = Builtin>) -> Self {
let mut by_name = BTreeMap::new();
let mut addr_by_name = BTreeMap::new();
let mut name_by_addr = HashMap::new();
for spec in specs {
let addr = spec.node.content_addr();
if let Some(prev) = name_by_addr.insert(addr, spec.name) {
panic!(
"builtins `{prev}` and `{}` share the content address {addr}",
spec.name,
);
}
addr_by_name.insert(spec.name, addr);
if by_name.insert(spec.name, spec.node).is_some() {
panic!("duplicate builtin name: `{}`", spec.name);
}
}
Self {
by_name,
addr_by_name,
name_by_addr,
}
}
pub fn names(&self) -> impl Iterator<Item = &'static str> + '_ {
self.by_name.keys().copied()
}
pub fn node_data(&self, name: &str) -> Option<&NodeData> {
self.by_name.get(name)
}
pub fn get(&self, ca: &ContentAddr) -> Option<&NodeData> {
self.name(ca).and_then(|name| self.by_name.get(name))
}
pub fn name(&self, ca: &ContentAddr) -> Option<&'static str> {
self.name_by_addr.get(ca).copied()
}
pub fn content_addr(&self, name: &str) -> Option<ContentAddr> {
self.addr_by_name.get(name).copied()
}
}