predicate_demo/
predicate_demo.rs

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