graph_api_lib/walker/steps/
edges.rs

1use crate::graph::{EdgeReference, Graph};
2use crate::walker::builder::{EdgeWalkerBuilder, VertexWalkerBuilder};
3use crate::walker::{EdgeWalker, VertexWalker, Walker};
4use crate::{EdgeSearch, ElementId};
5use include_doc::function_body;
6
7// ================ EDGES IMPLEMENTATION ================
8
9pub struct Edges<'search, 'graph, Parent>
10where
11    Parent: VertexWalker<'graph>,
12    <Parent as Walker<'graph>>::Graph: 'graph,
13{
14    parent: Parent,
15    current_iter: Option<<Parent::Graph as Graph>::EdgeIter<'search, 'graph>>,
16    edge_search: EdgeSearch<'search, Parent::Graph>,
17    current: Option<<Parent::Graph as Graph>::VertexId>,
18}
19
20impl<'a, 'graph, Parent> Edges<'a, 'graph, Parent>
21where
22    Parent: VertexWalker<'graph>,
23{
24    pub(crate) fn new(
25        parent: Parent,
26        search: EdgeSearch<'a, Parent::Graph>,
27    ) -> Edges<'a, 'graph, Parent> {
28        Self {
29            parent,
30            edge_search: search,
31            current_iter: None,
32            current: None,
33        }
34    }
35}
36
37impl<'search, 'graph, Parent> Walker<'graph> for Edges<'_, 'graph, Parent>
38where
39    Parent: VertexWalker<'graph>,
40    <Parent as Walker<'graph>>::Graph: 'graph,
41    <Parent::Graph as Graph>::EdgeIter<'search, 'graph>:
42        Iterator<Item = <Parent::Graph as Graph>::EdgeReference<'graph>>,
43{
44    type Graph = Parent::Graph;
45
46    type Context = Parent::Context;
47    fn next_element(&mut self, graph: &'graph Self::Graph) -> Option<ElementId<Self::Graph>> {
48        self.next(graph).map(ElementId::Edge)
49    }
50    fn ctx(&self) -> &Self::Context {
51        self.parent.ctx()
52    }
53
54    fn ctx_mut(&mut self) -> &mut Self::Context {
55        self.parent.ctx_mut()
56    }
57}
58
59impl<'graph, Parent> EdgeWalker<'graph> for Edges<'_, 'graph, Parent>
60where
61    Parent: VertexWalker<'graph>,
62    <Parent as Walker<'graph>>::Graph: 'graph,
63{
64    fn next(&mut self, graph: &'graph Self::Graph) -> Option<<Self::Graph as Graph>::EdgeId> {
65        loop {
66            if let Some(ref mut iter) = self.current_iter {
67                if let Some(edge) = iter.next() {
68                    return Some(edge.id());
69                }
70                self.current_iter = None;
71            } else if let Some(vertex) = self.parent.next(graph) {
72                self.current = Some(vertex);
73                self.current_iter = Some(graph.edges(vertex, &self.edge_search));
74            } else {
75                return None;
76            }
77        }
78    }
79}
80
81impl<'graph, Mutability, Graph, Walker> VertexWalkerBuilder<'graph, Mutability, Graph, Walker>
82where
83    Graph: crate::graph::Graph,
84    Walker: VertexWalker<'graph, Graph = Graph>,
85{
86    /// # Edges Step
87    ///
88    /// The `edges` step allows you to traverse to the edges in a graph.
89    /// It moves the traversal position from vertices to their connected edges based on the provided search criteria.
90    ///
91    /// ## Visual Diagram
92    ///
93    /// Before edges step (traversal position on vertices):
94    /// ```text
95    ///   [Person A]* --- knows ---> [Person B] --- created ---> [Project]
96    ///    ^                                         
97    ///    |                                         
98    ///   owns                                       
99    ///    |                                         
100    ///   [Company C]                                        
101    /// ```
102    ///
103    /// After edges step with outgoing direction (traversal position moves to edges):
104    /// ```text
105    ///   [Person A] --- knows --->* [Person B] --- created ---> [Project]
106    ///    ^                                         
107    ///    |                                         
108    ///   owns -*                                        
109    ///    |                                         
110    ///   [Company C]                                        
111    /// ```
112    ///
113    /// ## Parameters
114    ///
115    /// - `search`: An `EdgeSearch` that defines which edges to include. This can filter by label, direction, and other criteria.
116    ///
117    /// ## Return Value
118    ///
119    /// A new walker where the traversal position is on the edges matching the search criteria.
120    ///
121    /// ## Example
122    ///
123    /// ```rust
124    #[doc = function_body!("examples/edges.rs", example, [])]
125    /// ```
126    ///
127    /// ## Notes
128    ///
129    /// - The edges step changes the traversal position from vertices to edges
130    /// - To get back to vertices after an edges step, use `head()` or `tail()`
131    /// - The search direction matters: `.outgoing()` finds edges where the current vertex is the source,
132    ///   `.incoming()` finds edges where the current vertex is the target, and `.bidirectional()` finds both
133    /// - The edges step can filter by label and other properties through the EdgeSearch parameter
134    pub fn edges<'a, T: Into<EdgeSearch<'a, Graph>>>(
135        self,
136        search: T,
137    ) -> EdgeWalkerBuilder<'graph, Mutability, Graph, Edges<'a, 'graph, Walker>> {
138        self.with_edge_walker(|walker| walker.edges(search.into()))
139    }
140}