1use std::borrow::Cow;
4use std::ops::Range;
5use std::rc::Rc;
6use std::sync::Arc;
7
8use delegate::delegate;
9use itertools::Itertools;
10use portgraph::{LinkMut, LinkView, MultiPortGraph, PortMut, PortOffset, PortView};
11
12use crate::ops::handle::NodeHandle;
13use crate::ops::OpTrait;
14use crate::{Direction, Hugr, Node};
15
16use super::hugrmut::{panic_invalid_node, panic_invalid_non_root};
17use super::{HugrError, OpType, RootTagged};
18
19pub trait HugrInternals {
24 type Portgraph<'p>: LinkView + Clone + 'p
26 where
27 Self: 'p;
28
29 type Node: Copy + Ord + std::fmt::Debug + std::fmt::Display + std::hash::Hash;
31
32 fn portgraph(&self) -> Self::Portgraph<'_>;
34
35 fn base_hugr(&self) -> &Hugr;
37
38 fn root_node(&self) -> Self::Node;
40
41 fn get_pg_index(&self, node: Self::Node) -> portgraph::NodeIndex;
43
44 fn get_node(&self, index: portgraph::NodeIndex) -> Self::Node;
46}
47
48impl HugrInternals for Hugr {
49 type Portgraph<'p>
50 = &'p MultiPortGraph
51 where
52 Self: 'p;
53
54 type Node = Node;
55
56 #[inline]
57 fn portgraph(&self) -> Self::Portgraph<'_> {
58 &self.graph
59 }
60
61 #[inline]
62 fn base_hugr(&self) -> &Hugr {
63 self
64 }
65
66 #[inline]
67 fn root_node(&self) -> Self::Node {
68 self.root.into()
69 }
70
71 fn get_pg_index(&self, node: Self::Node) -> portgraph::NodeIndex {
72 node.pg_index()
73 }
74
75 fn get_node(&self, index: portgraph::NodeIndex) -> Self::Node {
76 index.into()
77 }
78}
79
80impl<T: HugrInternals> HugrInternals for &T {
81 type Portgraph<'p>
82 = T::Portgraph<'p>
83 where
84 Self: 'p;
85 type Node = T::Node;
86
87 delegate! {
88 to (**self) {
89 fn portgraph(&self) -> Self::Portgraph<'_>;
90 fn base_hugr(&self) -> &Hugr;
91 fn root_node(&self) -> Self::Node;
92 fn get_pg_index(&self, node: Self::Node) -> portgraph::NodeIndex;
93 fn get_node(&self, index: portgraph::NodeIndex) -> Self::Node;
94 }
95 }
96}
97
98impl<T: HugrInternals> HugrInternals for &mut T {
99 type Portgraph<'p>
100 = T::Portgraph<'p>
101 where
102 Self: 'p;
103 type Node = T::Node;
104
105 delegate! {
106 to (**self) {
107 fn portgraph(&self) -> Self::Portgraph<'_>;
108 fn base_hugr(&self) -> &Hugr;
109 fn root_node(&self) -> Self::Node;
110 fn get_pg_index(&self, node: Self::Node) -> portgraph::NodeIndex;
111 fn get_node(&self, index: portgraph::NodeIndex) -> Self::Node;
112 }
113 }
114}
115
116impl<T: HugrInternals> HugrInternals for Rc<T> {
117 type Portgraph<'p>
118 = T::Portgraph<'p>
119 where
120 Self: 'p;
121 type Node = T::Node;
122
123 delegate! {
124 to (**self) {
125 fn portgraph(&self) -> Self::Portgraph<'_>;
126 fn base_hugr(&self) -> &Hugr;
127 fn root_node(&self) -> Self::Node;
128 fn get_pg_index(&self, node: Self::Node) -> portgraph::NodeIndex;
129 fn get_node(&self, index: portgraph::NodeIndex) -> Self::Node;
130 }
131 }
132}
133
134impl<T: HugrInternals> HugrInternals for Arc<T> {
135 type Portgraph<'p>
136 = T::Portgraph<'p>
137 where
138 Self: 'p;
139 type Node = T::Node;
140
141 delegate! {
142 to (**self) {
143 fn portgraph(&self) -> Self::Portgraph<'_>;
144 fn base_hugr(&self) -> &Hugr;
145 fn root_node(&self) -> Self::Node;
146 fn get_pg_index(&self, node: Self::Node) -> portgraph::NodeIndex;
147 fn get_node(&self, index: portgraph::NodeIndex) -> Self::Node;
148 }
149 }
150}
151
152impl<T: HugrInternals> HugrInternals for Box<T> {
153 type Portgraph<'p>
154 = T::Portgraph<'p>
155 where
156 Self: 'p;
157 type Node = T::Node;
158
159 delegate! {
160 to (**self) {
161 fn portgraph(&self) -> Self::Portgraph<'_>;
162 fn base_hugr(&self) -> &Hugr;
163 fn root_node(&self) -> Self::Node;
164 fn get_pg_index(&self, node: Self::Node) -> portgraph::NodeIndex;
165 fn get_node(&self, index: portgraph::NodeIndex) -> Self::Node;
166 }
167 }
168}
169
170impl<T: HugrInternals + ToOwned> HugrInternals for Cow<'_, T> {
171 type Portgraph<'p>
172 = T::Portgraph<'p>
173 where
174 Self: 'p;
175 type Node = T::Node;
176
177 delegate! {
178 to self.as_ref() {
179 fn portgraph(&self) -> Self::Portgraph<'_>;
180 fn base_hugr(&self) -> &Hugr;
181 fn root_node(&self) -> Self::Node;
182 fn get_pg_index(&self, node: Self::Node) -> portgraph::NodeIndex;
183 fn get_node(&self, index: portgraph::NodeIndex) -> Self::Node;
184 }
185 }
186}
187pub trait HugrMutInternals: RootTagged<Node = Node> {
192 fn hugr_mut(&mut self) -> &mut Hugr;
194
195 fn set_num_ports(&mut self, node: Node, incoming: usize, outgoing: usize) {
201 panic_invalid_node(self, node);
202 self.hugr_mut().set_num_ports(node, incoming, outgoing)
203 }
204
205 fn add_ports(&mut self, node: Node, direction: Direction, amount: isize) -> Range<usize> {
217 panic_invalid_node(self, node);
218 self.hugr_mut().add_ports(node, direction, amount)
219 }
220
221 fn insert_ports(
231 &mut self,
232 node: Node,
233 direction: Direction,
234 index: usize,
235 amount: usize,
236 ) -> Range<usize> {
237 panic_invalid_node(self, node);
238 self.hugr_mut().insert_ports(node, direction, index, amount)
239 }
240
241 fn set_parent(&mut self, node: Node, parent: Node) {
249 panic_invalid_node(self, parent);
250 panic_invalid_non_root(self, node);
251 self.hugr_mut().set_parent(node, parent);
252 }
253
254 fn move_after_sibling(&mut self, node: Node, after: Node) {
265 panic_invalid_non_root(self, node);
266 panic_invalid_non_root(self, after);
267 self.hugr_mut().move_after_sibling(node, after);
268 }
269
270 fn move_before_sibling(&mut self, node: Node, before: Node) {
280 panic_invalid_non_root(self, node);
281 panic_invalid_non_root(self, before);
282 self.hugr_mut().move_before_sibling(node, before)
283 }
284
285 fn replace_op(&mut self, node: Node, op: impl Into<OpType>) -> Result<OpType, HugrError> {
302 panic_invalid_node(self, node);
303 let op = op.into();
304 if node == self.root() && !Self::RootHandle::TAG.is_superset(op.tag()) {
305 return Err(HugrError::InvalidTag {
306 required: Self::RootHandle::TAG,
307 actual: op.tag(),
308 });
309 }
310 self.hugr_mut().replace_op(node, op)
311 }
312}
313
314impl<T: RootTagged<RootHandle = Node, Node = Node> + AsMut<Hugr>> HugrMutInternals for T {
316 fn hugr_mut(&mut self) -> &mut Hugr {
317 self.as_mut()
318 }
319
320 #[inline]
321 fn set_num_ports(&mut self, node: Node, incoming: usize, outgoing: usize) {
322 self.hugr_mut()
323 .graph
324 .set_num_ports(node.pg_index(), incoming, outgoing, |_, _| {})
325 }
326
327 fn insert_ports(
328 &mut self,
329 node: Node,
330 direction: Direction,
331 index: usize,
332 amount: usize,
333 ) -> Range<usize> {
334 let old_num_ports = self.base_hugr().graph.num_ports(node.pg_index(), direction);
335
336 self.add_ports(node, direction, amount as isize);
337
338 for swap_from_port in (index..old_num_ports).rev() {
339 let swap_to_port = swap_from_port + amount;
340 let [from_port_index, to_port_index] = [swap_from_port, swap_to_port].map(|p| {
341 self.base_hugr()
342 .graph
343 .port_index(node.pg_index(), PortOffset::new(direction, p))
344 .unwrap()
345 });
346 let linked_ports = self
347 .base_hugr()
348 .graph
349 .port_links(from_port_index)
350 .map(|(_, to_subport)| to_subport.port())
351 .collect_vec();
352 self.hugr_mut().graph.unlink_port(from_port_index);
353 for linked_port_index in linked_ports {
354 let _ = self
355 .hugr_mut()
356 .graph
357 .link_ports(to_port_index, linked_port_index)
358 .expect("Ports exist");
359 }
360 }
361 index..index + amount
362 }
363
364 fn add_ports(&mut self, node: Node, direction: Direction, amount: isize) -> Range<usize> {
365 let mut incoming = self.hugr_mut().graph.num_inputs(node.pg_index());
366 let mut outgoing = self.hugr_mut().graph.num_outputs(node.pg_index());
367 let increment = |num: &mut usize| {
368 let new = num.saturating_add_signed(amount);
369 let range = *num..new;
370 *num = new;
371 range
372 };
373 let range = match direction {
374 Direction::Incoming => increment(&mut incoming),
375 Direction::Outgoing => increment(&mut outgoing),
376 };
377 self.hugr_mut()
378 .graph
379 .set_num_ports(node.pg_index(), incoming, outgoing, |_, _| {});
380 range
381 }
382
383 fn set_parent(&mut self, node: Node, parent: Node) {
384 self.hugr_mut().hierarchy.detach(node.pg_index());
385 self.hugr_mut()
386 .hierarchy
387 .push_child(node.pg_index(), parent.pg_index())
388 .expect("Inserting a newly-created node into the hierarchy should never fail.");
389 }
390
391 fn move_after_sibling(&mut self, node: Node, after: Node) {
392 self.hugr_mut().hierarchy.detach(node.pg_index());
393 self.hugr_mut()
394 .hierarchy
395 .insert_after(node.pg_index(), after.pg_index())
396 .expect("Inserting a newly-created node into the hierarchy should never fail.");
397 }
398
399 fn move_before_sibling(&mut self, node: Node, before: Node) {
400 self.hugr_mut().hierarchy.detach(node.pg_index());
401 self.hugr_mut()
402 .hierarchy
403 .insert_before(node.pg_index(), before.pg_index())
404 .expect("Inserting a newly-created node into the hierarchy should never fail.");
405 }
406
407 fn replace_op(&mut self, node: Node, op: impl Into<OpType>) -> Result<OpType, HugrError> {
408 let cur = self.hugr_mut().op_types.get_mut(node.pg_index());
410 Ok(std::mem::replace(cur, op.into()))
411 }
412}
413
414#[cfg(test)]
415mod test {
416 use crate::{
417 builder::{Container, DFGBuilder, Dataflow, DataflowHugr},
418 extension::prelude::Noop,
419 hugr::internal::HugrMutInternals as _,
420 ops::handle::NodeHandle,
421 types::{Signature, Type},
422 Direction, HugrView as _,
423 };
424
425 #[test]
426 fn insert_ports() {
427 let (nop, mut hugr) = {
428 let mut builder =
429 DFGBuilder::new(Signature::new_endo(Type::UNIT).with_prelude()).unwrap();
430 let [nop_in] = builder.input_wires_arr();
431 let nop = builder
432 .add_dataflow_op(Noop::new(Type::UNIT), [nop_in])
433 .unwrap();
434 builder.add_other_wire(nop.node(), builder.output().node());
435 let [nop_out] = nop.outputs_arr();
436 (
437 nop.node(),
438 builder.finish_hugr_with_outputs([nop_out]).unwrap(),
439 )
440 };
441 let [i, o] = hugr.get_io(hugr.root()).unwrap();
442 assert_eq!(0..2, hugr.insert_ports(nop, Direction::Incoming, 0, 2));
443 assert_eq!(1..3, hugr.insert_ports(nop, Direction::Outgoing, 1, 2));
444
445 assert_eq!(hugr.single_linked_input(i, 0), Some((nop, 2.into())));
446 assert_eq!(hugr.single_linked_output(o, 0), Some((nop, 0.into())));
447 assert_eq!(hugr.single_linked_output(o, 1), Some((nop, 3.into())));
448 }
449}