use std::marker::PhantomData;
use crate::hugr::HugrError;
use crate::ops::handle::NodeHandle;
use crate::ops::{OpTag, OpTrait};
use crate::{Hugr, Node};
use super::HugrView;
mod dfg;
pub use dfg::InvalidSignature;
#[derive(Clone)]
pub struct RootChecked<H, Handle = Node>(H, PhantomData<Handle>);
impl<H: HugrView, Handle: NodeHandle<H::Node>> RootChecked<H, Handle> {
const TAG: OpTag = Handle::TAG;
pub fn tag(&self) -> OpTag {
let tag = self.0.get_optype(self.0.entrypoint()).tag();
debug_assert!(Self::TAG.is_superset(tag));
tag
}
pub fn try_new(hugr: H) -> Result<Self, HugrError> {
Self::check(&hugr)?;
Ok(Self(hugr, PhantomData))
}
pub fn check(hugr: &H) -> Result<(), HugrError> {
check_tag::<Handle, _>(hugr, hugr.entrypoint())?;
Ok(())
}
pub fn hugr(&self) -> &H {
&self.0
}
pub fn into_hugr(self) -> H {
self.0
}
pub fn as_ref(&self) -> RootChecked<&H, Handle> {
RootChecked(&self.0, PhantomData)
}
}
impl<H: AsRef<Hugr>, Handle> AsRef<Hugr> for RootChecked<H, Handle> {
fn as_ref(&self) -> &Hugr {
self.0.as_ref()
}
}
pub fn check_tag<Required: NodeHandle<N>, N>(
hugr: &impl HugrView<Node = N>,
node: N,
) -> Result<(), HugrError> {
let actual = hugr.get_optype(node).tag();
let required = Required::TAG;
if !required.is_superset(actual) {
return Err(HugrError::InvalidTag { required, actual });
}
Ok(())
}
#[cfg(test)]
mod test {
use super::RootChecked;
use crate::hugr::HugrError;
use crate::ops::handle::{CfgID, DfgID};
use crate::ops::{OpTag, OpType};
use crate::{Hugr, ops, types::Signature};
#[test]
fn root_checked() {
let root_type: OpType = ops::DFG {
signature: Signature::new(vec![], vec![]),
}
.into();
let mut h = Hugr::new_with_entrypoint(root_type.clone()).unwrap();
let cfg_v = RootChecked::<_, CfgID>::check(&h);
assert_eq!(
cfg_v.err(),
Some(HugrError::InvalidTag {
required: OpTag::Cfg,
actual: OpTag::Dfg
})
);
let dfg_v = RootChecked::<&mut Hugr, DfgID>::try_new(&mut h).unwrap();
assert!(OpTag::Dfg.is_superset(dfg_v.tag()));
assert_eq!(dfg_v.as_ref().tag(), dfg_v.tag());
}
}