use crate::graph::Graph;
use crate::id::{NodeId, PortId};
use std::collections::HashMap;
use std::hash::Hash;
pub trait KeyedNodeTemplate<N, P, K> {
fn node_data(&self) -> N;
fn keyed_ports(&self) -> Vec<(K, P)>;
}
pub trait NodeTemplate<N, P> {
fn node_data(&self) -> N;
fn port_data(&self) -> Vec<P>;
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub struct NodeProto<N, P> {
pub data: N,
pub ports: Vec<P>,
}
impl<N: Clone, P: Clone> NodeTemplate<N, P> for NodeProto<N, P> {
fn node_data(&self) -> N {
self.data.clone()
}
fn port_data(&self) -> Vec<P> {
self.ports.clone()
}
}
impl<N, P, E> Graph<N, P, E> {
pub fn instantiate(
&mut self,
template: &(impl NodeTemplate<N, P> + ?Sized),
) -> (NodeId, Vec<PortId>) {
let node = self.add_node(template.node_data());
let ports = template
.port_data()
.into_iter()
.map(|p| {
self.add_port(node, p)
.expect("node was just added; it must exist")
})
.collect();
(node, ports)
}
pub fn instantiate_keyed<K>(
&mut self,
template: &(impl KeyedNodeTemplate<N, P, K> + ?Sized),
) -> (NodeId, HashMap<K, PortId>)
where
K: Eq + Hash,
{
let node = self.add_node(template.node_data());
let map = template
.keyed_ports()
.into_iter()
.map(|(key, data)| {
let port = self
.add_port(node, data)
.expect("node was just added; it must exist");
(key, port)
})
.collect();
(node, map)
}
}
#[cfg(test)]
mod tests {
use super::*;
struct Ic74x00;
impl NodeTemplate<&'static str, &'static str> for Ic74x00 {
fn node_data(&self) -> &'static str {
"74x00"
}
fn port_data(&self) -> Vec<&'static str> {
vec!["1A", "1B", "1Y", "GND", "VCC"]
}
}
#[test]
fn instantiate_concrete_and_dyn() {
let mut g: Graph<&str, &str, ()> = Graph::new();
let (u1, u1_pins) = g.instantiate(&Ic74x00);
assert_eq!(g[u1], "74x00");
assert_eq!(u1_pins.len(), 5);
assert_eq!(g[u1_pins[3]], "GND");
let palette: Vec<Box<dyn NodeTemplate<&str, &str>>> = vec![
Box::new(Ic74x00),
Box::new(NodeProto {
data: "R",
ports: vec!["a", "b"],
}),
];
let (u2, _) = g.instantiate(palette[0].as_ref());
let (r1, r1_pins) = g.instantiate(palette[1].as_ref());
assert_eq!(g[u2], "74x00");
assert_eq!(g[r1], "R");
assert_eq!(r1_pins.len(), 2);
let order: Vec<_> = g.ports(u1).collect();
assert_eq!(order, u1_pins);
}
}