lazy_evaluation/
lazy_evaluation.rs1use rust_queries_builder::LazyQuery;
7use key_paths_derive::Keypaths;
8use std::sync::atomic::{AtomicUsize, Ordering};
9
10static FILTER_EVALUATIONS: AtomicUsize = AtomicUsize::new(0);
12static EXPENSIVE_OPERATIONS: AtomicUsize = AtomicUsize::new(0);
13
14#[derive(Debug, Clone, Keypaths)]
15struct Product {
16 id: u32,
17 name: String,
18 price: f64,
19 category: String,
20 stock: u32,
21}
22
23fn create_products() -> Vec<Product> {
24 (1..=1000)
25 .map(|i| Product {
26 id: i,
27 name: format!("Product {}", i),
28 price: (i as f64 * 10.0) % 1000.0,
29 category: if i % 3 == 0 {
30 "Electronics".to_string()
31 } else if i % 3 == 1 {
32 "Furniture".to_string()
33 } else {
34 "Clothing".to_string()
35 },
36 stock: i % 50,
37 })
38 .collect()
39}
40
41fn expensive_check(value: &f64) -> bool {
42 EXPENSIVE_OPERATIONS.fetch_add(1, Ordering::SeqCst);
43 value > &100.0
45}
46
47fn main() {
48 println!("\n╔════════════════════════════════════════════════════════════════╗");
49 println!("║ Lazy Query Evaluation Demo ║");
50 println!("╚════════════════════════════════════════════════════════════════╝\n");
51
52 let products = create_products();
53 println!("Created {} products\n", products.len());
54
55 println!("═══════════════════════════════════════════════════════════════");
59 println!("Demo 1: Lazy execution - deferred until needed");
60 println!("═══════════════════════════════════════════════════════════════\n");
61
62 FILTER_EVALUATIONS.store(0, Ordering::SeqCst);
63
64 println!("Building query (should execute nothing)...");
65 let lazy_query = LazyQuery::new(&products)
66 .where_(Product::category_r(), |cat| {
67 FILTER_EVALUATIONS.fetch_add(1, Ordering::SeqCst);
68 cat == "Electronics"
69 });
70
71 let evals_after_build = FILTER_EVALUATIONS.load(Ordering::SeqCst);
72 println!(" Filter evaluations after building query: {}", evals_after_build);
73
74 if evals_after_build == 0 {
75 println!(" ✅ Confirmed: Query is lazy! Nothing executed yet.\n");
76 }
77
78 println!("Collecting results (now it executes)...");
79 let results: Vec<_> = lazy_query.collect();
80
81 let evals_after_collect = FILTER_EVALUATIONS.load(Ordering::SeqCst);
82 println!(" Filter evaluations after collecting: {}", evals_after_collect);
83 println!(" Results found: {}", results.len());
84 println!(" ✅ Query executed exactly once, when needed!\n");
85
86 println!("═══════════════════════════════════════════════════════════════");
90 println!("Demo 2: Early termination with .take()");
91 println!("═══════════════════════════════════════════════════════════════\n");
92
93 EXPENSIVE_OPERATIONS.store(0, Ordering::SeqCst);
94
95 println!("Finding first 5 expensive items from 1000 products...");
96 let first_5: Vec<_> = LazyQuery::new(&products)
97 .where_(Product::price_r(), |p| expensive_check(p))
98 .take_lazy(5)
99 .collect();
100
101 let ops = EXPENSIVE_OPERATIONS.load(Ordering::SeqCst);
102 println!(" Found: {} items", first_5.len());
103 println!(" Expensive operations performed: {}", ops);
104 println!(" Items NOT checked: {} (stopped early!)", 1000 - ops);
105
106 if ops < 1000 {
107 println!(" ✅ Early termination worked! Didn't check all 1000 items.\n");
108 }
109
110 println!("═══════════════════════════════════════════════════════════════");
114 println!("Demo 3: Iterator fusion - chained operations optimized");
115 println!("═══════════════════════════════════════════════════════════════\n");
116
117 println!("Chaining multiple operations...");
118 let chained_query = LazyQuery::new(&products)
119 .where_(Product::category_r(), |cat| cat == "Electronics")
120 .where_(Product::price_r(), |&price| price > 200.0)
121 .where_(Product::stock_r(), |&stock| stock > 10)
122 .take_lazy(10);
123
124 println!(" Built query with 3 filters + take(10)");
125 println!(" ✅ No execution yet - all operations fused into one iterator\n");
126
127 let results: Vec<_> = chained_query.collect();
128 println!(" Executed: Found {} items", results.len());
129 println!(" ✅ All filters applied in single pass!\n");
130
131 println!("═══════════════════════════════════════════════════════════════");
135 println!("Demo 4: Lazy projection");
136 println!("═══════════════════════════════════════════════════════════════\n");
137
138 println!("Selecting names (lazy)...");
139 let names: Vec<String> = LazyQuery::new(&products)
140 .where_(Product::category_r(), |cat| cat == "Electronics")
141 .select_lazy(Product::name_r())
142 .take(5) .collect();
144
145 println!(" Selected {} names", names.len());
146 println!(" ✅ Only evaluated until 5 names found!\n");
147
148 println!("═══════════════════════════════════════════════════════════════");
152 println!("Demo 5: Short-circuit with .any()");
153 println!("═══════════════════════════════════════════════════════════════\n");
154
155 FILTER_EVALUATIONS.store(0, Ordering::SeqCst);
156
157 println!("Checking if ANY electronics exist (1000 items to search)...");
158 let exists = LazyQuery::new(&products)
159 .where_(Product::category_r(), |cat| {
160 FILTER_EVALUATIONS.fetch_add(1, Ordering::SeqCst);
161 cat == "Electronics"
162 })
163 .any();
164
165 let checks = FILTER_EVALUATIONS.load(Ordering::SeqCst);
166 println!(" Result: {}", exists);
167 println!(" Items checked: {} out of 1000", checks);
168 println!(" Items skipped: {} (short-circuited!)", 1000 - checks);
169
170 if checks < 1000 {
171 println!(" ✅ Short-circuit worked! Stopped as soon as first match found.\n");
172 }
173
174 println!("═══════════════════════════════════════════════════════════════");
178 println!("Demo 6: .find() stops at first match");
179 println!("═══════════════════════════════════════════════════════════════\n");
180
181 FILTER_EVALUATIONS.store(0, Ordering::SeqCst);
182
183 println!("Finding first product with price > 500...");
184 let found = LazyQuery::new(&products)
185 .where_(Product::price_r(), |&price| {
186 FILTER_EVALUATIONS.fetch_add(1, Ordering::SeqCst);
187 price > 500.0
188 })
189 .first();
190
191 let checks = FILTER_EVALUATIONS.load(Ordering::SeqCst);
192 if let Some(product) = found {
193 println!(" Found: {} (${:.2})", product.name, product.price);
194 }
195 println!(" Items checked: {} out of 1000", checks);
196 println!(" ✅ Stopped immediately after finding first match!\n");
197
198 println!("═══════════════════════════════════════════════════════════════");
202 println!("Demo 7: Composable queries");
203 println!("═══════════════════════════════════════════════════════════════\n");
204
205 println!("Building base query...");
206 let base_query = LazyQuery::new(&products)
207 .where_(Product::category_r(), |cat| cat == "Electronics");
208
209 println!(" Created base query (not executed)\n");
210
211 println!(" Adding price filter...");
212 let refined_query = base_query
213 .where_(Product::price_r(), |&price| price > 100.0);
214
215 println!(" Still not executed...\n");
216
217 println!(" Adding stock filter and limiting...");
218 let final_query = refined_query
219 .where_(Product::stock_r(), |&stock| stock > 5)
220 .take_lazy(10);
221
222 println!(" Still not executed...\n");
223
224 println!(" Executing...");
225 let results: Vec<_> = final_query.collect();
226 println!(" ✅ Executed once with all filters: Found {} items\n", results.len());
227
228 println!("═══════════════════════════════════════════════════════════════");
232 println!("Demo 8: Use in for loops");
233 println!("═══════════════════════════════════════════════════════════════\n");
234
235 println!("Iterating over filtered products...");
236 let mut count = 0;
237 for product in LazyQuery::new(&products)
238 .where_(Product::category_r(), |cat| cat == "Electronics")
239 .take_lazy(3)
240 {
241 println!(" • {}: ${:.2}", product.name, product.price);
242 count += 1;
243 }
244 println!(" ✅ Processed {} items lazily\n", count);
245
246 println!("═══════════════════════════════════════════════════════════════");
250 println!("Demo 9: Performance benefit demonstration");
251 println!("═══════════════════════════════════════════════════════════════\n");
252
253 println!("Scenario: Find first expensive item from 1000 products\n");
254
255 EXPENSIVE_OPERATIONS.store(0, Ordering::SeqCst);
256
257 println!("Without lazy (hypothetical - check all, then take first):");
258 println!(" Would check: 1000 items");
259 println!(" Would find: ~300 matching items");
260 println!(" Would return: 1 item");
261 println!(" Wasted work: 299 items processed unnecessarily\n");
262
263 EXPENSIVE_OPERATIONS.store(0, Ordering::SeqCst);
264
265 println!("With lazy evaluation:");
266 let _first = LazyQuery::new(&products)
267 .where_(Product::price_r(), |p| expensive_check(p))
268 .first();
269
270 let ops = EXPENSIVE_OPERATIONS.load(Ordering::SeqCst);
271 println!(" Checked: {} items", ops);
272 println!(" Found: 1 item");
273 println!(" Wasted work: 0 items");
274 println!(" ✅ Efficiency gain: {}x faster!", 1000 / ops.max(1));
275
276 println!("\n╔════════════════════════════════════════════════════════════════╗");
280 println!("║ Lazy Evaluation Benefits ║");
281 println!("╚════════════════════════════════════════════════════════════════╝\n");
282
283 println!("✅ Deferred Execution:");
284 println!(" • No work until results needed");
285 println!(" • Can build complex queries without performance cost\n");
286
287 println!("✅ Early Termination:");
288 println!(" • .take(n) stops after n items");
289 println!(" • .first() stops after 1 item");
290 println!(" • .any() stops after first match");
291 println!(" • Massive performance win for large datasets\n");
292
293 println!("✅ Iterator Fusion:");
294 println!(" • Multiple filters combined into one pass");
295 println!(" • Rust compiler optimizes chained operations");
296 println!(" • No intermediate allocations\n");
297
298 println!("✅ Composable:");
299 println!(" • Build queries incrementally");
300 println!(" • Reuse query fragments");
301 println!(" • Clean separation of query building vs execution\n");
302
303 println!("✅ Zero Overhead:");
304 println!(" • Compiles to same code as manual loops");
305 println!(" • No runtime cost for abstraction");
306 println!(" • Pay only for what you use\n");
307
308 println!("✓ Lazy evaluation demo complete!\n");
309}
310