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