Skip to content

Commit

Permalink
feat(hugr-core): Unseal and make public the traits HugrInternals an…
Browse files Browse the repository at this point in the history
…d `HugrMutInternals` (#1122)

Exposes `HugrInternals` and `HugrMutInternals` in
`hugr_core::hugr::internal` (but not in `hugr`).

Closes #1121
  • Loading branch information
aborgna-q authored May 29, 2024
1 parent 75d1cb5 commit f97ba06
Show file tree
Hide file tree
Showing 16 changed files with 256 additions and 240 deletions.
12 changes: 6 additions & 6 deletions hugr-core/src/builder/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ use super::{
BuildError, Container,
};

use crate::{
extension::ExtensionRegistry,
hugr::{hugrmut::sealed::HugrMutInternals, views::HugrView, ValidationError},
ops,
types::{PolyFuncType, Type, TypeBound},
};
use crate::extension::ExtensionRegistry;
use crate::hugr::internal::HugrMutInternals;
use crate::hugr::views::HugrView;
use crate::hugr::ValidationError;
use crate::ops;
use crate::types::{PolyFuncType, Type, TypeBound};

use crate::ops::handle::{AliasID, FuncID, NodeHandle};

Expand Down
2 changes: 1 addition & 1 deletion hugr-core/src/extension/infer/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::ops::{CustomOp, Lift, OpType};
use crate::{
builder::test::closed_dfg_root_hugr,
extension::prelude::PRELUDE_ID,
hugr::{hugrmut::sealed::HugrMutInternals, validate::ValidationError},
hugr::{internal::HugrMutInternals, validate::ValidationError},
ops::{dataflow::DataflowParent, handle::NodeHandle},
};

Expand Down
1 change: 1 addition & 0 deletions hugr-core/src/hugr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
pub mod hugrmut;

pub(crate) mod ident;
pub mod internal;
pub mod rewrite;
pub mod serialize;
pub mod validate;
Expand Down
185 changes: 9 additions & 176 deletions hugr-core/src/hugr/hugrmut.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,16 @@
use core::panic;
use std::collections::HashMap;
use std::ops::Range;

use portgraph::view::{NodeFilter, NodeFiltered};
use portgraph::{LinkMut, NodeIndex, PortMut, PortView, SecondaryMap};

use crate::hugr::views::SiblingSubgraph;
use crate::hugr::{Direction, HugrError, HugrView, Node, NodeType, RootTagged};
use crate::hugr::{HugrView, Node, NodeType, RootTagged};
use crate::hugr::{NodeMetadata, Rewrite};
use crate::{Hugr, IncomingPort, OutgoingPort, Port, PortIndex};

use self::sealed::HugrMutInternals;

use super::internal::HugrMutInternals;
use super::NodeMetadataMap;

/// Functions for low-level building of a HUGR.
Expand Down Expand Up @@ -465,7 +463,7 @@ fn insert_subgraph_internal(

/// Panic if [`HugrView::valid_node`] fails.
#[track_caller]
fn panic_invalid_node<H: HugrView + ?Sized>(hugr: &H, node: Node) {
pub(super) fn panic_invalid_node<H: HugrView + ?Sized>(hugr: &H, node: Node) {
if !hugr.valid_node(node) {
panic!(
"Received an invalid node {node} while mutating a HUGR:\n\n {}",
Expand All @@ -476,7 +474,7 @@ fn panic_invalid_node<H: HugrView + ?Sized>(hugr: &H, node: Node) {

/// Panic if [`HugrView::valid_non_root`] fails.
#[track_caller]
fn panic_invalid_non_root<H: HugrView + ?Sized>(hugr: &H, node: Node) {
pub(super) fn panic_invalid_non_root<H: HugrView + ?Sized>(hugr: &H, node: Node) {
if !hugr.valid_non_root(node) {
panic!(
"Received an invalid non-root node {node} while mutating a HUGR:\n\n {}",
Expand All @@ -487,7 +485,11 @@ fn panic_invalid_non_root<H: HugrView + ?Sized>(hugr: &H, node: Node) {

/// Panic if [`HugrView::valid_node`] fails.
#[track_caller]
fn panic_invalid_port<H: HugrView + ?Sized>(hugr: &H, node: Node, port: impl Into<Port>) {
pub(super) fn panic_invalid_port<H: HugrView + ?Sized>(
hugr: &H,
node: Node,
port: impl Into<Port>,
) {
let port = port.into();
if hugr
.portgraph()
Expand All @@ -501,175 +503,6 @@ fn panic_invalid_port<H: HugrView + ?Sized>(hugr: &H, node: Node, port: impl Int
}
}

pub(crate) mod sealed {
use super::*;
use crate::ops::handle::NodeHandle;

/// Trait for accessing the mutable internals of a Hugr(Mut).
///
/// Specifically, this trait lets you apply arbitrary modifications that may
/// invalidate the HUGR.
pub trait HugrMutInternals: RootTagged {
/// Returns the Hugr at the base of a chain of views.
fn hugr_mut(&mut self) -> &mut Hugr;

/// Set the number of ports on a node. This may invalidate the node's `PortIndex`.
///
/// # Panics
///
/// If the node is not in the graph.
fn set_num_ports(&mut self, node: Node, incoming: usize, outgoing: usize) {
panic_invalid_node(self, node);
self.hugr_mut().set_num_ports(node, incoming, outgoing)
}

/// Alter the number of ports on a node and returns a range with the new
/// port offsets, if any. This may invalidate the node's `PortIndex`.
///
/// The `direction` parameter specifies whether to add ports to the incoming
/// or outgoing list.
///
/// # Panics
///
/// If the node is not in the graph.
fn add_ports(&mut self, node: Node, direction: Direction, amount: isize) -> Range<usize> {
panic_invalid_node(self, node);
self.hugr_mut().add_ports(node, direction, amount)
}

/// Sets the parent of a node.
///
/// The node becomes the parent's last child.
///
/// # Panics
///
/// If either the node or the parent is not in the graph.
fn set_parent(&mut self, node: Node, parent: Node) {
panic_invalid_node(self, parent);
panic_invalid_non_root(self, node);
self.hugr_mut().set_parent(node, parent);
}

/// Move a node in the hierarchy to be the subsequent sibling of another
/// node.
///
/// The sibling node's parent becomes the new node's parent.
///
/// The node becomes the parent's last child.
///
/// # Panics
///
/// If either node is not in the graph, or if it is a root.
fn move_after_sibling(&mut self, node: Node, after: Node) {
panic_invalid_non_root(self, node);
panic_invalid_non_root(self, after);
self.hugr_mut().move_after_sibling(node, after);
}

/// Move a node in the hierarchy to be the prior sibling of another node.
///
/// The sibling node's parent becomes the new node's parent.
///
/// The node becomes the parent's last child.
///
/// # Panics
///
/// If either node is not in the graph, or if it is a root.
fn move_before_sibling(&mut self, node: Node, before: Node) {
panic_invalid_non_root(self, node);
panic_invalid_non_root(self, before);
self.hugr_mut().move_before_sibling(node, before)
}

/// Replace the OpType at node and return the old OpType.
/// In general this invalidates the ports, which may need to be resized to
/// match the OpType signature.
/// TODO: Add a version which ignores input extensions
///
/// # Errors
///
/// Returns a [`HugrError::InvalidTag`] if this would break the bound
/// ([`Self::RootHandle`]) on the root node's [OpTag].
///
/// # Panics
///
/// If the node is not in the graph.
fn replace_op(&mut self, node: Node, op: NodeType) -> Result<NodeType, HugrError> {
panic_invalid_node(self, node);
if node == self.root() && !Self::RootHandle::TAG.is_superset(op.tag()) {
return Err(HugrError::InvalidTag {
required: Self::RootHandle::TAG,
actual: op.tag(),
});
}
self.hugr_mut().replace_op(node, op)
}
}

/// Impl for non-wrapped Hugrs. Overwrites the recursive default-impls to directly use the hugr.
impl<T: RootTagged<RootHandle = Node> + AsMut<Hugr>> HugrMutInternals for T {
fn hugr_mut(&mut self) -> &mut Hugr {
self.as_mut()
}

#[inline]
fn set_num_ports(&mut self, node: Node, incoming: usize, outgoing: usize) {
self.hugr_mut()
.graph
.set_num_ports(node.pg_index(), incoming, outgoing, |_, _| {})
}

fn add_ports(&mut self, node: Node, direction: Direction, amount: isize) -> Range<usize> {
let mut incoming = self.hugr_mut().graph.num_inputs(node.pg_index());
let mut outgoing = self.hugr_mut().graph.num_outputs(node.pg_index());
let increment = |num: &mut usize| {
let new = num.saturating_add_signed(amount);
let range = *num..new;
*num = new;
range
};
let range = match direction {
Direction::Incoming => increment(&mut incoming),
Direction::Outgoing => increment(&mut outgoing),
};
self.hugr_mut()
.graph
.set_num_ports(node.pg_index(), incoming, outgoing, |_, _| {});
range
}

fn set_parent(&mut self, node: Node, parent: Node) {
self.hugr_mut().hierarchy.detach(node.pg_index());
self.hugr_mut()
.hierarchy
.push_child(node.pg_index(), parent.pg_index())
.expect("Inserting a newly-created node into the hierarchy should never fail.");
}

fn move_after_sibling(&mut self, node: Node, after: Node) {
self.hugr_mut().hierarchy.detach(node.pg_index());
self.hugr_mut()
.hierarchy
.insert_after(node.pg_index(), after.pg_index())
.expect("Inserting a newly-created node into the hierarchy should never fail.");
}

fn move_before_sibling(&mut self, node: Node, before: Node) {
self.hugr_mut().hierarchy.detach(node.pg_index());
self.hugr_mut()
.hierarchy
.insert_before(node.pg_index(), before.pg_index())
.expect("Inserting a newly-created node into the hierarchy should never fail.");
}

fn replace_op(&mut self, node: Node, op: NodeType) -> Result<NodeType, HugrError> {
// We know RootHandle=Node here so no need to check
let cur = self.hugr_mut().op_types.get_mut(node.pg_index());
Ok(std::mem::replace(cur, op))
}
}
}

#[cfg(test)]
mod test {
use crate::{
Expand Down
Loading

0 comments on commit f97ba06

Please sign in to comment.