Skip to main content

predicate_demo/
predicate_demo.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10
11//! Comprehensive demonstration of the Predicate abstraction.
12//!
13//! This example shows:
14//! - Basic predicate usage with closures
15//! - BoxPredicate for single-ownership scenarios
16//! - RcPredicate for single-threaded reuse
17//! - ArcPredicate for multi-threaded scenarios
18//! - Logical composition (AND, OR, NOT)
19//! - Interior mutability patterns
20//! - Type conversions
21
22use qubit_function::{
23    ArcPredicate,
24    BoxPredicate,
25    FnPredicateOps,
26    Predicate,
27    RcPredicate,
28};
29use std::cell::RefCell;
30use std::collections::HashMap;
31use std::sync::{
32    Arc,
33    Mutex,
34};
35
36fn main() {
37    println!("=== Predicate Usage Examples ===\n");
38
39    basic_closure_predicates();
40    println!();
41
42    box_predicate_examples();
43    println!();
44
45    rc_predicate_examples();
46    println!();
47
48    arc_predicate_examples();
49    println!();
50
51    logical_composition_examples();
52    println!();
53
54    interior_mutability_examples();
55    println!();
56
57    practical_use_cases();
58}
59
60/// Basic closure predicate usage
61fn basic_closure_predicates() {
62    println!("--- 1. Basic Closure Predicate Usage ---");
63
64    // Simple closure predicate
65    let is_positive = |x: &i32| *x > 0;
66    println!("Is 5 positive? {}", is_positive.test(&5));
67    println!("Is -3 positive? {}", is_positive.test(&-3));
68
69    // Combining closures
70    let is_even = |x: &i32| x % 2 == 0;
71    let is_positive_and_even = is_positive.and(is_even);
72    println!("Is 4 positive and even? {}", is_positive_and_even.test(&4));
73    println!("Is 5 positive and even? {}", is_positive_and_even.test(&5));
74
75    // Using predicates with iterators
76    let numbers = [-2, -1, 0, 1, 2, 3, 4, 5];
77    let positives: Vec<_> = numbers.iter().filter(|x| is_positive.test(x)).copied().collect();
78    println!("Positive numbers: {:?}", positives);
79}
80
81/// BoxPredicate examples - single ownership
82fn box_predicate_examples() {
83    println!("--- 2. BoxPredicate Examples (Single Ownership) ---");
84
85    // Basic BoxPredicate
86    let pred = BoxPredicate::new(|x: &i32| *x > 0);
87    println!("BoxPredicate test 5: {}", pred.test(&5));
88
89    // Named predicate for better debugging
90    let named_pred = BoxPredicate::new_with_name("is_positive_even", |x: &i32| *x > 0 && x % 2 == 0);
91    println!("Predicate name: {:?}", named_pred.name());
92    println!("Test 4: {}", named_pred.test(&4));
93
94    // Method chaining - consumes self
95    let positive = BoxPredicate::new_with_name("positive", |x: &i32| *x > 0);
96    let even = BoxPredicate::new_with_name("even", |x: &i32| x % 2 == 0);
97    let combined = positive.and(even);
98    println!("Combined predicate name: {:?}", combined.name());
99    println!("Test 4: {}", combined.test(&4));
100}
101
102/// RcPredicate examples - single-threaded reuse
103fn rc_predicate_examples() {
104    println!("--- 3. RcPredicate Examples (Single-threaded Reuse) ---");
105
106    let is_positive = RcPredicate::new(|x: &i32| *x > 0);
107    let is_even = RcPredicate::new(|x: &i32| x % 2 == 0);
108
109    // Multiple compositions without consuming the original
110    let positive_and_even = is_positive.and(is_even.clone());
111    let positive_or_even = is_positive.or(is_even.clone());
112
113    println!("Original predicates still available:");
114    println!("  is_positive.test(&5) = {}", is_positive.test(&5));
115    println!("  is_even.test(&4) = {}", is_even.test(&4));
116
117    println!("Combined predicates:");
118    println!("  positive_and_even.test(&4) = {}", positive_and_even.test(&4));
119    println!("  positive_or_even.test(&5) = {}", positive_or_even.test(&5));
120
121    // Cloning
122    let cloned = is_positive.clone();
123    println!("Cloned predicate: {}", cloned.test(&10));
124}
125
126/// ArcPredicate examples - multi-threaded scenarios
127fn arc_predicate_examples() {
128    println!("--- 4. ArcPredicate Examples (Multi-threaded Scenarios) ---");
129
130    let is_positive = ArcPredicate::new(|x: &i32| *x > 0);
131    let is_even = ArcPredicate::new(|x: &i32| x % 2 == 0);
132
133    // Create combined predicate
134    let combined = is_positive.and(is_even);
135
136    // Use in multiple threads
137    let handles: Vec<_> = (0..3)
138        .map(|i| {
139            let pred = combined.clone();
140            std::thread::spawn(move || {
141                let value = i * 2;
142                println!("  Thread {} testing {}: {}", i, value, pred.test(&value));
143            })
144        })
145        .collect();
146
147    for handle in handles {
148        handle.join().expect("thread should not panic");
149    }
150
151    // Original predicates still usable
152    println!("Original predicates still available in main thread:");
153    println!("  is_positive.test(&5) = {}", is_positive.test(&5));
154}
155
156/// Logical composition examples
157fn logical_composition_examples() {
158    println!("--- 5. Logical Composition Examples ---");
159
160    let positive = RcPredicate::new_with_name("positive", |x: &i32| *x > 0);
161    let even = RcPredicate::new_with_name("even", |x: &i32| x % 2 == 0);
162    let less_than_ten = RcPredicate::new_with_name("less_than_ten", |x: &i32| *x < 10);
163
164    // AND composition
165    let positive_and_even = positive.and(even.clone());
166    println!("positive AND even: name={:?}", positive_and_even.name());
167    println!("  Test 4: {}", positive_and_even.test(&4));
168    println!("  Test 5: {}", positive_and_even.test(&5));
169
170    // OR composition
171    let positive_or_even = positive.or(even.clone());
172    println!("positive OR even: name={:?}", positive_or_even.name());
173    println!("  Test -2: {}", positive_or_even.test(&-2));
174    println!("  Test 5: {}", positive_or_even.test(&5));
175
176    // NOT composition
177    let not_positive = !&positive;
178    println!("NOT positive: name={:?}", not_positive.name());
179    println!("  Test 5: {}", not_positive.test(&5));
180    println!("  Test -3: {}", not_positive.test(&-3));
181
182    // NAND composition
183    let nand = positive.nand(even.clone());
184    println!("positive NAND even: name={:?}", nand.name());
185    println!("  Test 3: {}", nand.test(&3)); // true NAND false = true
186    println!("  Test 4: {}", nand.test(&4)); // true NAND true = false
187
188    // XOR composition
189    let xor = positive.xor(even.clone());
190    println!("positive XOR even: name={:?}", xor.name());
191    println!("  Test 3: {}", xor.test(&3)); // true XOR false = true
192    println!("  Test 4: {}", xor.test(&4)); // true XOR true = false
193    println!("  Test -2: {}", xor.test(&-2)); // false XOR true = true
194
195    // NOR composition
196    let nor = positive.nor(even.clone());
197    println!("positive NOR even: name={:?}", nor.name());
198    println!("  Test -3: {}", nor.test(&-3)); // false NOR false = true
199    println!("  Test 3: {}", nor.test(&3)); // true NOR false = false
200    println!("  Test -2: {}", nor.test(&-2)); // false NOR true = false
201    println!("  Test 4: {}", nor.test(&4)); // true NOR true = false
202
203    // Complex composition
204    let complex = positive.and(even.clone()).and(less_than_ten.clone());
205    println!("Complex composition: name={:?}", complex.name());
206    println!("  Test 4: {}", complex.test(&4));
207    println!("  Test 12: {}", complex.test(&12));
208}
209
210/// Interior mutability examples
211fn interior_mutability_examples() {
212    println!("--- 6. Interior Mutability Examples ---");
213
214    // BoxPredicate with counter (RefCell)
215    println!("BoxPredicate with counter:");
216    let count = RefCell::new(0);
217    let pred = BoxPredicate::new(move |x: &i32| {
218        *count.borrow_mut() += 1;
219        *x > 0
220    });
221    println!("  Test 5: {}", pred.test(&5));
222    println!("  Test -3: {}", pred.test(&-3));
223    println!("  Test 10: {}", pred.test(&10));
224    // Note: count is moved into the closure, so we can't access it here
225
226    // RcPredicate with cache (RefCell + HashMap)
227    println!("\nRcPredicate with cache:");
228    let cache: RefCell<HashMap<i32, bool>> = RefCell::new(HashMap::new());
229    let expensive_pred = RcPredicate::new(move |x: &i32| {
230        let mut c = cache.borrow_mut();
231        *c.entry(*x).or_insert_with(|| {
232            println!("    Computing result for {} (expensive operation)", x);
233            *x > 0 && x % 2 == 0
234        })
235    });
236
237    println!("  First test 4:");
238    println!("    Result: {}", expensive_pred.test(&4));
239    println!("  Test 4 again (using cache):");
240    println!("    Result: {}", expensive_pred.test(&4));
241    println!("  Test 3:");
242    println!("    Result: {}", expensive_pred.test(&3));
243
244    // ArcPredicate with thread-safe counter (Mutex)
245    println!("\nArcPredicate with thread-safe counter:");
246    let counter = Arc::new(Mutex::new(0));
247    let pred = ArcPredicate::new({
248        let counter = Arc::clone(&counter);
249        move |x: &i32| {
250            let mut c = counter.lock().expect("mutex should not be poisoned");
251            *c += 1;
252            *x > 0
253        }
254    });
255
256    let pred_clone = pred.clone();
257    let counter_clone = Arc::clone(&counter);
258
259    let handle = std::thread::spawn(move || {
260        pred_clone.test(&5);
261        pred_clone.test(&10);
262    });
263
264    pred.test(&3);
265    handle.join().expect("thread should not panic");
266
267    println!(
268        "  Total call count: {}",
269        counter_clone.lock().expect("mutex should not be poisoned")
270    );
271}
272
273/// Practical use cases
274fn practical_use_cases() {
275    println!("--- 7. Practical Use Cases ---");
276
277    // Validation rules
278    println!("Scenario 1: Form Validation");
279    struct User {
280        name: String,
281        age: i32,
282        email: String,
283    }
284
285    let name_valid = RcPredicate::new_with_name("name_not_empty", |user: &User| !user.name.is_empty());
286
287    let age_valid = RcPredicate::new_with_name("age_between_18_120", |user: &User| user.age >= 18 && user.age <= 120);
288
289    let email_valid = RcPredicate::new_with_name("email_contains_at", |user: &User| user.email.contains('@'));
290
291    let all_valid = name_valid.and(age_valid.clone()).and(email_valid.clone());
292
293    let user1 = User {
294        name: "Alice".to_string(),
295        age: 25,
296        email: "alice@example.com".to_string(),
297    };
298
299    let user2 = User {
300        name: "".to_string(),
301        age: 25,
302        email: "bob@example.com".to_string(),
303    };
304
305    println!("  user1 validation: {}", all_valid.test(&user1));
306    println!("  user2 validation: {}", all_valid.test(&user2));
307
308    // Filter pipeline
309    println!("\nScenario 2: Data Filtering Pipeline");
310    let numbers: Vec<i32> = (-10..=10).collect();
311
312    let positive = |x: &i32| *x > 0;
313    let even = |x: &i32| x % 2 == 0;
314    let less_than_eight = |x: &i32| *x < 8;
315
316    let filtered: Vec<i32> = numbers
317        .iter()
318        .filter(|x| positive.test(x))
319        .filter(|x| even.test(x))
320        .filter(|x| less_than_eight.test(x))
321        .copied()
322        .collect();
323
324    println!("  Filtered numbers: {:?}", filtered);
325
326    // Strategy pattern
327    println!("\nScenario 3: Strategy Pattern");
328    let mut strategies: HashMap<&str, RcPredicate<i32>> = HashMap::new();
329    strategies.insert("positive", RcPredicate::new(|x: &i32| *x > 0));
330    strategies.insert("negative", RcPredicate::new(|x: &i32| *x < 0));
331    strategies.insert("even", RcPredicate::new(|x: &i32| x % 2 == 0));
332
333    let test_value = 4;
334    for (name, pred) in strategies.iter() {
335        println!("  {} strategy test {}: {}", name, test_value, pred.test(&test_value));
336    }
337}