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