graph_api_lib/walker/steps/
endpoints.rs

1use crate::ElementId;
2use crate::graph::{EdgeReference, Graph};
3use crate::walker::{EdgeWalker, VertexWalker, Walker};
4use std::marker::PhantomData;
5
6/// # Endpoint Type
7///
8/// Identifies which endpoint of an edge to navigate to.
9///
10/// - `Head`: The target/destination vertex of a directed edge
11/// - `Tail`: The source/origin vertex of a directed edge
12pub enum End {
13    /// The head (target/destination) of a directed edge
14    Head,
15    /// The tail (source/origin) of a directed edge
16    Tail,
17}
18
19/// # Endpoints Walker
20///
21/// Internal implementation for the head() and tail() steps.
22/// This walker traverses from edges to their endpoint vertices.
23///
24/// ## Visual Diagram
25///
26/// For a Tail traversal:
27/// ```text
28///   [Person A] --- edge1* ---> [Person B]
29///    ^
30///    |
31///   edge2*
32///    |
33///   [Person C]
34/// ```
35///
36/// After endpoints step:
37/// ```text
38///   [Person A]* --- edge1 ---> [Person B]
39///    
40///   [Person C]*
41/// ```
42///
43/// For a Head traversal the target vertices would be selected instead.
44pub struct Endpoints<'graph, Parent>
45where
46    Parent: EdgeWalker<'graph>,
47{
48    _phantom_data: PhantomData<&'graph ()>,
49    parent: Parent,
50    end: End,
51}
52
53impl<'graph, Parent> Endpoints<'graph, Parent>
54where
55    Parent: EdgeWalker<'graph>,
56{
57    /// Creates a new Endpoints walker that navigates to either the head
58    /// or tail of each edge in the parent walker
59    pub(crate) fn new(parent: Parent, end: End) -> Endpoints<'graph, Parent> {
60        Self {
61            _phantom_data: Default::default(),
62            parent,
63            end,
64        }
65    }
66}
67
68impl<'search, 'graph, Parent> Walker<'graph> for Endpoints<'graph, Parent>
69where
70    Parent: EdgeWalker<'graph>,
71    <Parent as Walker<'graph>>::Context: Clone + 'static,
72    <Parent as Walker<'graph>>::Graph: 'graph,
73    <Parent::Graph as Graph>::EdgeIter<'search, 'graph>:
74        Iterator<Item = <Parent::Graph as Graph>::EdgeReference<'graph>>,
75{
76    type Graph = Parent::Graph;
77
78    type Context = Parent::Context;
79    fn next_element(&mut self, graph: &'graph Self::Graph) -> Option<ElementId<Self::Graph>> {
80        self.next(graph).map(ElementId::Vertex)
81    }
82    fn ctx(&self) -> &Parent::Context {
83        self.parent.ctx()
84    }
85
86    fn ctx_mut(&mut self) -> &mut Self::Context {
87        self.parent.ctx_mut()
88    }
89}
90
91impl<'search, 'graph, Parent> VertexWalker<'graph> for Endpoints<'graph, Parent>
92where
93    Parent: EdgeWalker<'graph>,
94    <Parent as Walker<'graph>>::Context: Clone + 'static,
95    <Parent as Walker<'graph>>::Graph: 'graph,
96    <Parent::Graph as Graph>::EdgeIter<'search, 'graph>:
97        Iterator<Item = <Parent::Graph as Graph>::EdgeReference<'graph>>,
98{
99    fn next(&mut self, graph: &'graph Self::Graph) -> Option<<Self::Graph as Graph>::VertexId> {
100        self.parent.next(graph).map(|e| match &self.end {
101            End::Head => graph.edge(e).expect("edge must exist").head(),
102            End::Tail => graph.edge(e).expect("edge must exist").tail(),
103        })
104    }
105}