Skip to main content

predicate_demo/
predicate_demo.rs

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