use crate::Node;
use crate::core::HugrNode;
use crate::types::{Type, TypeBound};
use derive_more::From as DerFrom;
use smol_str::SmolStr;
use super::{AliasDecl, OpTag};
pub trait NodeHandle<N = Node>: Clone {
const TAG: OpTag;
fn node(&self) -> N;
#[inline]
fn tag(&self) -> OpTag {
Self::TAG
}
fn try_cast<T: NodeHandle<N> + From<N>>(&self) -> Option<T> {
T::TAG.is_superset(Self::TAG).then(|| self.node().into())
}
#[must_use]
fn can_hold(tag: OpTag) -> bool {
Self::TAG.is_superset(tag)
}
}
pub trait ContainerHandle<N = Node>: NodeHandle<N> {
type ChildrenHandle: NodeHandle<N>;
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, DerFrom, Debug)]
pub struct DataflowOpID<N = Node>(N);
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, DerFrom, Debug)]
pub struct DfgID<N = Node>(N);
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, DerFrom, Debug)]
pub struct CfgID<N = Node>(N);
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, DerFrom, Debug)]
pub struct ModuleRootID<N = Node>(N);
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, DerFrom, Debug)]
pub struct ModuleID<N = Node>(N);
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, DerFrom, Debug)]
pub struct FuncID<const DEF: bool, N = Node>(N);
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AliasID<const DEF: bool, N = Node> {
node: N,
name: SmolStr,
bound: TypeBound,
}
impl<const DEF: bool, N> AliasID<DEF, N> {
pub fn new(node: N, name: SmolStr, bound: TypeBound) -> Self {
Self { node, name, bound }
}
pub fn get_alias_type(&self) -> Type {
Type::new_alias(AliasDecl::new(self.name.clone(), self.bound))
}
pub fn get_name(&self) -> &SmolStr {
&self.name
}
}
#[derive(DerFrom, Debug, Clone, PartialEq, Eq)]
pub struct ConstID<N = Node>(N);
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, DerFrom, Debug)]
pub struct BasicBlockID<N = Node>(N);
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, DerFrom, Debug)]
pub struct CaseID<N = Node>(N);
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, DerFrom, Debug)]
pub struct TailLoopID<N = Node>(N);
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, DerFrom, Debug)]
pub struct ConditionalID<N = Node>(N);
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, DerFrom, Debug)]
pub struct DataflowParentID<N = Node>(N);
macro_rules! impl_nodehandle {
($name:ident, $tag:expr) => {
impl_nodehandle!($name, $tag, 0);
};
($name:ident, $tag:expr, $node_attr:tt) => {
impl<N: HugrNode> NodeHandle<N> for $name<N> {
const TAG: OpTag = $tag;
#[inline]
fn node(&self) -> N {
self.$node_attr
}
}
};
}
impl_nodehandle!(DataflowParentID, OpTag::DataflowParent);
impl_nodehandle!(DataflowOpID, OpTag::DataflowChild);
impl_nodehandle!(ConditionalID, OpTag::Conditional);
impl_nodehandle!(CaseID, OpTag::Case);
impl_nodehandle!(DfgID, OpTag::Dfg);
impl_nodehandle!(TailLoopID, OpTag::TailLoop);
impl_nodehandle!(CfgID, OpTag::Cfg);
impl_nodehandle!(ModuleRootID, OpTag::ModuleRoot);
impl_nodehandle!(ModuleID, OpTag::ModuleOp);
impl_nodehandle!(ConstID, OpTag::Const);
impl_nodehandle!(BasicBlockID, OpTag::DataflowBlock);
impl<const DEF: bool, N: HugrNode> NodeHandle<N> for FuncID<DEF, N> {
const TAG: OpTag = OpTag::Function;
#[inline]
fn node(&self) -> N {
self.0
}
}
impl<const DEF: bool, N: HugrNode> NodeHandle<N> for AliasID<DEF, N> {
const TAG: OpTag = OpTag::Alias;
#[inline]
fn node(&self) -> N {
self.node
}
}
impl<N: HugrNode> NodeHandle<N> for N {
const TAG: OpTag = OpTag::Any;
#[inline]
fn node(&self) -> N {
*self
}
}
macro_rules! impl_containerHandle {
($name:ident, $children:ident) => {
impl<N: HugrNode> ContainerHandle<N> for $name<N> {
type ChildrenHandle = $children<N>;
}
};
}
impl_containerHandle!(DataflowParentID, DataflowOpID);
impl_containerHandle!(DfgID, DataflowOpID);
impl_containerHandle!(TailLoopID, DataflowOpID);
impl_containerHandle!(ConditionalID, CaseID);
impl_containerHandle!(CaseID, DataflowOpID);
impl_containerHandle!(ModuleRootID, ModuleID);
impl_containerHandle!(CfgID, BasicBlockID);
impl_containerHandle!(BasicBlockID, DataflowOpID);
impl<N: HugrNode> ContainerHandle<N> for FuncID<true, N> {
type ChildrenHandle = DataflowOpID<N>;
}
impl<N: HugrNode> ContainerHandle<N> for AliasID<true, N> {
type ChildrenHandle = DataflowOpID<N>;
}