graph_api_lib/walker/steps/
mutate_context.rs

1use crate::graph::Graph;
2use crate::walker::builder::{EdgeWalkerBuilder, VertexWalkerBuilder};
3use crate::walker::{EdgeWalker, VertexWalker, Walker};
4use include_doc::function_body;
5use std::marker::PhantomData;
6
7impl<'graph, Mutability, Graph, Walker> VertexWalkerBuilder<'graph, Mutability, Graph, Walker>
8where
9    Graph: crate::graph::Graph,
10    Walker: VertexWalker<'graph, Graph = Graph>,
11{
12    /// # Mutate Context Step
13    ///
14    /// The `mutate_context` step allows you to modify the context during traversal. For each element
15    /// in the traversal, the provided callback function is executed, giving you the ability to modify
16    /// the current context object in-place.
17    ///
18    /// ## Visual Diagram
19    ///
20    /// Before mutate_context step (traversal with contexts):
21    /// ```text
22    ///   [Person A]* + {visited: false} --- knows ---> [Person B]* + {visited: false}
23    /// ```
24    ///
25    /// After mutate_context step (contexts have been modified):
26    /// ```text
27    ///   [Person A]* + {visited: true} --- knows ---> [Person B]* + {visited: true}
28    /// ```
29    ///
30    /// ## Parameters
31    ///
32    /// - `callback`: A function that receives:
33    ///   - The current vertex reference
34    ///   - A mutable reference to the current context
35    ///
36    /// ## Return Value
37    ///
38    /// Returns a traversal with the same elements, but with modified context values.
39    ///
40    /// ## Example
41    ///
42    /// ```rust
43    #[doc = function_body!("examples/mutate_context.rs", vertex_mutate_context_example, [])]
44    /// ```
45    ///
46    /// ## Notes
47    ///
48    /// - Unlike `push_context`, this step doesn't create a new context layer
49    /// - The callback can modify the context in-place, allowing for updating state during traversal
50    /// - Context modifications are applied immediately, affecting subsequent steps
51    /// - This is useful for building accumulators or updating state as you traverse
52    /// - Can be combined with other context-based steps for complex traversal logic
53    /// - When using nested contexts, only the current context level is mutable; parent contexts remain immutable
54    pub fn mutate_context<Callback>(
55        self,
56        callback: Callback,
57    ) -> VertexWalkerBuilder<'graph, Mutability, Graph, VertexMutateContext<'graph, Walker, Callback>>
58    where
59        Callback: Fn(&Graph::VertexReference<'_>, &mut Walker::Context) + 'graph,
60    {
61        self.with_vertex_walker(|walker| VertexMutateContext::new(walker, callback))
62    }
63}
64
65impl<'graph, Mutability, Graph, Walker> EdgeWalkerBuilder<'graph, Mutability, Graph, Walker>
66where
67    Graph: crate::graph::Graph,
68    Walker: EdgeWalker<'graph, Graph = Graph>,
69{
70    /// # Mutate Context Step
71    ///
72    /// The `mutate_context` step allows you to modify the context during edge traversal. For each edge
73    /// in the traversal, the provided callback function is executed, giving you the ability to modify
74    /// the current context object in-place.
75    ///
76    /// ## Visual Diagram
77    ///
78    /// Before mutate_context step (traversal with contexts):
79    /// ```text
80    ///   [Person A] --- knows* + {weight: 1} ---> [Person B]
81    /// ```
82    ///
83    /// After mutate_context step (contexts have been modified):
84    /// ```text
85    ///   [Person A] --- knows* + {weight: 2} ---> [Person B]
86    /// ```
87    ///
88    /// ## Parameters
89    ///
90    /// - `callback`: A function that receives:
91    ///   - The current edge reference
92    ///   - A mutable reference to the current context
93    ///
94    /// ## Return Value
95    ///
96    /// Returns a traversal with the same elements, but with modified context values.
97    ///
98    /// ## Example
99    ///
100    /// ```rust
101    #[doc = function_body!("examples/mutate_context.rs", edge_mutate_context_example, [])]
102    /// ```
103    ///
104    /// ## Notes
105    ///
106    /// See the documentation for [`VertexWalkerBuilder::mutate_context`] for more details.
107    pub fn mutate_context<Callback>(
108        self,
109        callback: Callback,
110    ) -> EdgeWalkerBuilder<'graph, Mutability, Graph, EdgeMutateContext<'graph, Walker, Callback>>
111    where
112        Callback: Fn(&Graph::EdgeReference<'_>, &mut Walker::Context) + 'graph,
113    {
114        self.with_edge_walker(|walker| EdgeMutateContext::new(walker, callback))
115    }
116}
117
118pub struct VertexMutateContext<'graph, Parent, Callback>
119where
120    Parent: VertexWalker<'graph>,
121    Callback:
122        Fn(&<Parent::Graph as crate::graph::Graph>::VertexReference<'_>, &mut Parent::Context),
123{
124    _phantom_data: PhantomData<&'graph ()>,
125    parent: Parent,
126    callback: Callback,
127}
128
129impl<'graph, Parent, Callback> VertexMutateContext<'graph, Parent, Callback>
130where
131    Parent: VertexWalker<'graph>,
132    Callback:
133        Fn(&<Parent::Graph as crate::graph::Graph>::VertexReference<'_>, &mut Parent::Context),
134{
135    pub fn new(parent: Parent, callback: Callback) -> Self {
136        VertexMutateContext {
137            _phantom_data: Default::default(),
138            parent,
139            callback,
140        }
141    }
142}
143
144impl<'graph, Parent, Callback> Walker<'graph> for VertexMutateContext<'graph, Parent, Callback>
145where
146    Parent: VertexWalker<'graph>,
147    Callback:
148        Fn(&<Parent::Graph as crate::graph::Graph>::VertexReference<'_>, &mut Parent::Context),
149{
150    type Graph = Parent::Graph;
151    type Context = Parent::Context;
152
153    fn next_element(
154        &mut self,
155        graph: &'graph Self::Graph,
156    ) -> Option<crate::ElementId<Self::Graph>> {
157        self.next(graph).map(crate::ElementId::Vertex)
158    }
159
160    fn ctx(&self) -> &Self::Context {
161        self.parent.ctx()
162    }
163
164    fn ctx_mut(&mut self) -> &mut Self::Context {
165        self.parent.ctx_mut()
166    }
167}
168
169impl<'graph, Parent, Callback> VertexWalker<'graph>
170    for VertexMutateContext<'graph, Parent, Callback>
171where
172    Parent: VertexWalker<'graph>,
173    Callback:
174        Fn(&<Parent::Graph as crate::graph::Graph>::VertexReference<'_>, &mut Parent::Context),
175{
176    fn next(
177        &mut self,
178        graph: &'graph Self::Graph,
179    ) -> Option<<Self::Graph as crate::graph::Graph>::VertexId> {
180        if let Some(next) = self.parent.next(graph) {
181            if let Some(vertex) = graph.vertex(next) {
182                (self.callback)(&vertex, self.parent.ctx_mut());
183                return Some(next);
184            }
185        }
186        None
187    }
188}
189
190pub struct EdgeMutateContext<'graph, Parent, Callback>
191where
192    Parent: EdgeWalker<'graph>,
193    Callback: Fn(&<Parent::Graph as crate::graph::Graph>::EdgeReference<'_>, &mut Parent::Context),
194{
195    _phantom_data: PhantomData<&'graph ()>,
196    parent: Parent,
197    callback: Callback,
198}
199
200impl<'graph, Parent, Callback> EdgeMutateContext<'graph, Parent, Callback>
201where
202    Parent: EdgeWalker<'graph>,
203    Callback: Fn(&<Parent::Graph as crate::graph::Graph>::EdgeReference<'_>, &mut Parent::Context),
204{
205    pub fn new(parent: Parent, callback: Callback) -> Self {
206        EdgeMutateContext {
207            _phantom_data: Default::default(),
208            parent,
209            callback,
210        }
211    }
212}
213
214impl<'graph, Parent, Callback> Walker<'graph> for EdgeMutateContext<'graph, Parent, Callback>
215where
216    Parent: EdgeWalker<'graph>,
217    Callback: Fn(&<Parent::Graph as crate::graph::Graph>::EdgeReference<'_>, &mut Parent::Context),
218{
219    type Graph = Parent::Graph;
220    type Context = Parent::Context;
221
222    fn next_element(
223        &mut self,
224        graph: &'graph Self::Graph,
225    ) -> Option<crate::ElementId<Self::Graph>> {
226        self.next(graph).map(crate::ElementId::Edge)
227    }
228
229    fn ctx(&self) -> &Self::Context {
230        self.parent.ctx()
231    }
232
233    fn ctx_mut(&mut self) -> &mut Self::Context {
234        self.parent.ctx_mut()
235    }
236}
237
238impl<'graph, Parent, Callback> EdgeWalker<'graph> for EdgeMutateContext<'graph, Parent, Callback>
239where
240    Parent: EdgeWalker<'graph>,
241    Callback: Fn(&<Parent::Graph as crate::graph::Graph>::EdgeReference<'_>, &mut Parent::Context),
242{
243    fn next(
244        &mut self,
245        graph: &'graph Self::Graph,
246    ) -> Option<<Self::Graph as crate::graph::Graph>::EdgeId> {
247        if let Some(next) = self.parent.next(graph) {
248            if let Some(edge) = graph.edge(next) {
249                (self.callback)(&edge, self.parent.ctx_mut());
250                return Some(next);
251            }
252        }
253        None
254    }
255}