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>
27 + Clone
28 + 'p
29 where
30 Self: 'p;
31
32 type Node: Copy + Ord + std::fmt::Debug + std::fmt::Display + std::hash::Hash;
34
35 type RegionPortgraphNodes: PortgraphNodeMap<Self::Node>;
40
41 fn node_metadata_map(&self, node: Self::Node) -> &NodeMetadataMap;
47}
48
49pub trait PortgraphNodeMap<N>: Clone + Sized + std::fmt::Debug {
54 fn to_portgraph(&self, node: N) -> portgraph::NodeIndex;
59
60 #[allow(clippy::wrong_self_convention)]
65 fn from_portgraph(&self, node: portgraph::NodeIndex) -> N;
66}
67
68#[derive(
70 Copy, Clone, Debug, Default, Eq, PartialEq, Hash, PartialOrd, Ord, derive_more::Display,
71)]
72pub struct DefaultPGNodeMap;
73
74impl PortgraphNodeMap<Node> for DefaultPGNodeMap {
75 #[inline]
76 fn to_portgraph(&self, node: Node) -> portgraph::NodeIndex {
77 node.into_portgraph()
78 }
79
80 #[inline]
81 fn from_portgraph(&self, node: portgraph::NodeIndex) -> Node {
82 node.into()
83 }
84}
85
86impl<N: HugrNode> PortgraphNodeMap<N> for std::collections::HashMap<N, Node> {
87 #[inline]
88 fn to_portgraph(&self, node: N) -> portgraph::NodeIndex {
89 self[&node].into_portgraph()
90 }
91
92 #[inline]
93 fn from_portgraph(&self, node: portgraph::NodeIndex) -> N {
94 let node = node.into();
95 self.iter()
96 .find_map(|(&k, &v)| (v == node).then_some(k))
97 .expect("Portgraph node not found in map")
98 }
99}
100
101impl HugrInternals for Hugr {
102 type RegionPortgraph<'p>
103 = &'p MultiPortGraph<u32, u32, u32>
104 where
105 Self: 'p;
106
107 type Node = Node;
108
109 type RegionPortgraphNodes = DefaultPGNodeMap;
110
111 #[inline]
112 fn node_metadata_map(&self, node: Self::Node) -> &NodeMetadataMap {
113 static EMPTY: OnceLock<NodeMetadataMap> = OnceLock::new();
114 panic_invalid_node(self, node);
115 let map = self.metadata.get(node.into_portgraph()).as_ref();
116 map.unwrap_or(EMPTY.get_or_init(Default::default))
117 }
118}
119
120pub trait HugrMutInternals: HugrView {
125 fn set_module_root(&mut self, root: Self::Node);
138
139 fn set_num_ports(&mut self, node: Self::Node, incoming: usize, outgoing: usize);
145
146 fn add_ports(&mut self, node: Self::Node, direction: Direction, amount: isize) -> Range<usize>;
158
159 fn insert_ports(
169 &mut self,
170 node: Self::Node,
171 direction: Direction,
172 index: usize,
173 amount: usize,
174 ) -> Range<usize>;
175
176 fn set_parent(&mut self, node: Self::Node, parent: Self::Node);
184
185 fn move_after_sibling(&mut self, node: Self::Node, after: Self::Node);
196
197 fn move_before_sibling(&mut self, node: Self::Node, before: Self::Node);
207
208 fn replace_op(&mut self, node: Self::Node, op: impl Into<OpType>) -> OpType;
221
222 fn optype_mut(&mut self, node: Self::Node) -> &mut OpType;
235
236 fn node_metadata_map_mut(&mut self, node: Self::Node) -> &mut NodeMetadataMap;
242
243 fn extensions_mut(&mut self) -> &mut ExtensionRegistry;
248}
249
250impl HugrMutInternals for Hugr {
252 fn set_module_root(&mut self, root: Node) {
253 panic_invalid_node(self, root.node());
254 let root = root.into_portgraph();
255 self.hierarchy.detach(root);
256 self.module_root = root;
257 }
258
259 #[inline]
260 fn set_num_ports(&mut self, node: Node, incoming: usize, outgoing: usize) {
261 panic_invalid_node(self, node);
262 self.graph
263 .set_num_ports(node.into_portgraph(), incoming, outgoing, |_, _| {});
264 }
265
266 fn add_ports(&mut self, node: Node, direction: Direction, amount: isize) -> Range<usize> {
267 panic_invalid_node(self, node);
268 let mut incoming = self.graph.num_inputs(node.into_portgraph());
269 let mut outgoing = self.graph.num_outputs(node.into_portgraph());
270 let increment = |num: &mut usize| {
271 let new = num.saturating_add_signed(amount);
272 let range = *num..new;
273 *num = new;
274 range
275 };
276 let range = match direction {
277 Direction::Incoming => increment(&mut incoming),
278 Direction::Outgoing => increment(&mut outgoing),
279 };
280 self.graph
281 .set_num_ports(node.into_portgraph(), incoming, outgoing, |_, _| {});
282 range
283 }
284
285 fn insert_ports(
286 &mut self,
287 node: Node,
288 direction: Direction,
289 index: usize,
290 amount: usize,
291 ) -> Range<usize> {
292 panic_invalid_node(self, node);
293 let old_num_ports = self.graph.num_ports(node.into_portgraph(), direction);
294
295 self.add_ports(node, direction, amount as isize);
296
297 for swap_from_port in (index..old_num_ports).rev() {
298 let swap_to_port = swap_from_port + amount;
299 let [from_port_index, to_port_index] = [swap_from_port, swap_to_port].map(|p| {
300 self.graph
301 .port_index(node.into_portgraph(), PortOffset::new(direction, p))
302 .unwrap()
303 });
304 let linked_ports = self
305 .graph
306 .port_links(from_port_index)
307 .map(|(_, to_subport)| to_subport.port())
308 .collect_vec();
309 self.graph.unlink_port(from_port_index);
310 for linked_port_index in linked_ports {
311 let _ = self
312 .graph
313 .link_ports(to_port_index, linked_port_index)
314 .expect("Ports exist");
315 }
316 }
317 index..index + amount
318 }
319
320 fn set_parent(&mut self, node: Node, parent: Node) {
321 panic_invalid_node(self, parent);
322 panic_invalid_node(self, node);
323 self.hierarchy.detach(node.into_portgraph());
324 self.hierarchy
325 .push_child(node.into_portgraph(), parent.into_portgraph())
326 .expect("Inserting a newly-created node into the hierarchy should never fail.");
327 }
328
329 fn move_after_sibling(&mut self, node: Node, after: Node) {
330 panic_invalid_non_entrypoint(self, node);
331 panic_invalid_non_entrypoint(self, after);
332 self.hierarchy.detach(node.into_portgraph());
333 self.hierarchy
334 .insert_after(node.into_portgraph(), after.into_portgraph())
335 .expect("Inserting a newly-created node into the hierarchy should never fail.");
336 }
337
338 fn move_before_sibling(&mut self, node: Node, before: Node) {
339 panic_invalid_non_entrypoint(self, node);
340 panic_invalid_non_entrypoint(self, before);
341 self.hierarchy.detach(node.into_portgraph());
342 self.hierarchy
343 .insert_before(node.into_portgraph(), before.into_portgraph())
344 .expect("Inserting a newly-created node into the hierarchy should never fail.");
345 }
346
347 fn replace_op(&mut self, node: Node, op: impl Into<OpType>) -> OpType {
348 panic_invalid_node(self, node);
349 std::mem::replace(self.optype_mut(node), op.into())
350 }
351
352 fn optype_mut(&mut self, node: Node) -> &mut OpType {
353 panic_invalid_node(self, node);
354 let node = node.into_portgraph();
355 self.op_types.get_mut(node)
356 }
357
358 fn node_metadata_map_mut(&mut self, node: Self::Node) -> &mut NodeMetadataMap {
359 panic_invalid_node(self, node);
360 self.metadata
361 .get_mut(node.into_portgraph())
362 .get_or_insert_with(Default::default)
363 }
364
365 fn extensions_mut(&mut self) -> &mut ExtensionRegistry {
366 &mut self.extensions
367 }
368}
369
370#[cfg(test)]
371mod test {
372 use crate::{
373 Direction, HugrView as _,
374 builder::{Container, DFGBuilder, Dataflow, DataflowHugr},
375 extension::prelude::Noop,
376 hugr::internal::HugrMutInternals as _,
377 ops::handle::NodeHandle,
378 types::{Signature, Type},
379 };
380
381 #[test]
382 fn insert_ports() {
383 let (nop, mut hugr) = {
384 let mut builder = DFGBuilder::new(Signature::new_endo([Type::UNIT])).unwrap();
385 let [nop_in] = builder.input_wires_arr();
386 let nop = builder
387 .add_dataflow_op(Noop::new(Type::UNIT), [nop_in])
388 .unwrap();
389 builder.add_other_wire(nop.node(), builder.output().node());
390 let [nop_out] = nop.outputs_arr();
391 (
392 nop.node(),
393 builder.finish_hugr_with_outputs([nop_out]).unwrap(),
394 )
395 };
396 let [i, o] = hugr.get_io(hugr.entrypoint()).unwrap();
397 assert_eq!(0..2, hugr.insert_ports(nop, Direction::Incoming, 0, 2));
398 assert_eq!(1..3, hugr.insert_ports(nop, Direction::Outgoing, 1, 2));
399
400 assert_eq!(hugr.single_linked_input(i, 0), Some((nop, 2.into())));
401 assert_eq!(hugr.single_linked_output(o, 0), Some((nop, 0.into())));
402 assert_eq!(hugr.single_linked_output(o, 1), Some((nop, 3.into())));
403 }
404}