1use std::ops::Range;
4use std::sync::OnceLock;
5
6use itertools::Itertools;
7use portgraph::{LinkMut, LinkView, MultiPortGraph, PortMut, PortOffset, PortView};
8
9use crate::extension::ExtensionRegistry;
10use crate::{Direction, Hugr, Node};
11
12use super::HugrView;
13use super::views::{panic_invalid_node, panic_invalid_non_entrypoint};
14use super::{NodeMetadataMap, OpType};
15use crate::ops::handle::NodeHandle;
16
17pub trait HugrInternals {
22 type RegionPortgraph<'p>: LinkView<LinkEndpoint: Eq> + Clone + 'p
24 where
25 Self: 'p;
26
27 type Node: Copy + Ord + std::fmt::Debug + std::fmt::Display + std::hash::Hash;
29
30 type RegionPortgraphNodes: PortgraphNodeMap<Self::Node>;
33
34 fn region_portgraph(
44 &self,
45 parent: Self::Node,
46 ) -> (
47 portgraph::view::FlatRegion<'_, Self::RegionPortgraph<'_>>,
48 Self::RegionPortgraphNodes,
49 );
50
51 fn node_metadata_map(&self, node: Self::Node) -> &NodeMetadataMap;
57}
58
59pub trait PortgraphNodeMap<N>: Clone + Sized + std::fmt::Debug {
62 fn to_portgraph(&self, node: N) -> portgraph::NodeIndex;
67
68 #[allow(clippy::wrong_self_convention)]
73 fn from_portgraph(&self, node: portgraph::NodeIndex) -> N;
74}
75
76#[derive(
78 Copy, Clone, Debug, Default, Eq, PartialEq, Hash, PartialOrd, Ord, derive_more::Display,
79)]
80pub struct DefaultPGNodeMap;
81
82impl PortgraphNodeMap<Node> for DefaultPGNodeMap {
83 #[inline]
84 fn to_portgraph(&self, node: Node) -> portgraph::NodeIndex {
85 node.into_portgraph()
86 }
87
88 #[inline]
89 fn from_portgraph(&self, node: portgraph::NodeIndex) -> Node {
90 node.into()
91 }
92}
93
94impl HugrInternals for Hugr {
95 type RegionPortgraph<'p>
96 = &'p MultiPortGraph
97 where
98 Self: 'p;
99
100 type Node = Node;
101
102 type RegionPortgraphNodes = DefaultPGNodeMap;
103
104 #[inline]
105 fn region_portgraph(
106 &self,
107 parent: Self::Node,
108 ) -> (
109 portgraph::view::FlatRegion<'_, Self::RegionPortgraph<'_>>,
110 Self::RegionPortgraphNodes,
111 ) {
112 let root = parent.into_portgraph();
113 let region =
114 portgraph::view::FlatRegion::new_without_root(&self.graph, &self.hierarchy, root);
115 (region, DefaultPGNodeMap)
116 }
117
118 #[inline]
119 fn node_metadata_map(&self, node: Self::Node) -> &NodeMetadataMap {
120 static EMPTY: OnceLock<NodeMetadataMap> = OnceLock::new();
121 panic_invalid_node(self, node);
122 let map = self.metadata.get(node.into_portgraph()).as_ref();
123 map.unwrap_or(EMPTY.get_or_init(Default::default))
124 }
125}
126
127pub trait HugrMutInternals: HugrView {
132 fn set_module_root(&mut self, root: Self::Node);
145
146 fn set_num_ports(&mut self, node: Self::Node, incoming: usize, outgoing: usize);
152
153 fn add_ports(&mut self, node: Self::Node, direction: Direction, amount: isize) -> Range<usize>;
165
166 fn insert_ports(
176 &mut self,
177 node: Self::Node,
178 direction: Direction,
179 index: usize,
180 amount: usize,
181 ) -> Range<usize>;
182
183 fn set_parent(&mut self, node: Self::Node, parent: Self::Node);
191
192 fn move_after_sibling(&mut self, node: Self::Node, after: Self::Node);
203
204 fn move_before_sibling(&mut self, node: Self::Node, before: Self::Node);
214
215 fn replace_op(&mut self, node: Self::Node, op: impl Into<OpType>) -> OpType;
228
229 fn optype_mut(&mut self, node: Self::Node) -> &mut OpType;
242
243 fn node_metadata_map_mut(&mut self, node: Self::Node) -> &mut NodeMetadataMap;
249
250 fn extensions_mut(&mut self) -> &mut ExtensionRegistry;
255}
256
257impl HugrMutInternals for Hugr {
259 fn set_module_root(&mut self, root: Node) {
260 panic_invalid_node(self, root.node());
261 let root = root.into_portgraph();
262 self.hierarchy.detach(root);
263 self.module_root = root;
264 }
265
266 #[inline]
267 fn set_num_ports(&mut self, node: Node, incoming: usize, outgoing: usize) {
268 panic_invalid_node(self, node);
269 self.graph
270 .set_num_ports(node.into_portgraph(), incoming, outgoing, |_, _| {});
271 }
272
273 fn add_ports(&mut self, node: Node, direction: Direction, amount: isize) -> Range<usize> {
274 panic_invalid_node(self, node);
275 let mut incoming = self.graph.num_inputs(node.into_portgraph());
276 let mut outgoing = self.graph.num_outputs(node.into_portgraph());
277 let increment = |num: &mut usize| {
278 let new = num.saturating_add_signed(amount);
279 let range = *num..new;
280 *num = new;
281 range
282 };
283 let range = match direction {
284 Direction::Incoming => increment(&mut incoming),
285 Direction::Outgoing => increment(&mut outgoing),
286 };
287 self.graph
288 .set_num_ports(node.into_portgraph(), incoming, outgoing, |_, _| {});
289 range
290 }
291
292 fn insert_ports(
293 &mut self,
294 node: Node,
295 direction: Direction,
296 index: usize,
297 amount: usize,
298 ) -> Range<usize> {
299 panic_invalid_node(self, node);
300 let old_num_ports = self.graph.num_ports(node.into_portgraph(), direction);
301
302 self.add_ports(node, direction, amount as isize);
303
304 for swap_from_port in (index..old_num_ports).rev() {
305 let swap_to_port = swap_from_port + amount;
306 let [from_port_index, to_port_index] = [swap_from_port, swap_to_port].map(|p| {
307 self.graph
308 .port_index(node.into_portgraph(), PortOffset::new(direction, p))
309 .unwrap()
310 });
311 let linked_ports = self
312 .graph
313 .port_links(from_port_index)
314 .map(|(_, to_subport)| to_subport.port())
315 .collect_vec();
316 self.graph.unlink_port(from_port_index);
317 for linked_port_index in linked_ports {
318 let _ = self
319 .graph
320 .link_ports(to_port_index, linked_port_index)
321 .expect("Ports exist");
322 }
323 }
324 index..index + amount
325 }
326
327 fn set_parent(&mut self, node: Node, parent: Node) {
328 panic_invalid_node(self, parent);
329 panic_invalid_node(self, node);
330 self.hierarchy.detach(node.into_portgraph());
331 self.hierarchy
332 .push_child(node.into_portgraph(), parent.into_portgraph())
333 .expect("Inserting a newly-created node into the hierarchy should never fail.");
334 }
335
336 fn move_after_sibling(&mut self, node: Node, after: Node) {
337 panic_invalid_non_entrypoint(self, node);
338 panic_invalid_non_entrypoint(self, after);
339 self.hierarchy.detach(node.into_portgraph());
340 self.hierarchy
341 .insert_after(node.into_portgraph(), after.into_portgraph())
342 .expect("Inserting a newly-created node into the hierarchy should never fail.");
343 }
344
345 fn move_before_sibling(&mut self, node: Node, before: Node) {
346 panic_invalid_non_entrypoint(self, node);
347 panic_invalid_non_entrypoint(self, before);
348 self.hierarchy.detach(node.into_portgraph());
349 self.hierarchy
350 .insert_before(node.into_portgraph(), before.into_portgraph())
351 .expect("Inserting a newly-created node into the hierarchy should never fail.");
352 }
353
354 fn replace_op(&mut self, node: Node, op: impl Into<OpType>) -> OpType {
355 panic_invalid_node(self, node);
356 std::mem::replace(self.optype_mut(node), op.into())
357 }
358
359 fn optype_mut(&mut self, node: Node) -> &mut OpType {
360 panic_invalid_node(self, node);
361 let node = node.into_portgraph();
362 self.op_types.get_mut(node)
363 }
364
365 fn node_metadata_map_mut(&mut self, node: Self::Node) -> &mut NodeMetadataMap {
366 panic_invalid_node(self, node);
367 self.metadata
368 .get_mut(node.into_portgraph())
369 .get_or_insert_with(Default::default)
370 }
371
372 fn extensions_mut(&mut self) -> &mut ExtensionRegistry {
373 &mut self.extensions
374 }
375}
376
377#[cfg(test)]
378mod test {
379 use crate::{
380 Direction, HugrView as _,
381 builder::{Container, DFGBuilder, Dataflow, DataflowHugr},
382 extension::prelude::Noop,
383 hugr::internal::HugrMutInternals as _,
384 ops::handle::NodeHandle,
385 types::{Signature, Type},
386 };
387
388 #[test]
389 fn insert_ports() {
390 let (nop, mut hugr) = {
391 let mut builder = DFGBuilder::new(Signature::new_endo(Type::UNIT)).unwrap();
392 let [nop_in] = builder.input_wires_arr();
393 let nop = builder
394 .add_dataflow_op(Noop::new(Type::UNIT), [nop_in])
395 .unwrap();
396 builder.add_other_wire(nop.node(), builder.output().node());
397 let [nop_out] = nop.outputs_arr();
398 (
399 nop.node(),
400 builder.finish_hugr_with_outputs([nop_out]).unwrap(),
401 )
402 };
403 let [i, o] = hugr.get_io(hugr.entrypoint()).unwrap();
404 assert_eq!(0..2, hugr.insert_ports(nop, Direction::Incoming, 0, 2));
405 assert_eq!(1..3, hugr.insert_ports(nop, Direction::Outgoing, 1, 2));
406
407 assert_eq!(hugr.single_linked_input(i, 0), Some((nop, 2.into())));
408 assert_eq!(hugr.single_linked_output(o, 0), Some((nop, 0.into())));
409 assert_eq!(hugr.single_linked_output(o, 1), Some((nop, 3.into())));
410 }
411}