graph_api_lib/walker/steps/
control_flow.rs

1use crate::graph::Graph;
2use crate::walker::builder::{EdgeWalkerBuilder, VertexWalkerBuilder};
3use crate::walker::{EdgeWalker, VertexWalker, Walker};
4use crate::{EdgeReference, ElementId, VertexReference};
5use include_doc::function_body;
6use std::marker::PhantomData;
7use std::ops::ControlFlow;
8
9pub struct VertexControlFlow<'graph, Parent, Predicate> {
10    _phantom_data: PhantomData<&'graph ()>,
11    parent: Parent,
12    predicate: Predicate,
13}
14
15impl<Parent, Predicate> VertexControlFlow<'_, Parent, Predicate> {
16    pub(crate) fn new(parent: Parent, predicate: Predicate) -> Self {
17        Self {
18            _phantom_data: Default::default(),
19            parent,
20            predicate,
21        }
22    }
23}
24
25impl<'graph, Parent, Predicate> Walker<'graph> for VertexControlFlow<'graph, Parent, Predicate>
26where
27    Self: 'graph,
28    Parent: VertexWalker<'graph>,
29    for<'a> Predicate: Fn(
30        &'a <Parent::Graph as Graph>::VertexReference<'graph>,
31        &mut Parent::Context,
32    ) -> ControlFlow<
33        Option<&'a <Parent::Graph as Graph>::VertexReference<'graph>>,
34        Option<&'a <Parent::Graph as Graph>::VertexReference<'graph>>,
35    >,
36{
37    type Graph = Parent::Graph;
38    type Context = Parent::Context;
39
40    fn next_element(&mut self, graph: &'graph Self::Graph) -> Option<ElementId<Self::Graph>> {
41        self.next(graph).map(ElementId::Vertex)
42    }
43
44    fn ctx(&self) -> &Self::Context {
45        self.parent.ctx()
46    }
47
48    fn ctx_mut(&mut self) -> &mut Self::Context {
49        self.parent.ctx_mut()
50    }
51}
52
53impl<'graph, Parent, Predicate> VertexWalker<'graph>
54    for VertexControlFlow<'graph, Parent, Predicate>
55where
56    Self: 'graph,
57    Parent: VertexWalker<'graph>,
58    for<'a> Predicate: Fn(
59        &'a <Parent::Graph as Graph>::VertexReference<'graph>,
60        &mut Parent::Context,
61    ) -> ControlFlow<
62        Option<&'a <Parent::Graph as Graph>::VertexReference<'graph>>,
63        Option<&'a <Parent::Graph as Graph>::VertexReference<'graph>>,
64    >,
65{
66    fn next(&mut self, graph: &'graph Self::Graph) -> Option<<Self::Graph as Graph>::VertexId> {
67        while let Some(next) = self.parent.next(graph) {
68            if let Some(vertex) = graph.vertex(next) {
69                match (self.predicate)(&vertex, self.parent.ctx_mut()) {
70                    ControlFlow::Continue(Some(reference)) => return Some(reference.id()),
71                    ControlFlow::Continue(None) => continue, // Skip this element
72                    ControlFlow::Break(reference) => {
73                        return reference.map(|reference| reference.id());
74                    } // Break with optional final element
75                }
76            }
77        }
78        None
79    }
80}
81
82pub struct EdgeControlFlow<'graph, Parent, Predicate> {
83    _phantom_data: PhantomData<&'graph ()>,
84    parent: Parent,
85    predicate: Predicate,
86}
87
88impl<Parent, Predicate> EdgeControlFlow<'_, Parent, Predicate> {
89    pub(crate) fn new(parent: Parent, predicate: Predicate) -> Self {
90        Self {
91            _phantom_data: Default::default(),
92            parent,
93            predicate,
94        }
95    }
96}
97
98impl<'graph, Parent, Predicate> Walker<'graph> for EdgeControlFlow<'graph, Parent, Predicate>
99where
100    Self: 'graph,
101    Parent: EdgeWalker<'graph>,
102    for<'a> Predicate: Fn(
103        &'a <Parent::Graph as Graph>::EdgeReference<'graph>,
104        &mut Parent::Context,
105    ) -> ControlFlow<
106        Option<&'a <Parent::Graph as Graph>::EdgeReference<'graph>>,
107        Option<&'a <Parent::Graph as Graph>::EdgeReference<'graph>>,
108    >,
109{
110    type Graph = Parent::Graph;
111    type Context = Parent::Context;
112
113    fn next_element(&mut self, graph: &'graph Self::Graph) -> Option<ElementId<Self::Graph>> {
114        self.next(graph).map(ElementId::Edge)
115    }
116
117    fn ctx(&self) -> &Self::Context {
118        self.parent.ctx()
119    }
120
121    fn ctx_mut(&mut self) -> &mut Self::Context {
122        self.parent.ctx_mut()
123    }
124}
125
126impl<'graph, Parent, Predicate> EdgeWalker<'graph> for EdgeControlFlow<'graph, Parent, Predicate>
127where
128    Self: 'graph,
129    Parent: EdgeWalker<'graph>,
130    for<'a> Predicate: Fn(
131        &'a <Parent::Graph as Graph>::EdgeReference<'graph>,
132        &mut Parent::Context,
133    ) -> ControlFlow<
134        Option<&'a <Parent::Graph as Graph>::EdgeReference<'graph>>,
135        Option<&'a <Parent::Graph as Graph>::EdgeReference<'graph>>,
136    >,
137{
138    fn next(&mut self, graph: &'graph Self::Graph) -> Option<<Self::Graph as Graph>::EdgeId> {
139        while let Some(next) = self.parent.next(graph) {
140            if let Some(edge) = graph.edge(next) {
141                match (self.predicate)(&edge, self.parent.ctx_mut()) {
142                    ControlFlow::Continue(Some(reference)) => return Some(reference.id()),
143                    ControlFlow::Continue(None) => continue, // Skip this element
144                    ControlFlow::Break(reference) => {
145                        return reference.map(|reference| reference.id());
146                    } // Break with optional final element
147                }
148            }
149        }
150        None
151    }
152}
153
154impl<'graph, Mutability, Graph, Walker> VertexWalkerBuilder<'graph, Mutability, Graph, Walker>
155where
156    Graph: crate::graph::Graph,
157    Walker: VertexWalker<'graph, Graph = Graph>,
158{
159    /// # ControlFlow Step
160    ///
161    /// The `control_flow` step allows you to evaluate each vertex with a predicate function that returns a
162    /// `std::ops::ControlFlow` value. This gives precise control over traversal - you can either:
163    /// - Continue and include the element (ControlFlow::Continue(Some(id)))
164    /// - Continue but skip the element (ControlFlow::Continue(None))
165    /// - Stop traversal with an optional final element (ControlFlow::Break(option))
166    ///
167    /// ## Visual Diagram
168    ///
169    /// Before control_flow step (all vertices in traversal):
170    /// ```text
171    ///   [A]* --- edge1 ---> [B]* --- edge2 ---> [C]*
172    ///    ^
173    ///    |
174    ///   edge3
175    ///    |
176    ///   [D]*
177    /// ```
178    ///
179    /// After control_flow step that only includes projects and breaks on "Graph" projects:
180    /// ```text
181    ///   [A] --- edge1 ---> [B]* --- edge2 ---> [C]*
182    ///    ^
183    ///    |
184    ///   edge3
185    ///    |
186    ///   [D]
187    /// ```
188    ///
189    /// ## Parameters
190    ///
191    /// - `predicate`: A function that takes a reference to a vertex and a mutable reference to its context,
192    ///   and returns a `std::ops::ControlFlow<Option<VertexId>, Option<VertexId>>` value:
193    ///   - Return `ControlFlow::Continue(Some(vertex.id()))` to include the vertex and continue
194    ///   - Return `ControlFlow::Continue(None)` to skip the vertex and continue
195    ///   - Return `ControlFlow::Break(Some(vertex.id()))` to include the vertex and stop traversal
196    ///   - Return `ControlFlow::Break(None)` to stop traversal without including the vertex
197    ///
198    /// ## Return Value
199    ///
200    /// A new walker that applies the control flow logic to the traversal.
201    ///
202    /// ## Example
203    ///
204    /// ```rust
205    #[doc = function_body!("examples/control_flow.rs", vertex_example, [])]
206    /// ```
207    ///
208    /// ## Notes
209    ///
210    /// - This step is more powerful than `filter()` as it can both filter elements and control traversal flow
211    /// - The predicate receives a mutable reference to the context, allowing you to update state during traversal
212    /// - Use this step when you need a combination of filtering and conditional stopping of traversal
213    /// - Only elements where the predicate returns `Some` will be included in the traversal
214    /// - When `ControlFlow::Break` is returned, the entire traversal stops immediately
215    pub fn control_flow<Predicate>(
216        self,
217        predicate: Predicate,
218    ) -> VertexWalkerBuilder<'graph, Mutability, Graph, VertexControlFlow<'graph, Walker, Predicate>>
219    where
220        Walker: 'graph,
221        for<'a> Predicate: Fn(
222                &'a Graph::VertexReference<'graph>,
223                &mut Walker::Context,
224            ) -> ControlFlow<
225                Option<&'a Graph::VertexReference<'graph>>,
226                Option<&'a Graph::VertexReference<'graph>>,
227            > + 'graph,
228    {
229        self.with_vertex_walker(|walker| VertexControlFlow::new(walker, predicate))
230    }
231}
232
233impl<'graph, Mutability, Graph, Walker> EdgeWalkerBuilder<'graph, Mutability, Graph, Walker>
234where
235    Graph: crate::graph::Graph,
236    Walker: EdgeWalker<'graph, Graph = Graph>,
237{
238    /// # ControlFlow Step
239    ///
240    /// The `control_flow` step allows you to evaluate each edge with a predicate function that returns a
241    /// `std::ops::ControlFlow` value. This gives precise control over traversal - you can either:
242    /// - Continue and include the element (ControlFlow::Continue(Some(id)))
243    /// - Continue but skip the element (ControlFlow::Continue(None))
244    /// - Stop traversal with an optional final element (ControlFlow::Break(option))
245    ///
246    /// ## Visual Diagram
247    ///
248    /// Before control_flow step (all edges in traversal):
249    /// ```text
250    ///   [Person A] --- knows* ---> [Person B] --- created* ---> [Project]
251    ///    ^
252    ///    |
253    ///   owns*
254    ///    |
255    ///   [Company]
256    /// ```
257    ///
258    /// After control_flow step that only includes "knows" edges and breaks on old connections:
259    /// ```text
260    ///   [Person A] --- knows* ---> [Person B] --- created ---> [Project]
261    ///    ^
262    ///    |
263    ///   owns
264    ///    |
265    ///   [Company]
266    /// ```
267    ///
268    /// ## Parameters
269    ///
270    /// - `predicate`: A function that takes a reference to an edge and a mutable reference to its context,
271    ///   and returns a `std::ops::ControlFlow<Option<EdgeId>, Option<EdgeId>>` value:
272    ///   - Return `ControlFlow::Continue(Some(edge.id()))` to include the edge and continue
273    ///   - Return `ControlFlow::Continue(None)` to skip the edge and continue
274    ///   - Return `ControlFlow::Break(Some(edge.id()))` to include the edge and stop traversal
275    ///   - Return `ControlFlow::Break(None)` to stop traversal without including the edge
276    ///
277    /// ## Return Value
278    ///
279    /// A new walker that applies the control flow logic to the traversal.
280    ///
281    /// ## Example
282    ///
283    /// ```rust
284    #[doc = function_body!("examples/control_flow.rs", edge_example, [])]
285    /// ```
286    ///
287    /// ## Notes
288    ///
289    /// - This step is more powerful than `filter()` as it can both filter elements and control traversal flow
290    /// - The predicate receives a mutable reference to the context, allowing you to update state during traversal
291    /// - Use this step when you need a combination of filtering and conditional stopping of traversal
292    /// - Only elements where the predicate returns `Some` will be included in the traversal
293    /// - When `ControlFlow::Break` is returned, the entire traversal stops immediately
294    pub fn control_flow<Predicate>(
295        self,
296        predicate: Predicate,
297    ) -> EdgeWalkerBuilder<'graph, Mutability, Graph, EdgeControlFlow<'graph, Walker, Predicate>>
298    where
299        Walker: 'graph,
300        for<'a> Predicate: Fn(
301                &'a Graph::EdgeReference<'graph>,
302                &mut Walker::Context,
303            ) -> ControlFlow<
304                Option<&'a Graph::EdgeReference<'graph>>,
305                Option<&'a Graph::EdgeReference<'graph>>,
306            > + 'graph,
307    {
308        self.with_edge_walker(|walker| EdgeControlFlow::new(walker, predicate))
309    }
310}