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}