1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
use graph_api_lib::*;
use graph_api_simplegraph::SimpleGraph;
use graph_api_test::{Edge, Vertex, populate_graph};
fn example() {
let mut graph = SimpleGraph::<Vertex, Edge>::new();
populate_graph(&mut graph);
// Example 1: Complex traversal without boxing (for comparison)
// This creates deeply nested types like:
// Endpoints<Edges<Endpoints<Edges<Vertices<Empty>>>>>
println!("=== Without Boxing (Complex Types) ===");
let _complex_result: Vec<_> = graph
.walk()
.vertices(VertexSearch::scan())
.edges(EdgeSearch::scan())
.head()
.edges(EdgeSearch::scan())
.head()
.collect();
// Example 2: Strategic boxing to control type complexity
println!("=== With Strategic Boxing ===");
let boxed_result: Vec<_> = graph
.walk()
.vertices(VertexSearch::scan())
.edges(EdgeSearch::scan())
.boxed() // ← Breaks type complexity here
.head()
.edges(EdgeSearch::scan())
.boxed() // ← Further complexity reduction
.head()
.edges(EdgeSearch::scan())
.head()
.collect();
println!(
"Found {} vertices after complex traversal",
boxed_result.len()
);
// Example 3: Boxing at different strategic points
println!("=== Boxing at Logical Checkpoints ===");
let checkpoint_result: Vec<_> = graph
.walk()
.vertices(VertexSearch::scan())
.take(10)
.boxed() // ← Box after initial filtering
.edges(EdgeSearch::scan())
.boxed() // ← Box after edge filtering
.head()
.collect();
println!(
"Found {} vertices after filtered traversal",
checkpoint_result.len()
);
// Example 4: When NOT to use boxing (simple chains)
println!("=== Simple Chains (No Boxing Needed) ===");
let simple_result: Vec<_> = graph
.walk()
.vertices(VertexSearch::scan())
.take(5) // Simple chain - no boxing needed
.collect();
println!("Found {} vertices in simple traversal", simple_result.len());
// Example 5: Boxing for storage in data structures
println!("=== Storing Walkers in Data Structures ===");
// Without boxing, this would be very difficult due to complex types
// Note: Different walker types need different iterators
let vertex_walkers: Vec<Box<dyn Iterator<Item = _>>> = vec![
Box::new(
graph
.walk()
.vertices(VertexSearch::scan())
.take(5)
.boxed() // ← Makes storage possible
.into_iter(),
),
Box::new(
graph
.walk()
.vertices(VertexSearch::scan())
.take(3)
.boxed() // ← Makes storage possible
.into_iter(),
),
];
println!("Stored {} different walker types", vertex_walkers.len());
}
fn main() {
example();
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_boxed_examples() {
example(); // Just ensure it runs without panicking
}
#[test]
fn test_compilation_time_comparison() {
// This test demonstrates the type complexity difference
let mut graph = SimpleGraph::<Vertex, Edge>::new();
populate_graph(&mut graph);
// Measure difference in compilation for complex vs boxed chains
// (The real benefit is seen during actual compilation, not runtime)
// Complex nested types (slower to compile)
let _complex: Vec<_> = graph
.walk()
.vertices(VertexSearch::scan())
.edges(EdgeSearch::scan())
.head()
.edges(EdgeSearch::scan())
.head()
.edges(EdgeSearch::scan())
.head()
.collect();
// Boxed types (faster to compile)
let _boxed: Vec<_> = graph
.walk()
.vertices(VertexSearch::scan())
.edges(EdgeSearch::scan())
.boxed()
.head()
.edges(EdgeSearch::scan())
.boxed()
.head()
.edges(EdgeSearch::scan())
.boxed()
.head()
.collect();
}
#[test]
fn test_performance_characteristics() {
let mut graph = SimpleGraph::<Vertex, Edge>::new();
populate_graph(&mut graph);
// Demonstrate that boxed walkers work identically to unboxed ones
let unboxed: Vec<_> = graph
.walk()
.vertices(VertexSearch::scan())
.edges(EdgeSearch::scan())
.head()
.collect();
let boxed: Vec<_> = graph
.walk()
.vertices(VertexSearch::scan())
.edges(EdgeSearch::scan())
.boxed()
.head()
.collect();
// Results should be identical (ignoring potential order differences)
assert_eq!(unboxed.len(), boxed.len());
}
}