diff --git a/hugr-core/src/builder/build_traits.rs b/hugr-core/src/builder/build_traits.rs index 3e22623b27..ac4d46645d 100644 --- a/hugr-core/src/builder/build_traits.rs +++ b/hugr-core/src/builder/build_traits.rs @@ -82,10 +82,20 @@ pub trait Container { self.add_child_node(constant.into()).into() } - /// Insert a HUGR as a child of the container. + /// Insert a HUGR's entrypoint region as a child of the container. + /// + /// To insert an arbitrary region of a HUGR, use [`Container::add_hugr_region`]. fn add_hugr(&mut self, child: Hugr) -> InsertionResult { + let region = child.entrypoint(); + self.add_hugr_region(child, region) + } + + /// Insert a HUGR region as a child of the container. + /// + /// To insert the entrypoint region of a HUGR, use [`Container::add_hugr`]. + fn add_hugr_region(&mut self, child: Hugr, region: Node) -> InsertionResult { let parent = self.container_node(); - self.hugr_mut().insert_hugr(parent, child) + self.hugr_mut().insert_region(parent, child, region) } /// Insert a copy of a HUGR as a child of the container. @@ -200,6 +210,10 @@ pub trait Dataflow: Container { /// Insert a hugr-defined op to the sibling graph, wiring up the /// `input_wires` to the incoming ports of the resulting root node. /// + /// Inserts everything from the entrypoint region of the HUGR. + /// See [`Dataflow::add_hugr_region_with_wires`] for a generic version that allows + /// inserting a region other than the entrypoint. + /// /// # Errors /// /// This function will return an error if there is an error when adding the @@ -209,9 +223,29 @@ pub trait Dataflow: Container { hugr: Hugr, input_wires: impl IntoIterator, ) -> Result, BuildError> { - let optype = hugr.get_optype(hugr.entrypoint()).clone(); + let region = hugr.entrypoint(); + self.add_hugr_region_with_wires(hugr, region, input_wires) + } + + /// Insert a hugr-defined op to the sibling graph, wiring up the + /// `input_wires` to the incoming ports of the resulting root node. + /// + /// `region` must be a node in the `hugr`. See [`Dataflow::add_hugr_with_wires`] + /// for a helper that inserts the entrypoint region to the HUGR. + /// + /// # Errors + /// + /// This function will return an error if there is an error when adding the + /// node. + fn add_hugr_region_with_wires( + &mut self, + hugr: Hugr, + region: Node, + input_wires: impl IntoIterator, + ) -> Result, BuildError> { + let optype = hugr.get_optype(region).clone(); let num_outputs = optype.value_output_count(); - let node = self.add_hugr(hugr).inserted_entrypoint; + let node = self.add_hugr_region(hugr, region).inserted_entrypoint; wire_up_inputs(input_wires, node, self).map_err(|error| BuildError::OperationWiring { op: Box::new(optype), diff --git a/hugr-core/src/hugr/hugrmut.rs b/hugr-core/src/hugr/hugrmut.rs index 0265acd59f..74a6d1461d 100644 --- a/hugr-core/src/hugr/hugrmut.rs +++ b/hugr-core/src/hugr/hugrmut.rs @@ -183,7 +183,23 @@ pub trait HugrMut: HugrMutInternals { /// # Panics /// /// If the root node is not in the graph. - fn insert_hugr(&mut self, root: Self::Node, other: Hugr) -> InsertionResult; + fn insert_hugr(&mut self, root: Self::Node, other: Hugr) -> InsertionResult { + let region = other.entrypoint(); + Self::insert_region(self, root, other, region) + } + + /// Insert a sub-region of another hugr into this one, under a given parent node. + /// + /// # Panics + /// + /// - If the root node is not in the graph. + /// - If the `region` node is not in `other`. + fn insert_region( + &mut self, + root: Self::Node, + other: Hugr, + region: Node, + ) -> InsertionResult; /// Copy another hugr into this one, under a given parent node. /// @@ -247,15 +263,17 @@ pub trait HugrMut: HugrMutInternals { ExtensionRegistry: Extend; } -/// Records the result of inserting a Hugr or view -/// via [`HugrMut::insert_hugr`] or [`HugrMut::insert_from_view`]. +/// Records the result of inserting a Hugr or view via [`HugrMut::insert_hugr`], +/// [`HugrMut::insert_from_view`], or [`HugrMut::insert_region`]. /// -/// Contains a map from the nodes in the source HUGR to the nodes in the -/// target HUGR, using their respective `Node` types. +/// Contains a map from the nodes in the source HUGR to the nodes in the target +/// HUGR, using their respective `Node` types. pub struct InsertionResult { - /// The node, after insertion, that was the entrypoint of the inserted Hugr. + /// The node, after insertion, that was the root of the inserted Hugr. /// - /// That is, the value in [`InsertionResult::node_map`] under the key that was the [`HugrView::entrypoint`]. + /// That is, the value in [`InsertionResult::node_map`] under the key that + /// was the the `region` passed to [`HugrMut::insert_region`] or the + /// [`HugrView::entrypoint`] in the other cases. pub inserted_entrypoint: TargetN, /// Map from nodes in the Hugr/view that was inserted, to their new /// positions in the Hugr into which said was inserted. @@ -394,17 +412,14 @@ impl HugrMut for Hugr { (src_port, dst_port) } - fn insert_hugr( + fn insert_region( &mut self, root: Self::Node, mut other: Hugr, + region: Node, ) -> InsertionResult { - let node_map = insert_hugr_internal(self, &other, other.entry_descendants(), |&n| { - if n == other.entrypoint() { - Some(root) - } else { - None - } + let node_map = insert_hugr_internal(self, &other, other.descendants(region), |&n| { + if n == region { Some(root) } else { None } }); // Merge the extension sets. self.extensions.extend(other.extensions()); @@ -420,7 +435,7 @@ impl HugrMut for Hugr { self.metadata.set(new_node_pg, meta); } InsertionResult { - inserted_entrypoint: node_map[&other.entrypoint()], + inserted_entrypoint: node_map[®ion], node_map, } } diff --git a/hugr-core/src/hugr/views/impls.rs b/hugr-core/src/hugr/views/impls.rs index 75311f2f73..dbc9ad7b8f 100644 --- a/hugr-core/src/hugr/views/impls.rs +++ b/hugr-core/src/hugr/views/impls.rs @@ -115,6 +115,7 @@ macro_rules! hugr_mut_methods { fn disconnect(&mut self, node: Self::Node, port: impl Into); fn add_other_edge(&mut self, src: Self::Node, dst: Self::Node) -> (crate::OutgoingPort, crate::IncomingPort); fn insert_hugr(&mut self, root: Self::Node, other: crate::Hugr) -> crate::hugr::hugrmut::InsertionResult; + fn insert_region(&mut self, root: Self::Node, other: crate::Hugr, region: crate::Node) -> crate::hugr::hugrmut::InsertionResult; fn insert_from_view(&mut self, root: Self::Node, other: &Other) -> crate::hugr::hugrmut::InsertionResult; fn insert_subgraph(&mut self, root: Self::Node, other: &Other, subgraph: &crate::hugr::views::SiblingSubgraph) -> std::collections::HashMap; fn use_extension(&mut self, extension: impl Into>); diff --git a/hugr-core/src/hugr/views/rerooted.rs b/hugr-core/src/hugr/views/rerooted.rs index 8c84abdc71..18821cfe29 100644 --- a/hugr-core/src/hugr/views/rerooted.rs +++ b/hugr-core/src/hugr/views/rerooted.rs @@ -138,6 +138,7 @@ impl HugrMut for Rerooted { fn disconnect(&mut self, node: Self::Node, port: impl Into); fn add_other_edge(&mut self, src: Self::Node, dst: Self::Node) -> (crate::OutgoingPort, crate::IncomingPort); fn insert_hugr(&mut self, root: Self::Node, other: crate::Hugr) -> crate::hugr::hugrmut::InsertionResult; + fn insert_region(&mut self, root: Self::Node, other: crate::Hugr, region: crate::Node) -> crate::hugr::hugrmut::InsertionResult; fn insert_from_view(&mut self, root: Self::Node, other: &Other) -> crate::hugr::hugrmut::InsertionResult; fn insert_subgraph(&mut self, root: Self::Node, other: &Other, subgraph: &crate::hugr::views::SiblingSubgraph) -> std::collections::HashMap; fn use_extension(&mut self, extension: impl Into>);