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 fn portgraph(&self) -> Self::Portgraph<'_>;
31
32 fn base_hugr(&self) -> &Hugr;
34
35 fn root_node(&self) -> Node;
37}
38
39impl HugrInternals for Hugr {
40 type Portgraph<'p>
41 = &'p MultiPortGraph
42 where
43 Self: 'p;
44
45 #[inline]
46 fn portgraph(&self) -> Self::Portgraph<'_> {
47 &self.graph
48 }
49
50 #[inline]
51 fn base_hugr(&self) -> &Hugr {
52 self
53 }
54
55 #[inline]
56 fn root_node(&self) -> Node {
57 self.root.into()
58 }
59}
60
61impl<T: HugrInternals> HugrInternals for &T {
62 type Portgraph<'p>
63 = T::Portgraph<'p>
64 where
65 Self: 'p;
66 delegate! {
67 to (**self) {
68 fn portgraph(&self) -> Self::Portgraph<'_>;
69 fn base_hugr(&self) -> &Hugr;
70 fn root_node(&self) -> Node;
71 }
72 }
73}
74
75impl<T: HugrInternals> HugrInternals for &mut T {
76 type Portgraph<'p>
77 = T::Portgraph<'p>
78 where
79 Self: 'p;
80 delegate! {
81 to (**self) {
82 fn portgraph(&self) -> Self::Portgraph<'_>;
83 fn base_hugr(&self) -> &Hugr;
84 fn root_node(&self) -> Node;
85 }
86 }
87}
88
89impl<T: HugrInternals> HugrInternals for Rc<T> {
90 type Portgraph<'p>
91 = T::Portgraph<'p>
92 where
93 Self: 'p;
94 delegate! {
95 to (**self) {
96 fn portgraph(&self) -> Self::Portgraph<'_>;
97 fn base_hugr(&self) -> &Hugr;
98 fn root_node(&self) -> Node;
99 }
100 }
101}
102
103impl<T: HugrInternals> HugrInternals for Arc<T> {
104 type Portgraph<'p>
105 = T::Portgraph<'p>
106 where
107 Self: 'p;
108 delegate! {
109 to (**self) {
110 fn portgraph(&self) -> Self::Portgraph<'_>;
111 fn base_hugr(&self) -> &Hugr;
112 fn root_node(&self) -> Node;
113 }
114 }
115}
116
117impl<T: HugrInternals> HugrInternals for Box<T> {
118 type Portgraph<'p>
119 = T::Portgraph<'p>
120 where
121 Self: 'p;
122 delegate! {
123 to (**self) {
124 fn portgraph(&self) -> Self::Portgraph<'_>;
125 fn base_hugr(&self) -> &Hugr;
126 fn root_node(&self) -> Node;
127 }
128 }
129}
130
131impl<T: HugrInternals + ToOwned> HugrInternals for Cow<'_, T> {
132 type Portgraph<'p>
133 = T::Portgraph<'p>
134 where
135 Self: 'p;
136 delegate! {
137 to self.as_ref() {
138 fn portgraph(&self) -> Self::Portgraph<'_>;
139 fn base_hugr(&self) -> &Hugr;
140 fn root_node(&self) -> Node;
141 }
142 }
143}
144pub trait HugrMutInternals: RootTagged {
149 fn hugr_mut(&mut self) -> &mut Hugr;
151
152 fn set_num_ports(&mut self, node: Node, incoming: usize, outgoing: usize) {
158 panic_invalid_node(self, node);
159 self.hugr_mut().set_num_ports(node, incoming, outgoing)
160 }
161
162 fn add_ports(&mut self, node: Node, direction: Direction, amount: isize) -> Range<usize> {
174 panic_invalid_node(self, node);
175 self.hugr_mut().add_ports(node, direction, amount)
176 }
177
178 fn insert_ports(
188 &mut self,
189 node: Node,
190 direction: Direction,
191 index: usize,
192 amount: usize,
193 ) -> Range<usize> {
194 panic_invalid_node(self, node);
195 self.hugr_mut().insert_ports(node, direction, index, amount)
196 }
197
198 fn set_parent(&mut self, node: Node, parent: Node) {
206 panic_invalid_node(self, parent);
207 panic_invalid_non_root(self, node);
208 self.hugr_mut().set_parent(node, parent);
209 }
210
211 fn move_after_sibling(&mut self, node: Node, after: Node) {
222 panic_invalid_non_root(self, node);
223 panic_invalid_non_root(self, after);
224 self.hugr_mut().move_after_sibling(node, after);
225 }
226
227 fn move_before_sibling(&mut self, node: Node, before: Node) {
237 panic_invalid_non_root(self, node);
238 panic_invalid_non_root(self, before);
239 self.hugr_mut().move_before_sibling(node, before)
240 }
241
242 fn replace_op(&mut self, node: Node, op: impl Into<OpType>) -> Result<OpType, HugrError> {
259 panic_invalid_node(self, node);
260 let op = op.into();
261 if node == self.root() && !Self::RootHandle::TAG.is_superset(op.tag()) {
262 return Err(HugrError::InvalidTag {
263 required: Self::RootHandle::TAG,
264 actual: op.tag(),
265 });
266 }
267 self.hugr_mut().replace_op(node, op)
268 }
269}
270
271impl<T: RootTagged<RootHandle = Node> + AsMut<Hugr>> HugrMutInternals for T {
273 fn hugr_mut(&mut self) -> &mut Hugr {
274 self.as_mut()
275 }
276
277 #[inline]
278 fn set_num_ports(&mut self, node: Node, incoming: usize, outgoing: usize) {
279 self.hugr_mut()
280 .graph
281 .set_num_ports(node.pg_index(), incoming, outgoing, |_, _| {})
282 }
283
284 fn insert_ports(
285 &mut self,
286 node: Node,
287 direction: Direction,
288 index: usize,
289 amount: usize,
290 ) -> Range<usize> {
291 let old_num_ports = self.base_hugr().graph.num_ports(node.pg_index(), direction);
292
293 self.add_ports(node, direction, amount as isize);
294
295 for swap_from_port in (index..old_num_ports).rev() {
296 let swap_to_port = swap_from_port + amount;
297 let [from_port_index, to_port_index] = [swap_from_port, swap_to_port].map(|p| {
298 self.base_hugr()
299 .graph
300 .port_index(node.pg_index(), PortOffset::new(direction, p))
301 .unwrap()
302 });
303 let linked_ports = self
304 .base_hugr()
305 .graph
306 .port_links(from_port_index)
307 .map(|(_, to_subport)| to_subport.port())
308 .collect_vec();
309 self.hugr_mut().graph.unlink_port(from_port_index);
310 for linked_port_index in linked_ports {
311 let _ = self
312 .hugr_mut()
313 .graph
314 .link_ports(to_port_index, linked_port_index)
315 .expect("Ports exist");
316 }
317 }
318 index..index + amount
319 }
320
321 fn add_ports(&mut self, node: Node, direction: Direction, amount: isize) -> Range<usize> {
322 let mut incoming = self.hugr_mut().graph.num_inputs(node.pg_index());
323 let mut outgoing = self.hugr_mut().graph.num_outputs(node.pg_index());
324 let increment = |num: &mut usize| {
325 let new = num.saturating_add_signed(amount);
326 let range = *num..new;
327 *num = new;
328 range
329 };
330 let range = match direction {
331 Direction::Incoming => increment(&mut incoming),
332 Direction::Outgoing => increment(&mut outgoing),
333 };
334 self.hugr_mut()
335 .graph
336 .set_num_ports(node.pg_index(), incoming, outgoing, |_, _| {});
337 range
338 }
339
340 fn set_parent(&mut self, node: Node, parent: Node) {
341 self.hugr_mut().hierarchy.detach(node.pg_index());
342 self.hugr_mut()
343 .hierarchy
344 .push_child(node.pg_index(), parent.pg_index())
345 .expect("Inserting a newly-created node into the hierarchy should never fail.");
346 }
347
348 fn move_after_sibling(&mut self, node: Node, after: Node) {
349 self.hugr_mut().hierarchy.detach(node.pg_index());
350 self.hugr_mut()
351 .hierarchy
352 .insert_after(node.pg_index(), after.pg_index())
353 .expect("Inserting a newly-created node into the hierarchy should never fail.");
354 }
355
356 fn move_before_sibling(&mut self, node: Node, before: Node) {
357 self.hugr_mut().hierarchy.detach(node.pg_index());
358 self.hugr_mut()
359 .hierarchy
360 .insert_before(node.pg_index(), before.pg_index())
361 .expect("Inserting a newly-created node into the hierarchy should never fail.");
362 }
363
364 fn replace_op(&mut self, node: Node, op: impl Into<OpType>) -> Result<OpType, HugrError> {
365 let cur = self.hugr_mut().op_types.get_mut(node.pg_index());
367 Ok(std::mem::replace(cur, op.into()))
368 }
369}
370
371#[cfg(test)]
372mod test {
373 use crate::{
374 builder::{Container, DFGBuilder, Dataflow, DataflowHugr},
375 extension::prelude::Noop,
376 hugr::internal::HugrMutInternals as _,
377 ops::handle::NodeHandle,
378 types::{Signature, Type},
379 Direction, HugrView as _,
380 };
381
382 #[test]
383 fn insert_ports() {
384 let (nop, mut hugr) = {
385 let mut builder =
386 DFGBuilder::new(Signature::new_endo(Type::UNIT).with_prelude()).unwrap();
387 let [nop_in] = builder.input_wires_arr();
388 let nop = builder
389 .add_dataflow_op(Noop::new(Type::UNIT), [nop_in])
390 .unwrap();
391 builder.add_other_wire(nop.node(), builder.output().node());
392 let [nop_out] = nop.outputs_arr();
393 (
394 nop.node(),
395 builder.finish_hugr_with_outputs([nop_out]).unwrap(),
396 )
397 };
398 let [i, o] = hugr.get_io(hugr.root()).unwrap();
399 assert_eq!(0..2, hugr.insert_ports(nop, Direction::Incoming, 0, 2));
400 assert_eq!(1..3, hugr.insert_ports(nop, Direction::Outgoing, 1, 2));
401
402 assert_eq!(hugr.single_linked_input(i, 0), Some((nop, 2.into())));
403 assert_eq!(hugr.single_linked_output(o, 0), Some((nop, 0.into())));
404 assert_eq!(hugr.single_linked_output(o, 1), Some((nop, 3.into())));
405 }
406}