guppy/petgraph_support/
dfs.rs
1use petgraph::{
5 prelude::*,
6 visit::{
7 DfsPostOrder, IntoEdgeReferences, IntoEdges, IntoEdgesDirected, Reversed,
8 ReversedEdgeReference, VisitMap,
9 },
10};
11
12pub fn dfs_next_buffered_filter<N, VM, G>(
14 dfs: &mut DfsPostOrder<N, VM>,
15 graph: G,
16 mut buffered_filter: impl BufferedEdgeFilter<G>,
17) -> Option<N>
18where
19 N: Copy + PartialEq,
20 VM: VisitMap<N>,
21 G: IntoEdges<NodeId = N>,
22{
23 while let Some(&nx) = dfs.stack.last() {
25 if dfs.discovered.visit(nx) {
26 let neighbors = graph.edges(nx).flat_map(|edge| {
28 buffered_filter
29 .filter(edge)
30 .into_iter()
31 .map(|edge| edge.target())
32 });
33 for succ in neighbors {
34 if !dfs.discovered.is_visited(&succ) {
35 dfs.stack.push(succ);
36 }
37 }
38 } else {
39 dfs.stack.pop();
40 if dfs.finished.visit(nx) {
41 return Some(nx);
43 }
44 }
45 }
46 None
47}
48
49pub trait BufferedEdgeFilter<G>
52where
53 G: IntoEdges,
54{
55 type Iter: IntoIterator<Item = G::EdgeRef>;
57
58 fn filter(&mut self, edge: G::EdgeRef) -> Self::Iter;
59}
60
61impl<G, T> BufferedEdgeFilter<G> for &mut T
62where
63 T: BufferedEdgeFilter<G>,
64 G: IntoEdges,
65{
66 type Iter = T::Iter;
68
69 #[inline]
70 fn filter(&mut self, edge: G::EdgeRef) -> Self::Iter {
71 (*self).filter(edge)
72 }
73}
74
75#[derive(Debug)]
76pub struct SimpleEdgeFilterFn<F>(pub F);
77
78impl<F, G> BufferedEdgeFilter<G> for SimpleEdgeFilterFn<F>
79where
80 F: FnMut(G::EdgeRef) -> bool,
81 G: IntoEdges,
82{
83 type Iter = Option<G::EdgeRef>;
84
85 #[inline]
86 fn filter(&mut self, edge: G::EdgeRef) -> Self::Iter {
87 if (self.0)(edge) { Some(edge) } else { None }
88 }
89}
90
91#[derive(Debug)]
92pub struct BufferedEdgeFilterFn<F>(pub F);
93
94impl<F, G, I> BufferedEdgeFilter<G> for BufferedEdgeFilterFn<F>
95where
96 F: FnMut(G::EdgeRef) -> I,
97 G: IntoEdges,
98 I: IntoIterator<Item = G::EdgeRef>,
99{
100 type Iter = I;
101
102 #[inline]
103 fn filter(&mut self, edge: G::EdgeRef) -> Self::Iter {
104 (self.0)(edge)
105 }
106}
107
108#[derive(Debug)]
109pub struct ReversedBufferedFilter<T>(pub T);
110
111impl<T, G> BufferedEdgeFilter<Reversed<G>> for ReversedBufferedFilter<T>
112where
113 T: BufferedEdgeFilter<G>,
114 G: IntoEdgesDirected,
115{
116 type Iter =
117 ReversedEdgeReferences<<<T as BufferedEdgeFilter<G>>::Iter as IntoIterator>::IntoIter>;
118
119 fn filter(&mut self, edge: <Reversed<G> as IntoEdgeReferences>::EdgeRef) -> Self::Iter {
120 ReversedEdgeReferences {
121 iter: self.0.filter(edge.into_unreversed()).into_iter(),
122 }
123 }
124}
125
126pub struct ReversedEdgeReferences<I> {
128 iter: I,
129}
130
131impl<I> Iterator for ReversedEdgeReferences<I>
132where
133 I: Iterator,
134{
135 type Item = ReversedEdgeReference<I::Item>;
136
137 #[inline]
138 fn next(&mut self) -> Option<Self::Item> {
139 let item = self.iter.next()?;
142 Some(unsafe { horrible_transmute::<I::Item, ReversedEdgeReference<I::Item>>(item) })
143 }
144
145 #[inline]
146 fn size_hint(&self) -> (usize, Option<usize>) {
147 self.iter.size_hint()
148 }
149}
150
151unsafe fn horrible_transmute<A, B>(a: A) -> B {
152 let b = ::core::ptr::read(&a as *const A as *const B);
153 ::core::mem::forget(a);
154 b
155}
156
157static_assertions::assert_eq_size!((), ReversedEdgeReference<()>);