diff --git a/hugr-core/src/builder/cfg.rs b/hugr-core/src/builder/cfg.rs index bcb6aff3b..c2de140d8 100644 --- a/hugr-core/src/builder/cfg.rs +++ b/hugr-core/src/builder/cfg.rs @@ -392,7 +392,11 @@ impl + AsRef> BlockBuilder { Dataflow::set_outputs(self, [branch_wire].into_iter().chain(outputs)) } fn create(base: B, block_n: Node) -> Result { - let block_op = base.get_optype(block_n).as_dataflow_block().unwrap(); + let block_op = base + .as_ref() + .get_optype(block_n) + .as_dataflow_block() + .unwrap(); let signature = block_op.inner_signature(); let db = DFGBuilder::create_with_io(base, block_n, signature)?; Ok(BlockBuilder::from_dfg_builder(db)) diff --git a/hugr-core/src/hugr/internal.rs b/hugr-core/src/hugr/internal.rs index 47bbd657b..3f1c6b6ff 100644 --- a/hugr-core/src/hugr/internal.rs +++ b/hugr-core/src/hugr/internal.rs @@ -1,7 +1,11 @@ //! Internal traits, not exposed in the public `hugr` API. +use std::borrow::Cow; use std::ops::Range; +use std::rc::Rc; +use std::sync::Arc; +use delegate::delegate; use portgraph::{LinkView, MultiPortGraph, PortMut, PortView}; use crate::ops::handle::NodeHandle; @@ -31,7 +35,7 @@ pub trait HugrInternals { fn root_node(&self) -> Node; } -impl> HugrInternals for T { +impl HugrInternals for Hugr { type Portgraph<'p> = &'p MultiPortGraph where @@ -39,20 +43,103 @@ impl> HugrInternals for T { #[inline] fn portgraph(&self) -> Self::Portgraph<'_> { - &self.as_ref().graph + &self.graph } #[inline] fn base_hugr(&self) -> &Hugr { - self.as_ref() + self } #[inline] fn root_node(&self) -> Node { - self.as_ref().root.into() + self.root.into() } } +impl HugrInternals for &T { + type Portgraph<'p> + = T::Portgraph<'p> + where + Self: 'p; + delegate! { + to (**self) { + fn portgraph(&self) -> Self::Portgraph<'_>; + fn base_hugr(&self) -> &Hugr; + fn root_node(&self) -> Node; + } + } +} + +impl HugrInternals for &mut T { + type Portgraph<'p> + = T::Portgraph<'p> + where + Self: 'p; + delegate! { + to (**self) { + fn portgraph(&self) -> Self::Portgraph<'_>; + fn base_hugr(&self) -> &Hugr; + fn root_node(&self) -> Node; + } + } +} + +impl HugrInternals for Rc { + type Portgraph<'p> + = T::Portgraph<'p> + where + Self: 'p; + delegate! { + to (**self) { + fn portgraph(&self) -> Self::Portgraph<'_>; + fn base_hugr(&self) -> &Hugr; + fn root_node(&self) -> Node; + } + } +} + +impl HugrInternals for Arc { + type Portgraph<'p> + = T::Portgraph<'p> + where + Self: 'p; + delegate! { + to (**self) { + fn portgraph(&self) -> Self::Portgraph<'_>; + fn base_hugr(&self) -> &Hugr; + fn root_node(&self) -> Node; + } + } +} + +impl HugrInternals for Box { + type Portgraph<'p> + = T::Portgraph<'p> + where + Self: 'p; + delegate! { + to (**self) { + fn portgraph(&self) -> Self::Portgraph<'_>; + fn base_hugr(&self) -> &Hugr; + fn root_node(&self) -> Node; + } + } +} + +impl HugrInternals for Cow<'_, T> { + type Portgraph<'p> + = T::Portgraph<'p> + where + Self: 'p; + delegate! { + to self.as_ref() { + fn portgraph(&self) -> Self::Portgraph<'_>; + fn base_hugr(&self) -> &Hugr; + fn root_node(&self) -> Node; + } + } +} /// Trait for accessing the mutable internals of a Hugr(Mut). /// /// Specifically, this trait lets you apply arbitrary modifications that may diff --git a/hugr-core/src/hugr/views.rs b/hugr-core/src/hugr/views.rs index 7d744c150..30015e2c3 100644 --- a/hugr-core/src/hugr/views.rs +++ b/hugr-core/src/hugr/views.rs @@ -1,6 +1,7 @@ //! Read-only access into HUGR graphs and subgraphs. pub mod descendants; +mod impls; pub mod petgraph; pub mod render; mod root_checked; @@ -513,41 +514,35 @@ impl ExtractHugr for &mut Hugr { } } -impl> HugrView for T { +impl HugrView for Hugr { #[inline] fn contains_node(&self, node: Node) -> bool { - self.as_ref().graph.contains_node(node.pg_index()) + self.graph.contains_node(node.pg_index()) } #[inline] fn node_count(&self) -> usize { - self.as_ref().graph.node_count() + self.graph.node_count() } #[inline] fn edge_count(&self) -> usize { - self.as_ref().graph.link_count() + self.graph.link_count() } #[inline] fn nodes(&self) -> impl Iterator + Clone { - self.as_ref().graph.nodes_iter().map_into() + self.graph.nodes_iter().map_into() } #[inline] fn node_ports(&self, node: Node, dir: Direction) -> impl Iterator + Clone { - self.as_ref() - .graph - .port_offsets(node.pg_index(), dir) - .map_into() + self.graph.port_offsets(node.pg_index(), dir).map_into() } #[inline] fn all_node_ports(&self, node: Node) -> impl Iterator + Clone { - self.as_ref() - .graph - .all_port_offsets(node.pg_index()) - .map_into() + self.graph.all_port_offsets(node.pg_index()).map_into() } #[inline] @@ -557,54 +552,46 @@ impl> HugrView for T { port: impl Into, ) -> impl Iterator + Clone { let port = port.into(); - let hugr = self.as_ref(); - let port = hugr + + let port = self .graph .port_index(node.pg_index(), port.pg_offset()) .unwrap(); - hugr.graph.port_links(port).map(|(_, link)| { + self.graph.port_links(port).map(|(_, link)| { let port = link.port(); - let node = hugr.graph.port_node(port).unwrap(); - let offset = hugr.graph.port_offset(port).unwrap(); + let node = self.graph.port_node(port).unwrap(); + let offset = self.graph.port_offset(port).unwrap(); (node.into(), offset.into()) }) } #[inline] fn node_connections(&self, node: Node, other: Node) -> impl Iterator + Clone { - let hugr = self.as_ref(); - - hugr.graph + self.graph .get_connections(node.pg_index(), other.pg_index()) .map(|(p1, p2)| { - [p1, p2].map(|link| hugr.graph.port_offset(link.port()).unwrap().into()) + [p1, p2].map(|link| self.graph.port_offset(link.port()).unwrap().into()) }) } #[inline] fn num_ports(&self, node: Node, dir: Direction) -> usize { - self.as_ref().graph.num_ports(node.pg_index(), dir) + self.graph.num_ports(node.pg_index(), dir) } #[inline] fn children(&self, node: Node) -> impl DoubleEndedIterator + Clone { - self.as_ref().hierarchy.children(node.pg_index()).map_into() + self.hierarchy.children(node.pg_index()).map_into() } #[inline] fn neighbours(&self, node: Node, dir: Direction) -> impl Iterator + Clone { - self.as_ref() - .graph - .neighbours(node.pg_index(), dir) - .map_into() + self.graph.neighbours(node.pg_index(), dir).map_into() } #[inline] fn all_neighbours(&self, node: Node) -> impl Iterator + Clone { - self.as_ref() - .graph - .all_neighbours(node.pg_index()) - .map_into() + self.graph.all_neighbours(node.pg_index()).map_into() } } diff --git a/hugr-core/src/hugr/views/impls.rs b/hugr-core/src/hugr/views/impls.rs new file mode 100644 index 000000000..7f3f45386 --- /dev/null +++ b/hugr-core/src/hugr/views/impls.rs @@ -0,0 +1,101 @@ +use std::{borrow::Cow, rc::Rc, sync::Arc}; + +use delegate::delegate; + +use super::{HugrView, RootChecked}; +use crate::{Direction, Hugr, Node, Port}; + +macro_rules! hugr_view_methods { + // The extra ident here is because invocations of the macro cannot pass `self` as argument + ($arg:ident, $e:expr) => { + delegate! { + to ({let $arg=self; $e}) { + fn contains_node(&self, node: Node) -> bool; + fn node_count(&self) -> usize; + fn edge_count(&self) -> usize; + fn nodes(&self) -> impl Iterator + Clone; + fn node_ports(&self, node: Node, dir: Direction) -> impl Iterator + Clone; + fn all_node_ports(&self, node: Node) -> impl Iterator + Clone; + fn linked_ports( + &self, + node: Node, + port: impl Into, + ) -> impl Iterator + Clone; + fn node_connections(&self, node: Node, other: Node) -> impl Iterator + Clone; + fn num_ports(&self, node: Node, dir: Direction) -> usize; + fn children(&self, node: Node) -> impl DoubleEndedIterator + Clone; + fn neighbours(&self, node: Node, dir: Direction) -> impl Iterator + Clone; + fn all_neighbours(&self, node: Node) -> impl Iterator + Clone; + } + } + } +} + +impl HugrView for &T { + hugr_view_methods! {this, *this} +} + +impl HugrView for &mut T { + hugr_view_methods! {this, &**this} +} + +impl HugrView for Rc { + hugr_view_methods! {this, this.as_ref()} +} + +impl HugrView for Arc { + hugr_view_methods! {this, this.as_ref()} +} + +impl HugrView for Box { + hugr_view_methods! {this, this.as_ref()} +} + +impl HugrView for Cow<'_, T> { + hugr_view_methods! {this, this.as_ref()} +} + +impl, Root> HugrView for RootChecked { + hugr_view_methods! {this, this.as_ref()} +} + +#[cfg(test)] +mod test { + use std::{rc::Rc, sync::Arc}; + + use crate::hugr::views::{DescendantsGraph, HierarchyView}; + use crate::{Hugr, HugrView, Node}; + + struct ViewWrapper(H); + impl ViewWrapper { + fn nodes(&self) -> impl Iterator + '_ { + self.0.nodes() + } + } + + #[test] + fn test_refs_to_view() { + let h = Hugr::default(); + let v = ViewWrapper(&h); + let c = h.nodes().count(); + assert_eq!(v.nodes().count(), c); + let v2 = ViewWrapper(DescendantsGraph::::try_new(&h, h.root()).unwrap()); + // v2 owns the DescendantsGraph, but that only borrows `h`, so we still have both + assert_eq!(v2.nodes().count(), v.nodes().count()); + // And we can borrow the DescendantsGraph, even just a reference to that counts as a HugrView + assert_eq!(ViewWrapper(&v2.0).nodes().count(), v.nodes().count()); + + let vh = ViewWrapper(h); + assert_eq!(vh.nodes().count(), c); + let h: Hugr = vh.0; + assert_eq!(h.nodes().count(), c); + + let vb = ViewWrapper(Box::new(&h)); + assert_eq!(vb.nodes().count(), c); + let va = ViewWrapper(Arc::new(h)); + assert_eq!(va.nodes().count(), c); + let h = Arc::try_unwrap(va.0).unwrap(); + let vr = Rc::new(&h); + assert_eq!(ViewWrapper(&vr).nodes().count(), h.nodes().count()); + } +} diff --git a/hugr-core/src/hugr/views/root_checked.rs b/hugr-core/src/hugr/views/root_checked.rs index c98943966..88b0ad020 100644 --- a/hugr-core/src/hugr/views/root_checked.rs +++ b/hugr-core/src/hugr/views/root_checked.rs @@ -1,6 +1,9 @@ use std::marker::PhantomData; -use crate::hugr::internal::HugrMutInternals; +use delegate::delegate; +use portgraph::MultiPortGraph; + +use crate::hugr::internal::{HugrInternals, HugrMutInternals}; use crate::hugr::{HugrError, HugrMut}; use crate::ops::handle::NodeHandle; use crate::{Hugr, Node}; @@ -45,6 +48,20 @@ impl RootChecked<&mut Hugr, Root> { } } +impl, Root> HugrInternals for RootChecked { + type Portgraph<'p> + = &'p MultiPortGraph + where + Self: 'p; + delegate! { + to self.as_ref() { + fn portgraph(&self) -> Self::Portgraph<'_>; + fn base_hugr(&self) -> &Hugr; + fn root_node(&self) -> Node; + } + } +} + impl, Root: NodeHandle> RootTagged for RootChecked { type RootHandle = Root; }