1use std::ops::Range;
4use std::sync::OnceLock;
5
6use itertools::Itertools;
7use portgraph::{LinkMut, LinkView, MultiPortGraph, PortMut, PortOffset, PortView};
8
9use crate::core::HugrNode;
10use crate::extension::ExtensionRegistry;
11use crate::{Direction, Hugr, Node};
12
13use super::HugrView;
14use super::views::{panic_invalid_node, panic_invalid_non_entrypoint};
15use super::{NodeMetadataMap, OpType};
16use crate::ops::handle::NodeHandle;
17
18pub trait HugrInternals {
23 type RegionPortgraph<'p>: LinkView<LinkEndpoint: Eq, NodeIndexBase = u32, PortIndexBase = u32, PortOffsetBase = u32>
25 + Clone
26 + 'p
27 where
28 Self: 'p;
29
30 type Node: Copy + Ord + std::fmt::Debug + std::fmt::Display + std::hash::Hash;
32
33 type RegionPortgraphNodes: PortgraphNodeMap<Self::Node>;
36
37 fn region_portgraph(
47 &self,
48 parent: Self::Node,
49 ) -> (
50 portgraph::view::FlatRegion<'_, Self::RegionPortgraph<'_>>,
51 Self::RegionPortgraphNodes,
52 );
53
54 fn node_metadata_map(&self, node: Self::Node) -> &NodeMetadataMap;
60}
61
62pub trait PortgraphNodeMap<N>: Clone + Sized + std::fmt::Debug {
65 fn to_portgraph(&self, node: N) -> portgraph::NodeIndex;
70
71 #[allow(clippy::wrong_self_convention)]
76 fn from_portgraph(&self, node: portgraph::NodeIndex) -> N;
77}
78
79#[derive(
81 Copy, Clone, Debug, Default, Eq, PartialEq, Hash, PartialOrd, Ord, derive_more::Display,
82)]
83pub struct DefaultPGNodeMap;
84
85impl PortgraphNodeMap<Node> for DefaultPGNodeMap {
86 #[inline]
87 fn to_portgraph(&self, node: Node) -> portgraph::NodeIndex {
88 node.into_portgraph()
89 }
90
91 #[inline]
92 fn from_portgraph(&self, node: portgraph::NodeIndex) -> Node {
93 node.into()
94 }
95}
96
97impl<N: HugrNode> PortgraphNodeMap<N> for std::collections::HashMap<N, Node> {
98 #[inline]
99 fn to_portgraph(&self, node: N) -> portgraph::NodeIndex {
100 self[&node].into_portgraph()
101 }
102
103 #[inline]
104 fn from_portgraph(&self, node: portgraph::NodeIndex) -> N {
105 let node = node.into();
106 self.iter()
107 .find_map(|(&k, &v)| (v == node).then_some(k))
108 .expect("Portgraph node not found in map")
109 }
110}
111
112impl HugrInternals for Hugr {
113 type RegionPortgraph<'p>
114 = &'p MultiPortGraph<u32, u32, u32>
115 where
116 Self: 'p;
117
118 type Node = Node;
119
120 type RegionPortgraphNodes = DefaultPGNodeMap;
121
122 #[inline]
123 fn region_portgraph(
124 &self,
125 parent: Self::Node,
126 ) -> (
127 portgraph::view::FlatRegion<'_, Self::RegionPortgraph<'_>>,
128 Self::RegionPortgraphNodes,
129 ) {
130 let root = parent.into_portgraph();
131 let region =
132 portgraph::view::FlatRegion::new_without_root(&self.graph, &self.hierarchy, root);
133 (region, DefaultPGNodeMap)
134 }
135
136 #[inline]
137 fn node_metadata_map(&self, node: Self::Node) -> &NodeMetadataMap {
138 static EMPTY: OnceLock<NodeMetadataMap> = OnceLock::new();
139 panic_invalid_node(self, node);
140 let map = self.metadata.get(node.into_portgraph()).as_ref();
141 map.unwrap_or(EMPTY.get_or_init(Default::default))
142 }
143}
144
145pub trait HugrMutInternals: HugrView {
150 fn set_module_root(&mut self, root: Self::Node);
163
164 fn set_num_ports(&mut self, node: Self::Node, incoming: usize, outgoing: usize);
170
171 fn add_ports(&mut self, node: Self::Node, direction: Direction, amount: isize) -> Range<usize>;
183
184 fn insert_ports(
194 &mut self,
195 node: Self::Node,
196 direction: Direction,
197 index: usize,
198 amount: usize,
199 ) -> Range<usize>;
200
201 fn set_parent(&mut self, node: Self::Node, parent: Self::Node);
209
210 fn move_after_sibling(&mut self, node: Self::Node, after: Self::Node);
221
222 fn move_before_sibling(&mut self, node: Self::Node, before: Self::Node);
232
233 fn replace_op(&mut self, node: Self::Node, op: impl Into<OpType>) -> OpType;
246
247 fn optype_mut(&mut self, node: Self::Node) -> &mut OpType;
260
261 fn node_metadata_map_mut(&mut self, node: Self::Node) -> &mut NodeMetadataMap;
267
268 fn extensions_mut(&mut self) -> &mut ExtensionRegistry;
273}
274
275impl HugrMutInternals for Hugr {
277 fn set_module_root(&mut self, root: Node) {
278 panic_invalid_node(self, root.node());
279 let root = root.into_portgraph();
280 self.hierarchy.detach(root);
281 self.module_root = root;
282 }
283
284 #[inline]
285 fn set_num_ports(&mut self, node: Node, incoming: usize, outgoing: usize) {
286 panic_invalid_node(self, node);
287 self.graph
288 .set_num_ports(node.into_portgraph(), incoming, outgoing, |_, _| {});
289 }
290
291 fn add_ports(&mut self, node: Node, direction: Direction, amount: isize) -> Range<usize> {
292 panic_invalid_node(self, node);
293 let mut incoming = self.graph.num_inputs(node.into_portgraph());
294 let mut outgoing = self.graph.num_outputs(node.into_portgraph());
295 let increment = |num: &mut usize| {
296 let new = num.saturating_add_signed(amount);
297 let range = *num..new;
298 *num = new;
299 range
300 };
301 let range = match direction {
302 Direction::Incoming => increment(&mut incoming),
303 Direction::Outgoing => increment(&mut outgoing),
304 };
305 self.graph
306 .set_num_ports(node.into_portgraph(), incoming, outgoing, |_, _| {});
307 range
308 }
309
310 fn insert_ports(
311 &mut self,
312 node: Node,
313 direction: Direction,
314 index: usize,
315 amount: usize,
316 ) -> Range<usize> {
317 panic_invalid_node(self, node);
318 let old_num_ports = self.graph.num_ports(node.into_portgraph(), direction);
319
320 self.add_ports(node, direction, amount as isize);
321
322 for swap_from_port in (index..old_num_ports).rev() {
323 let swap_to_port = swap_from_port + amount;
324 let [from_port_index, to_port_index] = [swap_from_port, swap_to_port].map(|p| {
325 self.graph
326 .port_index(node.into_portgraph(), PortOffset::new(direction, p))
327 .unwrap()
328 });
329 let linked_ports = self
330 .graph
331 .port_links(from_port_index)
332 .map(|(_, to_subport)| to_subport.port())
333 .collect_vec();
334 self.graph.unlink_port(from_port_index);
335 for linked_port_index in linked_ports {
336 let _ = self
337 .graph
338 .link_ports(to_port_index, linked_port_index)
339 .expect("Ports exist");
340 }
341 }
342 index..index + amount
343 }
344
345 fn set_parent(&mut self, node: Node, parent: Node) {
346 panic_invalid_node(self, parent);
347 panic_invalid_node(self, node);
348 self.hierarchy.detach(node.into_portgraph());
349 self.hierarchy
350 .push_child(node.into_portgraph(), parent.into_portgraph())
351 .expect("Inserting a newly-created node into the hierarchy should never fail.");
352 }
353
354 fn move_after_sibling(&mut self, node: Node, after: Node) {
355 panic_invalid_non_entrypoint(self, node);
356 panic_invalid_non_entrypoint(self, after);
357 self.hierarchy.detach(node.into_portgraph());
358 self.hierarchy
359 .insert_after(node.into_portgraph(), after.into_portgraph())
360 .expect("Inserting a newly-created node into the hierarchy should never fail.");
361 }
362
363 fn move_before_sibling(&mut self, node: Node, before: Node) {
364 panic_invalid_non_entrypoint(self, node);
365 panic_invalid_non_entrypoint(self, before);
366 self.hierarchy.detach(node.into_portgraph());
367 self.hierarchy
368 .insert_before(node.into_portgraph(), before.into_portgraph())
369 .expect("Inserting a newly-created node into the hierarchy should never fail.");
370 }
371
372 fn replace_op(&mut self, node: Node, op: impl Into<OpType>) -> OpType {
373 panic_invalid_node(self, node);
374 std::mem::replace(self.optype_mut(node), op.into())
375 }
376
377 fn optype_mut(&mut self, node: Node) -> &mut OpType {
378 panic_invalid_node(self, node);
379 let node = node.into_portgraph();
380 self.op_types.get_mut(node)
381 }
382
383 fn node_metadata_map_mut(&mut self, node: Self::Node) -> &mut NodeMetadataMap {
384 panic_invalid_node(self, node);
385 self.metadata
386 .get_mut(node.into_portgraph())
387 .get_or_insert_with(Default::default)
388 }
389
390 fn extensions_mut(&mut self) -> &mut ExtensionRegistry {
391 &mut self.extensions
392 }
393}
394
395impl Hugr {
396 #[inline]
399 pub fn into_region_portgraph(
400 self,
401 parent: Node,
402 ) -> portgraph::view::FlatRegion<'static, MultiPortGraph<u32, u32, u32>> {
403 let root = parent.into_portgraph();
404 let Self {
405 graph, hierarchy, ..
406 } = self;
407 portgraph::view::FlatRegion::new_without_root(graph, hierarchy, root)
408 }
409}
410
411#[cfg(test)]
412mod test {
413 use crate::{
414 Direction, HugrView as _,
415 builder::{Container, DFGBuilder, Dataflow, DataflowHugr},
416 extension::prelude::Noop,
417 hugr::internal::HugrMutInternals as _,
418 ops::handle::NodeHandle,
419 types::{Signature, Type},
420 };
421
422 #[test]
423 fn insert_ports() {
424 let (nop, mut hugr) = {
425 let mut builder = DFGBuilder::new(Signature::new_endo([Type::UNIT])).unwrap();
426 let [nop_in] = builder.input_wires_arr();
427 let nop = builder
428 .add_dataflow_op(Noop::new(Type::UNIT), [nop_in])
429 .unwrap();
430 builder.add_other_wire(nop.node(), builder.output().node());
431 let [nop_out] = nop.outputs_arr();
432 (
433 nop.node(),
434 builder.finish_hugr_with_outputs([nop_out]).unwrap(),
435 )
436 };
437 let [i, o] = hugr.get_io(hugr.entrypoint()).unwrap();
438 assert_eq!(0..2, hugr.insert_ports(nop, Direction::Incoming, 0, 2));
439 assert_eq!(1..3, hugr.insert_ports(nop, Direction::Outgoing, 1, 2));
440
441 assert_eq!(hugr.single_linked_input(i, 0), Some((nop, 2.into())));
442 assert_eq!(hugr.single_linked_output(o, 0), Some((nop, 0.into())));
443 assert_eq!(hugr.single_linked_output(o, 1), Some((nop, 3.into())));
444 }
445}