use gantz_ca::ContentAddr;
use std::collections::{BTreeMap, HashMap};
pub trait Builtins: Send + Sync {
type Node: 'static + Send + Sync;
fn names(&self) -> Vec<&str>;
fn create(&self, name: &str) -> Option<Self::Node>;
fn instance(&self, ca: &ContentAddr) -> Option<&Self::Node>;
fn name(&self, ca: &ContentAddr) -> Option<&str>;
fn content_addr(&self, name: &str) -> Option<ContentAddr>;
fn demo_graph(&self, name: &str) -> Option<&str> {
let _ = name;
None
}
}
pub trait FromNode<T> {
fn from_node(node: T) -> Self;
}
pub struct Builtin<N> {
pub name: &'static str,
pub new: Box<dyn Fn() -> N + Send + Sync>,
pub demo_graph: Option<&'static str>,
}
pub struct BuiltinSet<N> {
builtins: BTreeMap<&'static str, Builtin<N>>,
instances: HashMap<ContentAddr, N>,
names: HashMap<ContentAddr, &'static str>,
}
impl<N> Builtin<N> {
pub fn new(name: &'static str, new: impl Fn() -> N + Send + Sync + 'static) -> Self {
Self {
name,
new: Box::new(new),
demo_graph: None,
}
}
}
impl<N> BuiltinSet<N>
where
N: gantz_ca::CaHash + Send + Sync + 'static,
{
pub fn from_specs(specs: impl IntoIterator<Item = Builtin<N>>) -> Self {
let mut builtins = BTreeMap::new();
let mut instances = HashMap::new();
let mut names = HashMap::new();
for spec in specs {
let node = (spec.new)();
let ca = gantz_ca::content_addr(&node);
instances.insert(ca, node);
names.insert(ca, spec.name);
if let Some(prev) = builtins.insert(spec.name, spec) {
panic!("duplicate builtin name: {:?}", prev.name);
}
}
Self {
builtins,
instances,
names,
}
}
}
impl<N: 'static + Send + Sync> Builtins for BuiltinSet<N> {
type Node = N;
fn names(&self) -> Vec<&str> {
self.builtins.keys().copied().collect()
}
fn create(&self, name: &str) -> Option<Self::Node> {
self.builtins.get(name).map(|b| (b.new)())
}
fn instance(&self, ca: &ContentAddr) -> Option<&Self::Node> {
self.instances.get(ca)
}
fn name(&self, ca: &ContentAddr) -> Option<&str> {
self.names.get(ca).copied()
}
fn content_addr(&self, name: &str) -> Option<ContentAddr> {
self.names
.iter()
.find(|(_, n)| **n == name)
.map(|(ca, _)| *ca)
}
fn demo_graph(&self, name: &str) -> Option<&str> {
self.builtins.get(name).and_then(|b| b.demo_graph)
}
}