graph_api_lib/walker/steps/
take.rs

1use crate::ElementId;
2use crate::graph::Graph;
3use crate::walker::builder::{EdgeWalkerBuilder, VertexWalkerBuilder};
4use crate::walker::{EdgeWalker, VertexWalker, Walker};
5use include_doc::function_body;
6use std::marker::PhantomData;
7
8// ================ TAKE IMPLEMENTATION ================
9
10pub struct VertexTake<'graph, Parent> {
11    _phantom_data: PhantomData<&'graph ()>,
12    parent: Parent,
13    limit: usize,
14}
15
16impl<Parent> VertexTake<'_, Parent> {
17    pub(crate) fn new(parent: Parent, limit: usize) -> Self {
18        Self {
19            _phantom_data: Default::default(),
20            parent,
21            limit,
22        }
23    }
24}
25
26impl<'graph, Parent> Walker<'graph> for VertexTake<'graph, Parent>
27where
28    Parent: VertexWalker<'graph>,
29{
30    type Graph = Parent::Graph;
31
32    type Context = Parent::Context;
33    fn next_element(&mut self, graph: &'graph Self::Graph) -> Option<ElementId<Self::Graph>> {
34        self.next(graph).map(ElementId::Vertex)
35    }
36
37    fn ctx(&self) -> &Parent::Context {
38        self.parent.ctx()
39    }
40    fn ctx_mut(&mut self) -> &mut Self::Context {
41        self.parent.ctx_mut()
42    }
43}
44
45impl<'graph, Parent> VertexWalker<'graph> for VertexTake<'graph, Parent>
46where
47    Parent: VertexWalker<'graph>,
48{
49    fn next(&mut self, graph: &'graph Self::Graph) -> Option<<Self::Graph as Graph>::VertexId> {
50        if self.limit > 0 {
51            self.limit -= 1;
52            self.parent.next(graph)
53        } else {
54            None
55        }
56    }
57}
58
59pub struct EdgeTake<'graph, Parent> {
60    _phantom_data: PhantomData<&'graph ()>,
61    parent: Parent,
62    limit: usize,
63}
64
65impl<Parent> EdgeTake<'_, Parent> {
66    pub(crate) fn new(parent: Parent, limit: usize) -> Self {
67        Self {
68            _phantom_data: Default::default(),
69            parent,
70            limit,
71        }
72    }
73}
74
75impl<'graph, Parent> Walker<'graph> for EdgeTake<'graph, Parent>
76where
77    Parent: EdgeWalker<'graph>,
78{
79    type Graph = Parent::Graph;
80
81    type Context = Parent::Context;
82    fn next_element(&mut self, graph: &'graph Self::Graph) -> Option<ElementId<Self::Graph>> {
83        self.next(graph).map(ElementId::Edge)
84    }
85    fn ctx(&self) -> &Parent::Context {
86        self.parent.ctx()
87    }
88    fn ctx_mut(&mut self) -> &mut Self::Context {
89        self.parent.ctx_mut()
90    }
91}
92
93impl<'graph, Parent> EdgeWalker<'graph> for EdgeTake<'graph, Parent>
94where
95    Parent: EdgeWalker<'graph>,
96{
97    fn next(&mut self, graph: &'graph Self::Graph) -> Option<<Self::Graph as Graph>::EdgeId> {
98        if self.limit > 0 {
99            self.limit -= 1;
100            self.parent.next(graph)
101        } else {
102            None
103        }
104    }
105}
106
107impl<'graph, Mutability, Graph, Walker> VertexWalkerBuilder<'graph, Mutability, Graph, Walker>
108where
109    Graph: crate::graph::Graph,
110    Walker: VertexWalker<'graph, Graph = Graph>,
111{
112    /// # Take Step
113    ///
114    /// The `take` step restricts a vertex traversal to return at most a specified number of vertices.
115    /// This is useful for pagination, performance optimization, or when you only need a subset of results.
116    ///
117    /// ## Visual Diagram
118    ///
119    /// Before take step (with multiple vertices in traversal):
120    /// ```text
121    ///   [A]* --- edge1 ---> [B]* --- edge2 ---> [C]*  
122    ///    ^                                         
123    ///    |                                         
124    ///   edge3                                       
125    ///    |                                         
126    ///   [D]*                                        
127    /// ```
128    ///
129    /// After take(2) step (only first 2 vertices remain in traversal):
130    /// ```text
131    ///   [A]* --- edge1 ---> [B]* --- edge2 ---> [C]  
132    ///    ^                                         
133    ///    |                                         
134    ///   edge3                                       
135    ///    |                                         
136    ///   [D]                                        
137    /// ```
138    ///
139    /// ## Parameters
140    ///
141    /// - `n`: A usize value specifying the maximum number of vertices to include in the traversal
142    ///
143    /// ## Return Value
144    ///
145    /// Returns a traversal containing at most the specified number of vertices.
146    ///
147    /// ## Example
148    ///
149    /// ```rust
150    #[doc = function_body!("examples/take.rs", vertex_example, [])]
151    /// ```
152    ///
153    /// ## Notes
154    ///
155    /// - The `take` step is generally applied after filtering operations but before terminal operations
156    /// - It does not guarantee which vertices will be returned, just how many
157    /// - For predictable results, combine with sorting operations or range indexes
158    /// - Can significantly improve performance by avoiding unnecessary traversal
159    /// - Particularly useful for large graphs where full traversal would be expensive
160    /// - If the traversal contains fewer vertices than the limit, all vertices are returned
161    /// - Different from `first()` which returns only a single vertex as an Option
162    /// - Follows the naming convention of Rust's standard library Iterator::take
163    pub fn take(
164        self,
165        n: usize,
166    ) -> VertexWalkerBuilder<'graph, Mutability, Graph, VertexTake<'graph, Walker>> {
167        self.with_vertex_walker(|walker| walker.take(n))
168    }
169}
170
171impl<'graph, Mutability, Graph, Walker> EdgeWalkerBuilder<'graph, Mutability, Graph, Walker>
172where
173    Graph: crate::graph::Graph,
174    Walker: EdgeWalker<'graph, Graph = Graph>,
175{
176    /// # Take Step
177    ///
178    /// The `take` step restricts an edge traversal to return at most a specified number of edges.
179    /// This is useful for pagination, performance optimization, or when you only need a subset of edges.
180    ///
181    /// ## Visual Diagram
182    ///
183    /// Before take step (with multiple edges in traversal):
184    /// ```text
185    ///   [Person A] --- knows* ---> [Person B] --- created* ---> [Project]
186    ///    ^                                         
187    ///    |                                         
188    ///   owns*                                       
189    ///    |                                         
190    ///   [Company]                                        
191    /// ```
192    ///
193    /// After take(2) step (only first 2 edges remain in traversal):
194    /// ```text
195    ///   [Person A] --- knows* ---> [Person B] --- created* ---> [Project]
196    ///    ^                                         
197    ///    |                                         
198    ///   owns                                       
199    ///    |                                         
200    ///   [Company]                                        
201    /// ```
202    ///
203    /// ## Parameters
204    ///
205    /// - `n`: A usize value specifying the maximum number of edges to include in the traversal
206    ///
207    /// ## Return Value
208    ///
209    /// Returns a traversal containing at most the specified number of edges.
210    ///
211    /// ## Example
212    ///
213    /// ```rust
214    #[doc = function_body!("examples/take.rs", edge_example, [])]
215    /// ```
216    ///
217    /// ## Notes
218    ///
219    /// - Use take to avoid processing excessive numbers of connections in a dense graph
220    /// - Improves performance for graphs with highly connected nodes
221    /// - Particularly useful when you only need to analyze a sample of connections
222    /// - The order of edges returned depends on the graph implementation
223    /// - For pagination purposes, consider combining with sorting or other ordering mechanisms
224    /// - Follows the naming convention of Rust's standard library Iterator::take
225    pub fn take(
226        self,
227        n: usize,
228    ) -> EdgeWalkerBuilder<'graph, Mutability, Graph, EdgeTake<'graph, Walker>> {
229        self.with_edge_walker(|walker| walker.take(n))
230    }
231}