arc_rwlock_hashmap/
arc_rwlock_hashmap.rs

1// Demonstrates querying HashMap<String, Arc<RwLock<Product>>>
2// This is a common pattern for thread-safe shared data
3// Shows all lazy query operations
4// cargo run --example arc_rwlock_hashmap
5
6use rust_queries_builder::LazyQuery;
7use key_paths_derive::Keypaths;
8use std::collections::HashMap;
9use std::sync::{Arc, RwLock};
10
11#[derive(Debug, Clone, Keypaths)]
12struct Product {
13    id: u32,
14    name: String,
15    price: f64,
16    category: String,
17    stock: u32,
18    rating: f64,
19    active: bool,
20}
21
22type ProductId = String;
23type SharedProduct = Arc<RwLock<Product>>;
24type ProductMap = HashMap<ProductId, SharedProduct>;
25
26fn create_sample_data() -> ProductMap {
27    let mut map = HashMap::new();
28
29    let products = vec![
30        Product { id: 1, name: "Laptop Pro".to_string(), price: 1299.99, category: "Electronics".to_string(), stock: 15, rating: 4.8, active: true },
31        Product { id: 2, name: "Wireless Mouse".to_string(), price: 29.99, category: "Electronics".to_string(), stock: 50, rating: 4.5, active: true },
32        Product { id: 3, name: "Mechanical Keyboard".to_string(), price: 129.99, category: "Electronics".to_string(), stock: 30, rating: 4.7, active: true },
33        Product { id: 4, name: "Office Chair".to_string(), price: 299.99, category: "Furniture".to_string(), stock: 20, rating: 4.6, active: true },
34        Product { id: 5, name: "Standing Desk".to_string(), price: 499.99, category: "Furniture".to_string(), stock: 10, rating: 4.9, active: true },
35        Product { id: 6, name: "USB-C Hub".to_string(), price: 49.99, category: "Electronics".to_string(), stock: 100, rating: 4.3, active: true },
36        Product { id: 7, name: "Monitor 27\"".to_string(), price: 349.99, category: "Electronics".to_string(), stock: 25, rating: 4.7, active: true },
37        Product { id: 8, name: "Desk Lamp".to_string(), price: 39.99, category: "Furniture".to_string(), stock: 40, rating: 4.2, active: true },
38        Product { id: 9, name: "Webcam HD".to_string(), price: 79.99, category: "Electronics".to_string(), stock: 35, rating: 4.4, active: true },
39        Product { id: 10, name: "Bookshelf".to_string(), price: 149.99, category: "Furniture".to_string(), stock: 15, rating: 4.5, active: false },
40    ];
41
42    for product in products {
43        let id = format!("PROD-{:03}", product.id);
44        map.insert(id, Arc::new(RwLock::new(product)));
45    }
46
47    map
48}
49
50// Helper to extract products from Arc<RwLock<Product>> for querying
51fn extract_products(map: &ProductMap) -> Vec<Product> {
52    map.values()
53        .filter_map(|arc_lock| {
54            arc_lock.read().ok().map(|guard| guard.clone())
55        })
56        .collect()
57}
58
59fn main() {
60    println!("\n╔══════════════════════════════════════════════════════════════════╗");
61    println!("║  Arc<RwLock<T>> HashMap Lazy Query Demo                         ║");
62    println!("║  Thread-safe shared data with lazy evaluation                   ║");
63    println!("╚══════════════════════════════════════════════════════════════════╝\n");
64
65    let product_map = create_sample_data();
66    println!("Created product catalog:");
67    println!("  Total products: {}", product_map.len());
68    println!("  Keys: {:?}\n", product_map.keys().take(3).collect::<Vec<_>>());
69
70    // Extract products for querying
71    let products = extract_products(&product_map);
72    println!("Extracted {} products from Arc<RwLock<Product>>\n", products.len());
73
74    // ============================================================================
75    // LAZY OPERATION 1: where_ - Lazy Filtering
76    // ============================================================================
77    println!("═══════════════════════════════════════════════════════════════");
78    println!("Lazy Operation 1: where_ (filtering)");
79    println!("═══════════════════════════════════════════════════════════════\n");
80
81    println!("Building filtered query (nothing executes yet)...");
82    let electronics_query = LazyQuery::new(&products)
83        .where_(Product::category_r(), |cat| cat == "Electronics")
84        .where_(Product::active_r(), |&active| active)
85        .where_(Product::stock_r(), |&stock| stock > 20);
86
87    println!("  ✅ Query built (deferred execution)\n");
88
89    println!("Collecting results (executes now)...");
90    let electronics: Vec<_> = electronics_query.collect();
91    println!("  Found {} electronics in stock", electronics.len());
92    for p in &electronics {
93        println!("    • {}: {} in stock", p.name, p.stock);
94    }
95
96    // ============================================================================
97    // LAZY OPERATION 2: select_lazy - Lazy Projection
98    // ============================================================================
99    println!("\n═══════════════════════════════════════════════════════════════");
100    println!("Lazy Operation 2: select_lazy (projection)");
101    println!("═══════════════════════════════════════════════════════════════\n");
102
103    println!("Selecting product names (lazy)...");
104    let names: Vec<String> = LazyQuery::new(&products)
105        .where_(Product::category_r(), |cat| cat == "Furniture")
106        .select_lazy(Product::name_r())
107        .collect();
108
109    println!("  Furniture names ({}):", names.len());
110    for name in &names {
111        println!("    • {}", name);
112    }
113
114    // ============================================================================
115    // LAZY OPERATION 3: take_lazy - Early Termination
116    // ============================================================================
117    println!("\n═══════════════════════════════════════════════════════════════");
118    println!("Lazy Operation 3: take_lazy (early termination)");
119    println!("═══════════════════════════════════════════════════════════════\n");
120
121    println!("Getting first 3 electronics...");
122    let first_3: Vec<_> = LazyQuery::new(&products)
123        .where_(Product::category_r(), |cat| cat == "Electronics")
124        .take_lazy(3)
125        .collect();
126
127    println!("  First 3 electronics:");
128    for (i, p) in first_3.iter().enumerate() {
129        println!("    {}. {} - ${:.2}", i + 1, p.name, p.price);
130    }
131    println!("  ✅ Stopped after finding 3 items!");
132
133    // ============================================================================
134    // LAZY OPERATION 4: skip_lazy - Pagination
135    // ============================================================================
136    println!("\n═══════════════════════════════════════════════════════════════");
137    println!("Lazy Operation 4: skip_lazy (pagination)");
138    println!("═══════════════════════════════════════════════════════════════\n");
139
140    println!("Getting page 2 (skip 3, take 3)...");
141    let page_2: Vec<_> = LazyQuery::new(&products)
142        .where_(Product::active_r(), |&active| active)
143        .skip_lazy(3)
144        .take_lazy(3)
145        .collect();
146
147    println!("  Page 2 items:");
148    for (i, p) in page_2.iter().enumerate() {
149        println!("    {}. {}", i + 4, p.name);
150    }
151
152    // ============================================================================
153    // LAZY OPERATION 5: first - Short-Circuit Search
154    // ============================================================================
155    println!("\n═══════════════════════════════════════════════════════════════");
156    println!("Lazy Operation 5: first (short-circuit)");
157    println!("═══════════════════════════════════════════════════════════════\n");
158
159    println!("Finding first expensive item (>$1000)...");
160    let expensive = LazyQuery::new(&products)
161        .where_(Product::price_r(), |&price| price > 1000.0)
162        .first();
163
164    match expensive {
165        Some(p) => println!("  Found: {} - ${:.2}", p.name, p.price),
166        None => println!("  Not found"),
167    }
168    println!("  ✅ Stopped at first match!");
169
170    // ============================================================================
171    // LAZY OPERATION 6: any - Existence Check
172    // ============================================================================
173    println!("\n═══════════════════════════════════════════════════════════════");
174    println!("Lazy Operation 6: any (existence check)");
175    println!("═══════════════════════════════════════════════════════════════\n");
176
177    println!("Checking if any furniture exists...");
178    let has_furniture = LazyQuery::new(&products)
179        .where_(Product::category_r(), |cat| cat == "Furniture")
180        .any();
181
182    println!("  Has furniture: {}", has_furniture);
183    println!("  ✅ Stopped immediately after finding first match!");
184
185    // ============================================================================
186    // LAZY OPERATION 7: count - Count Matching Items
187    // ============================================================================
188    println!("\n═══════════════════════════════════════════════════════════════");
189    println!("Lazy Operation 7: count");
190    println!("═══════════════════════════════════════════════════════════════\n");
191
192    let electronics_count = LazyQuery::new(&products)
193        .where_(Product::category_r(), |cat| cat == "Electronics")
194        .count();
195
196    println!("  Electronics count: {}", electronics_count);
197
198    // ============================================================================
199    // LAZY OPERATION 8: sum_by - Aggregation
200    // ============================================================================
201    println!("\n═══════════════════════════════════════════════════════════════");
202    println!("Lazy Operation 8: sum_by (aggregation)");
203    println!("═══════════════════════════════════════════════════════════════\n");
204
205    let total_value: f64 = LazyQuery::new(&products)
206        .where_(Product::category_r(), |cat| cat == "Electronics")
207        .sum_by(Product::price_r());
208
209    println!("  Total electronics value: ${:.2}", total_value);
210
211    // ============================================================================
212    // LAZY OPERATION 9: avg_by - Average
213    // ============================================================================
214    println!("\n═══════════════════════════════════════════════════════════════");
215    println!("Lazy Operation 9: avg_by");
216    println!("═══════════════════════════════════════════════════════════════\n");
217
218    let avg_price = LazyQuery::new(&products)
219        .where_(Product::category_r(), |cat| cat == "Furniture")
220        .avg_by(Product::price_r())
221        .unwrap_or(0.0);
222
223    println!("  Average furniture price: ${:.2}", avg_price);
224
225    // ============================================================================
226    // LAZY OPERATION 10: min_by_float / max_by_float
227    // ============================================================================
228    println!("\n═══════════════════════════════════════════════════════════════");
229    println!("Lazy Operation 10: min_by_float / max_by_float");
230    println!("═══════════════════════════════════════════════════════════════\n");
231
232    let min_price = LazyQuery::new(&products)
233        .where_(Product::active_r(), |&active| active)
234        .min_by_float(Product::price_r())
235        .unwrap_or(0.0);
236
237    let max_price = LazyQuery::new(&products)
238        .where_(Product::active_r(), |&active| active)
239        .max_by_float(Product::price_r())
240        .unwrap_or(0.0);
241
242    println!("  Price range for active products:");
243    println!("    Min: ${:.2}", min_price);
244    println!("    Max: ${:.2}", max_price);
245
246    // ============================================================================
247    // LAZY OPERATION 11: find - Find with Predicate
248    // ============================================================================
249    println!("\n═══════════════════════════════════════════════════════════════");
250    println!("Lazy Operation 11: find (with predicate)");
251    println!("═══════════════════════════════════════════════════════════════\n");
252
253    let high_rated = LazyQuery::new(&products)
254        .where_(Product::category_r(), |cat| cat == "Electronics")
255        .find(|item| item.rating > 4.7);
256
257    if let Some(product) = high_rated {
258        println!("  First highly-rated electronic:");
259        println!("    {}: Rating {:.1}", product.name, product.rating);
260    }
261
262    // ============================================================================
263    // LAZY OPERATION 12: for_each - Iteration
264    // ============================================================================
265    println!("\n═══════════════════════════════════════════════════════════════");
266    println!("Lazy Operation 12: for_each (iteration)");
267    println!("═══════════════════════════════════════════════════════════════\n");
268
269    println!("  Low stock alerts:");
270    LazyQuery::new(&products)
271        .where_(Product::stock_r(), |&stock| stock < 20)
272        .for_each(|product| {
273            println!("    ⚠️  {}: Only {} in stock", product.name, product.stock);
274        });
275
276    // ============================================================================
277    // LAZY OPERATION 13: fold - Custom Aggregation
278    // ============================================================================
279    println!("\n═══════════════════════════════════════════════════════════════");
280    println!("Lazy Operation 14: fold (custom aggregation)");
281    println!("═══════════════════════════════════════════════════════════════\n");
282
283    let total_inventory_value = LazyQuery::new(&products)
284        .where_(Product::active_r(), |&active| active)
285        .fold(0.0, |acc, product| {
286            acc + (product.price * product.stock as f64)
287        });
288
289    println!("  Total inventory value: ${:.2}", total_inventory_value);
290
291    // ============================================================================
292    // LAZY OPERATION 14: all_match - Validation
293    // ============================================================================
294    println!("\n═══════════════════════════════════════════════════════════════");
295    println!("Lazy Operation 15: all_match (validation)");
296    println!("═══════════════════════════════════════════════════════════════\n");
297
298    let all_priced = LazyQuery::new(&products)
299        .all_match(|item| item.price > 0.0);
300
301    println!("  All products have valid prices: {}", all_priced);
302
303    // ============================================================================
304    // LAZY OPERATION 15: into_iter - For Loop
305    // ============================================================================
306    println!("\n═══════════════════════════════════════════════════════════════");
307    println!("Lazy Operation 16: into_iter (for loop)");
308    println!("═══════════════════════════════════════════════════════════════\n");
309
310    println!("  High-value products (>$300):");
311    for product in LazyQuery::new(&products)
312        .where_(Product::price_r(), |&p| p > 300.0)
313        .take_lazy(5)
314    {
315        println!("    • {}: ${:.2}", product.name, product.price);
316    }
317
318    // ============================================================================
319    // LAZY OPERATION 16: map_items - Transform
320    // ============================================================================
321    println!("\n═══════════════════════════════════════════════════════════════");
322    println!("Lazy Operation 17: map_items (transformation)");
323    println!("═══════════════════════════════════════════════════════════════\n");
324
325    let price_tags: Vec<String> = LazyQuery::new(&products)
326        .where_(Product::category_r(), |cat| cat == "Electronics")
327        .map_items(|p| format!("{}: ${:.2}", p.name, p.price))
328        .take(5)
329        .collect();
330
331    println!("  Electronics price tags:");
332    for tag in &price_tags {
333        println!("    • {}", tag);
334    }
335
336    // ============================================================================
337    // COMPLEX EXAMPLE: Multi-Stage Lazy Pipeline
338    // ============================================================================
339    println!("\n═══════════════════════════════════════════════════════════════");
340    println!("Complex Example: Multi-stage lazy pipeline");
341    println!("═══════════════════════════════════════════════════════════════\n");
342
343    println!("Building complex query:");
344    println!("  1. Filter by category (Electronics)");
345    println!("  2. Filter by price range ($50-$500)");
346    println!("  3. Filter by rating (>4.5)");
347    println!("  4. Select names");
348    println!("  5. Take first 3");
349    println!();
350
351    let results: Vec<String> = LazyQuery::new(&products)
352        .where_(Product::category_r(), |cat| cat == "Electronics")
353        .where_(Product::price_r(), |&p| p >= 50.0 && p <= 500.0)
354        .where_(Product::rating_r(), |&r| r > 4.5)
355        .select_lazy(Product::name_r())
356        .take(3)
357        .collect();
358
359    println!("  Results:");
360    for (i, name) in results.iter().enumerate() {
361        println!("    {}. {}", i + 1, name);
362    }
363    println!("  ✅ All operations fused and executed lazily!");
364
365    // ============================================================================
366    // THREAD-SAFE UPDATES WITH RWLOCK
367    // ============================================================================
368    println!("\n═══════════════════════════════════════════════════════════════");
369    println!("Bonus: Thread-safe updates with RwLock");
370    println!("═══════════════════════════════════════════════════════════════\n");
371
372    // Update a product through the Arc<RwLock>
373    if let Some(product_arc) = product_map.get("PROD-002") {
374        println!("Updating PROD-002 stock...");
375        
376        // Write lock for mutation
377        if let Ok(mut product) = product_arc.write() {
378            let old_stock = product.stock;
379            product.stock = 25;
380            println!("  Stock updated: {} → {}", old_stock, product.stock);
381        }
382    }
383
384    // Query again to see the update
385    let updated_products = extract_products(&product_map);
386    let mouse = LazyQuery::new(&updated_products)
387        .find(|p| p.id == 2);
388
389    if let Some(product) = mouse {
390        println!("  Verified update: {} now has {} in stock", product.name, product.stock);
391    }
392
393    // ============================================================================
394    // PRACTICAL EXAMPLE: Price Analysis by Category
395    // ============================================================================
396    println!("\n═══════════════════════════════════════════════════════════════");
397    println!("Practical Example: Price analysis by category");
398    println!("═══════════════════════════════════════════════════════════════\n");
399
400    let categories = vec!["Electronics", "Furniture"];
401
402    for category in categories {
403        println!("  {} Statistics:", category);
404        
405        // Filter products by category first
406        let cat_products: Vec<Product> = products.iter()
407            .filter(|p| p.category == category)
408            .cloned()
409            .collect();
410
411        let count = LazyQuery::new(&cat_products).count();
412        let total = LazyQuery::new(&cat_products).sum_by(Product::price_r());
413        let avg = LazyQuery::new(&cat_products).avg_by(Product::price_r()).unwrap_or(0.0);
414        let min = LazyQuery::new(&cat_products).min_by_float(Product::price_r()).unwrap_or(0.0);
415        let max = LazyQuery::new(&cat_products).max_by_float(Product::price_r()).unwrap_or(0.0);
416
417        println!("    Count: {}", count);
418        println!("    Total: ${:.2}", total);
419        println!("    Average: ${:.2}", avg);
420        println!("    Range: ${:.2} - ${:.2}\n", min, max);
421    }
422
423    // ============================================================================
424    // COMBINING WITH HASHMAP OPERATIONS
425    // ============================================================================
426    println!("═══════════════════════════════════════════════════════════════");
427    println!("HashMap Integration: Query by key patterns");
428    println!("═══════════════════════════════════════════════════════════════\n");
429
430    // Filter HashMap by key pattern
431    let electronics_keys: Vec<String> = product_map
432        .iter()
433        .filter(|(_key, value)| {
434            // Read the value to check category
435            if let Ok(guard) = value.read() {
436                guard.category == "Electronics"
437            } else {
438                false
439            }
440        })
441        .map(|(key, _value)| key.clone())
442        .collect();
443
444    println!("  Electronics product IDs:");
445    for key in electronics_keys.iter().take(5) {
446        println!("    • {}", key);
447    }
448
449    // ============================================================================
450    // PERFORMANCE DEMONSTRATION
451    // ============================================================================
452    println!("\n═══════════════════════════════════════════════════════════════");
453    println!("Performance: Lazy vs Eager comparison");
454    println!("═══════════════════════════════════════════════════════════════\n");
455
456    println!("Scenario: Find first product with rating > 4.7 from {} products\n", products.len());
457
458    println!("  Eager approach (hypothetical):");
459    println!("    - Filter all {} products", products.len());
460    println!("    - Collect filtered results");
461    println!("    - Take first item");
462    println!("    - Wasted work: Check all items\n");
463
464    println!("  Lazy approach (actual):");
465    let _first_rated = LazyQuery::new(&products)
466        .where_(Product::rating_r(), |&r| r > 4.7)
467        .first();
468    println!("    - Starts checking products");
469    println!("    - Stops at first match");
470    println!("    - ✅ Early termination - checks ~3-5 items only!");
471
472    // ============================================================================
473    // Summary
474    // ============================================================================
475    println!("\n╔══════════════════════════════════════════════════════════════════╗");
476    println!("║  Summary: All Lazy Operations Demonstrated                      ║");
477    println!("╚══════════════════════════════════════════════════════════════════╝\n");
478
479    println!("✅ Lazy Query Operations:");
480    println!("   1. ✅ where_ - Lazy filtering");
481    println!("   2. ✅ select_lazy - Lazy projection");
482    println!("   3. ✅ take_lazy - Early termination");
483    println!("   4. ✅ skip_lazy - Pagination");
484    println!("   5. ✅ first - Short-circuit search");
485    println!("   6. ✅ any - Existence check (short-circuit)");
486    println!("   7. ✅ count - Count items");
487    println!("   8. ✅ sum_by - Sum aggregation");
488    println!("   9. ✅ avg_by - Average aggregation");
489    println!("   10. ✅ min_by_float - Minimum value");
490    println!("   11. ✅ max_by_float - Maximum value");
491    println!("   12. ✅ find - Find with predicate (short-circuit)");
492    println!("   13. ✅ for_each - Iteration");
493    println!("   14. ✅ fold - Custom aggregation");
494    println!("   15. ✅ all_match - Validation (short-circuit)");
495    println!("   16. ✅ into_iter - For loop support");
496    println!("   17. ✅ map_items - Transformation\n");
497
498    println!("✅ Arc<RwLock<T>> Benefits:");
499    println!("   • Thread-safe shared access");
500    println!("   • Interior mutability");
501    println!("   • Multiple readers, single writer");
502    println!("   • Reference counting (Arc)");
503    println!("   • Can be queried after extracting data\n");
504
505    println!("✅ HashMap<K, Arc<RwLock<V>>> Benefits:");
506    println!("   • Fast key-based lookup");
507    println!("   • Thread-safe value access");
508    println!("   • Can query all values");
509    println!("   • Can filter by key patterns");
510    println!("   • Perfect for shared state/caches\n");
511
512    println!("🎯 Use Cases:");
513    println!("   • Shared product catalogs");
514    println!("   • User session stores");
515    println!("   • Configuration caches");
516    println!("   • Real-time inventory systems");
517    println!("   • Multi-threaded data processing");
518    println!("   • Web server state management\n");
519
520    println!("✓ Arc<RwLock<T>> HashMap with all lazy operations demo complete!\n");
521}
522