use std;
use std::collections::{BTreeMap, HashMap};
use std::fmt::Debug;
use std::hash::Hash;
use crate::id::NodeId;
pub trait GenericContext {}
pub trait NodeStorage<I> {
type Node;
fn get(&self, id: &I) -> Option<&Self::Node>;
fn set(&mut self, id: I, node: Self::Node) -> Option<Self::Node>;
}
impl<K, V> NodeStorage<K> for HashMap<K, V>
where
K: Hash + Eq,
{
type Node = V;
fn get(&self, id: &K) -> Option<&V> {
HashMap::get(self, id)
}
fn set(&mut self, id: K, node: V) -> Option<V> {
HashMap::insert(self, id, node)
}
}
impl<K, V> NodeStorage<K> for BTreeMap<K, V>
where
K: Ord,
{
type Node = V;
fn get(&self, id: &K) -> Option<&V> {
BTreeMap::get(self, id)
}
fn set(&mut self, id: K, node: V) -> Option<V> {
BTreeMap::insert(self, id, node)
}
}
pub trait NodeMaker<I, N> {
fn make(&self, id: I) -> Result<N>;
}
pub type Result<T> = std::result::Result<T, ()>;
pub trait NodeRef: Copy + Eq + Ord + Hash + Debug + Into<NodeId> {
fn alloc() -> Self {
Self::new(NodeId::alloc())
}
fn new(id: NodeId) -> Self;
}
#[macro_export]
macro_rules! node_ref {
($name:ident) => {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct $name($crate::NodeId);
impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(f, "{}({:?})", stringify!($name), self.0)
}
}
impl Into<$crate::NodeId> for $name {
fn into(self) -> $crate::NodeId {
self.0
}
}
impl $crate::score::NodeRef for $name {
fn new(id: $crate::NodeId) -> $name {
$name(id)
}
}
};
}
#[macro_export]
macro_rules! node_ref_group {
($name:ident: $($var:ident($ty:ty),)+) => {
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum $name {
$($var($ty),)*
}
impl std::fmt::Debug for $name {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
node_ref_group!(MATCHES *self, $($name::$var(id) => write!(f, "{}({:?})", stringify!($var), id)),*)
}
}
impl Into<$crate::NodeId> for $name {
fn into(self) -> $crate::NodeId {
node_ref_group!(MATCHES self, $($name::$var(id) => id.into()),*)
}
}
$(
impl From<$ty> for $name {
fn from(id: $ty) -> $name {
$name::$var(id)
}
}
)*
};
(MATCHES $value:expr, $($lhs:pat => $rhs:expr),+) => {
match $value {
$($lhs => $rhs),+
}
};
}
#[macro_export]
macro_rules! node_storage {
($name:ident<$($lt:tt),+>: $($node_name:ident : $node_ref:ty => $node:ty,)+) => {
pub struct $name<$($lt),*> {
$($node_name: std::collections::HashMap<$node_ref, $node>,)*
}
node_storage!(STRUCT_IMPL $name; $($lt),*; $($node_name, $node_ref, $node;)*);
};
($name:ident<$($lt:tt),+> where ($($wh:tt)+): $($node_name:ident : $node_ref:ty => $node:ty,)+) => {
pub struct $name<$($lt),*> where $($wh)* {
$($node_name: std::collections::HashMap<$node_ref, $node>,)*
}
node_storage!(STRUCT_IMPL $name; $($lt),*; $($node_name, $node_ref, $node;)*);
};
(STRUCT_IMPL $name:ident; $($lt:tt),+; $($node_name:ident, $node_ref:ty, $node:ty;)*) => {
impl<$($lt),*> $name<$($lt),*> {
pub fn new() -> $name<$($lt),*> {
$name {
$($node_name: std::collections::HashMap::new(),)*
}
}
}
node_storage!(TRAIT_IMPL $name; $($lt),*; $($node_name, $node_ref, $node;)*);
};
(TRAIT_IMPL $name:ident; $($lt:tt),+; $node_name:ident, $node_ref:ty, $node:ty; $($tail_name:ident, $tail_ref:ty, $tail:ty;)*) => {
impl<$($lt),*> $crate::score::NodeStorage<$node_ref> for $name<$($lt),*> {
type Node = $node;
fn get(&self, id: &$node_ref) -> Option<&$node> {
self.$node_name.get(id)
}
fn set(&mut self, id: $node_ref, node: $node) -> Option<$node> {
self.$node_name.insert(id, node)
}
}
node_storage!(TRAIT_IMPL $name; $($lt),*; $($tail_name, $tail_ref, $tail;)*);
};
(TRAIT_IMPL $name:ident; $($lt:tt),*;) => {}
}