Predicate

Trait Predicate 

Source
pub trait Predicate<T> {
    // Required method
    fn test(&self, value: &T) -> bool;

    // Provided methods
    fn into_box(self) -> BoxPredicate<T>
       where Self: Sized + 'static,
             T: 'static { ... }
    fn into_rc(self) -> RcPredicate<T>
       where Self: Sized + 'static,
             T: 'static { ... }
    fn into_arc(self) -> ArcPredicate<T>
       where Self: Sized + Send + Sync + 'static,
             T: Send + Sync + 'static { ... }
    fn into_fn(self) -> impl Fn(&T) -> bool
       where Self: Sized + 'static,
             T: 'static { ... }
    fn to_box(&self) -> BoxPredicate<T>
       where Self: Clone + Sized + 'static,
             T: 'static { ... }
    fn to_rc(&self) -> RcPredicate<T>
       where Self: Clone + Sized + 'static,
             T: 'static { ... }
    fn to_arc(&self) -> ArcPredicate<T>
       where Self: Clone + Sized + Send + Sync + 'static,
             T: Send + Sync + 'static { ... }
    fn to_fn(&self) -> impl Fn(&T) -> bool
       where Self: Clone + Sized + 'static,
             T: 'static { ... }
}
Expand description

A predicate trait for testing whether a value satisfies a condition.

This trait represents a pure judgment operation - it tests whether a given value meets certain criteria without modifying either the value or the predicate itself (from the user’s perspective). This semantic clarity distinguishes predicates from consumers or transformers.

§Design Rationale

This is a minimal trait that only defines:

  • The core test method using &self (immutable borrow)
  • Type conversion methods (into_box, into_rc, into_arc)
  • Closure conversion method (into_fn)

Logical composition methods (and, or, not) are intentionally not part of the trait. Instead, they are implemented on concrete types (BoxPredicate, RcPredicate, ArcPredicate), allowing each implementation to maintain its specific ownership characteristics:

  • BoxPredicate: Methods consume self (single ownership)
  • RcPredicate: Methods borrow &self (shared ownership)
  • ArcPredicate: Methods borrow &self (thread-safe shared ownership)

§Why &self Instead of &mut self?

Predicates use &self because:

  1. Semantic Clarity: A predicate is a judgment, not a mutation
  2. Flexibility: Can be used in immutable contexts
  3. Simplicity: No need for mut in user code
  4. Interior Mutability: State (if needed) can be managed with RefCell, Cell, or Mutex

§Automatic Implementation for Closures

Any closure matching Fn(&T) -> bool automatically implements this trait, providing seamless integration with Rust’s closure system.

§Examples

§Basic Usage

use prism3_function::predicate::Predicate;

let is_positive = |x: &i32| *x > 0;
assert!(is_positive.test(&5));
assert!(!is_positive.test(&-3));

§Type Conversion

use prism3_function::predicate::{Predicate, BoxPredicate};

let closure = |x: &i32| *x > 0;
let boxed: BoxPredicate<i32> = closure.into_box();
assert!(boxed.test(&5));

§Stateful Predicate with Interior Mutability

use prism3_function::predicate::{Predicate, BoxPredicate};
use std::cell::Cell;

let count = Cell::new(0);
let counting_pred = BoxPredicate::new(move |x: &i32| {
    count.set(count.get() + 1);
    *x > 0
});

// Note: No `mut` needed - interior mutability handles state
assert!(counting_pred.test(&5));
assert!(!counting_pred.test(&-3));

§Author

Haixing Hu

Required Methods§

Source

fn test(&self, value: &T) -> bool

Tests whether the given value satisfies this predicate.

§Parameters
  • value - The value to test.
§Returns

true if the value satisfies this predicate, false otherwise.

Provided Methods§

Source

fn into_box(self) -> BoxPredicate<T>
where Self: Sized + 'static, T: 'static,

Converts this predicate into a BoxPredicate.

The default implementation wraps the predicate in a closure that calls the test method. Concrete types may override this with more efficient implementations.

§Returns

A BoxPredicate wrapping this predicate.

Source

fn into_rc(self) -> RcPredicate<T>
where Self: Sized + 'static, T: 'static,

Converts this predicate into an RcPredicate.

The default implementation wraps the predicate in a closure that calls the test method. Concrete types may override this with more efficient implementations.

§Returns

An RcPredicate wrapping this predicate.

Source

fn into_arc(self) -> ArcPredicate<T>
where Self: Sized + Send + Sync + 'static, T: Send + Sync + 'static,

Converts this predicate into an ArcPredicate.

The default implementation wraps the predicate in a closure that calls the test method. Concrete types may override this with more efficient implementations.

§Returns

An ArcPredicate wrapping this predicate.

Source

fn into_fn(self) -> impl Fn(&T) -> bool
where Self: Sized + 'static, T: 'static,

Converts this predicate into a closure that can be used directly with standard library methods.

This method consumes the predicate and returns a closure with signature Fn(&T) -> bool. Since Fn is a subtrait of FnMut, the returned closure can be used in any context that requires either Fn(&T) -> bool or FnMut(&T) -> bool, making it compatible with methods like Iterator::filter, Iterator::filter_map, Vec::retain, and similar standard library APIs.

The default implementation returns a closure that calls the test method. Concrete types may override this with more efficient implementations.

§Returns

A closure implementing Fn(&T) -> bool (also usable as FnMut(&T) -> bool).

§Examples
§Using with Iterator::filter (requires FnMut)
use prism3_function::predicate::{Predicate, BoxPredicate};

let pred = BoxPredicate::new(|x: &i32| *x > 0);

let numbers = vec![-2, -1, 0, 1, 2, 3];
let positives: Vec<_> = numbers.iter()
    .copied()
    .filter(pred.into_fn())
    .collect();
assert_eq!(positives, vec![1, 2, 3]);
§Using with Vec::retain (requires FnMut)
use prism3_function::predicate::{Predicate, BoxPredicate};

let pred = BoxPredicate::new(|x: &i32| *x % 2 == 0);
let mut numbers = vec![1, 2, 3, 4, 5, 6];
numbers.retain(pred.into_fn());
assert_eq!(numbers, vec![2, 4, 6]);
Examples found in repository?
examples/predicate_fn_mut_demo.rs (line 29)
24fn demo_with_iterator_filter() {
25    println!("1. Using Iterator::filter");
26
27    let pred = BoxPredicate::new(|x: &i32| *x > 0);
28    let numbers = vec![-2, -1, 0, 1, 2, 3];
29    let positives: Vec<_> = numbers.iter().copied().filter(pred.into_fn()).collect();
30    println!("   Original data: {:?}", numbers);
31    println!("   Filtered result: {:?}", positives);
32    assert_eq!(positives, vec![1, 2, 3]);
33    println!("   ✓ BoxPredicate::into_fn() can be used in filter\n");
34}
35
36/// Demonstrates usage with Vec::retain (retain requires FnMut)
37fn demo_with_vec_retain() {
38    println!("2. Using Vec::retain");
39
40    // RcPredicate example
41    let pred = RcPredicate::new(|x: &i32| *x % 2 == 0);
42    let mut numbers = vec![1, 2, 3, 4, 5, 6];
43    println!("   Original data: {:?}", numbers);
44    numbers.retain(pred.to_fn());
45    println!("   Retained even numbers: {:?}", numbers);
46    assert_eq!(numbers, vec![2, 4, 6]);
47
48    // Original predicate is still available
49    assert!(pred.test(&10));
50    println!("   ✓ RcPredicate::to_fn() can be used in retain");
51    println!("   ✓ Original predicate is still available\n");
52}
53
54/// Demonstrates usage with generic functions that require FnMut
55fn demo_with_generic_function() {
56    println!("3. Using generic functions (requires FnMut)");
57
58    fn count_matching<F>(items: &[i32], mut predicate: F) -> usize
59    where
60        F: FnMut(&i32) -> bool,
61    {
62        items.iter().filter(|x| predicate(x)).count()
63    }
64
65    let pred = RcPredicate::new(|x: &i32| *x > 10);
66    let count1 = count_matching(&[5, 15, 8, 20], pred.to_fn());
67    println!("   First call: count = {}", count1);
68    assert_eq!(count1, 2);
69
70    // Original predicate can be reused
71    let count2 = count_matching(&[12, 3, 18], pred.to_fn());
72    println!("   Second call: count = {}", count2);
73    assert_eq!(count2, 2);
74
75    println!("   ✓ RcPredicate::to_fn() can be passed to generic functions requiring FnMut");
76    println!("   ✓ Original predicate can be converted and used multiple times\n");
77}
78
79/// Demonstrates thread-safe usage
80fn demo_thread_safe() {
81    println!("4. Thread-safe usage");
82
83    let pred = ArcPredicate::new(|x: &i32| *x > 0);
84    // clone and convert into a 'static closure so it can be moved to another thread
85    let closure = pred.clone().into_fn();
86
87    // Closure can be passed between threads
88    let handle = std::thread::spawn(move || {
89        let numbers = [-2, -1, 0, 1, 2, 3];
90        numbers.iter().copied().filter(closure).count()
91    });
92
93    let count = handle.join().unwrap();
94    println!("   Filtered result count in thread: {}", count);
95    assert_eq!(count, 3);
96
97    // Original predicate is still available
98    assert!(pred.test(&5));
99    println!("   ✓ ArcPredicate::to_fn() returns a thread-safe closure");
100    println!("   ✓ Original predicate is still available in main thread\n");
101}
More examples
Hide additional examples
examples/always_predicate_demo.rs (line 136)
11fn main() {
12    println!("=== BoxPredicate always_true/always_false Demo ===\n");
13
14    // BoxPredicate::always_true
15    let always_true: BoxPredicate<i32> = BoxPredicate::always_true();
16    println!("BoxPredicate::always_true():");
17    println!("  test(&42): {}", always_true.test(&42));
18    println!("  test(&-1): {}", always_true.test(&-1));
19    println!("  test(&0): {}", always_true.test(&0));
20    println!("  name: {:?}", always_true.name());
21
22    // BoxPredicate::always_false
23    let always_false: BoxPredicate<i32> = BoxPredicate::always_false();
24    println!("\nBoxPredicate::always_false():");
25    println!("  test(&42): {}", always_false.test(&42));
26    println!("  test(&-1): {}", always_false.test(&-1));
27    println!("  test(&0): {}", always_false.test(&0));
28    println!("  name: {:?}", always_false.name());
29
30    println!("\n=== RcPredicate always_true/always_false Demo ===\n");
31
32    // RcPredicate::always_true
33    let rc_always_true: RcPredicate<String> = RcPredicate::always_true();
34    println!("RcPredicate::always_true():");
35    println!(
36        "  test(&\"hello\"): {}",
37        rc_always_true.test(&"hello".to_string())
38    );
39    println!(
40        "  test(&\"world\"): {}",
41        rc_always_true.test(&"world".to_string())
42    );
43    println!("  name: {:?}", rc_always_true.name());
44
45    // RcPredicate::always_false
46    let rc_always_false: RcPredicate<String> = RcPredicate::always_false();
47    println!("\nRcPredicate::always_false():");
48    println!(
49        "  test(&\"hello\"): {}",
50        rc_always_false.test(&"hello".to_string())
51    );
52    println!(
53        "  test(&\"world\"): {}",
54        rc_always_false.test(&"world".to_string())
55    );
56    println!("  name: {:?}", rc_always_false.name());
57
58    // Can be cloned and reused
59    let rc_clone = rc_always_true.clone();
60    println!("\nAfter cloning, still usable:");
61    println!(
62        "  Original: test(&\"test\"): {}",
63        rc_always_true.test(&"test".to_string())
64    );
65    println!(
66        "  Clone: test(&\"test\"): {}",
67        rc_clone.test(&"test".to_string())
68    );
69
70    println!("\n=== ArcPredicate always_true/always_false Demo ===\n");
71
72    // ArcPredicate::always_true
73    let arc_always_true: ArcPredicate<i32> = ArcPredicate::always_true();
74    println!("ArcPredicate::always_true():");
75    println!("  test(&100): {}", arc_always_true.test(&100));
76    println!("  test(&-100): {}", arc_always_true.test(&-100));
77    println!("  name: {:?}", arc_always_true.name());
78
79    // ArcPredicate::always_false
80    let arc_always_false: ArcPredicate<i32> = ArcPredicate::always_false();
81    println!("\nArcPredicate::always_false():");
82    println!("  test(&100): {}", arc_always_false.test(&100));
83    println!("  test(&-100): {}", arc_always_false.test(&-100));
84    println!("  name: {:?}", arc_always_false.name());
85
86    println!("\n=== Combining with other predicates ===\n");
87
88    // Combining with always_true (AND)
89    let is_positive = BoxPredicate::new(|x: &i32| *x > 0);
90    let combined_and_true = is_positive.and(BoxPredicate::always_true());
91    println!("is_positive AND always_true:");
92    println!(
93        "  test(&5): {} (equivalent to is_positive)",
94        combined_and_true.test(&5)
95    );
96    println!(
97        "  test(&-3): {} (equivalent to is_positive)",
98        combined_and_true.test(&-3)
99    );
100
101    // Combining with always_false (AND)
102    let is_positive = BoxPredicate::new(|x: &i32| *x > 0);
103    let combined_and_false = is_positive.and(BoxPredicate::always_false());
104    println!("\nis_positive AND always_false:");
105    println!("  test(&5): {} (always false)", combined_and_false.test(&5));
106    println!(
107        "  test(&-3): {} (always false)",
108        combined_and_false.test(&-3)
109    );
110
111    // Combining with always_true (OR)
112    let is_positive = BoxPredicate::new(|x: &i32| *x > 0);
113    let combined_or_true = is_positive.or(BoxPredicate::always_true());
114    println!("\nis_positive OR always_true:");
115    println!("  test(&5): {} (always true)", combined_or_true.test(&5));
116    println!("  test(&-3): {} (always true)", combined_or_true.test(&-3));
117
118    // Combining with always_false (OR)
119    let is_positive = BoxPredicate::new(|x: &i32| *x > 0);
120    let combined_or_false = is_positive.or(BoxPredicate::always_false());
121    println!("\nis_positive OR always_false:");
122    println!(
123        "  test(&5): {} (equivalent to is_positive)",
124        combined_or_false.test(&5)
125    );
126    println!(
127        "  test(&-3): {} (equivalent to is_positive)",
128        combined_or_false.test(&-3)
129    );
130
131    println!("\n=== Practical scenarios: Default pass/reject filters ===\n");
132
133    // Scenario 1: Default pass-all filter
134    let numbers = vec![1, 2, 3, 4, 5];
135    let pass_all = BoxPredicate::<i32>::always_true();
136    let filtered: Vec<_> = numbers.iter().copied().filter(pass_all.into_fn()).collect();
137    println!("Default pass all elements: {:?} -> {:?}", numbers, filtered);
138
139    // Scenario 2: Default reject-all filter
140    let numbers = vec![1, 2, 3, 4, 5];
141    let reject_all = BoxPredicate::<i32>::always_false();
142    let filtered: Vec<_> = numbers
143        .iter()
144        .copied()
145        .filter(reject_all.into_fn())
146        .collect();
147    println!(
148        "Default reject all elements: {:?} -> {:?}",
149        numbers, filtered
150    );
151
152    // Scenario 3: Configurable filter
153    fn configurable_filter(enable_filter: bool) -> BoxPredicate<i32> {
154        if enable_filter {
155            BoxPredicate::new(|x: &i32| *x > 3)
156        } else {
157            BoxPredicate::always_true()
158        }
159    }
160
161    let numbers = vec![1, 2, 3, 4, 5];
162
163    let filter_enabled = configurable_filter(true);
164    let filtered: Vec<_> = numbers
165        .iter()
166        .copied()
167        .filter(filter_enabled.into_fn())
168        .collect();
169    println!("\nFilter enabled: {:?} -> {:?}", numbers, filtered);
170
171    let filter_disabled = configurable_filter(false);
172    let filtered: Vec<_> = numbers
173        .iter()
174        .copied()
175        .filter(filter_disabled.into_fn())
176        .collect();
177    println!("Filter disabled: {:?} -> {:?}", numbers, filtered);
178}
Source

fn to_box(&self) -> BoxPredicate<T>
where Self: Clone + Sized + 'static, T: 'static,

Converts a reference to this predicate into a BoxPredicate.

This method clones the predicate and then converts it to a BoxPredicate. The original predicate remains usable after this call.

§Returns

A BoxPredicate wrapping a clone of this predicate.

Source

fn to_rc(&self) -> RcPredicate<T>
where Self: Clone + Sized + 'static, T: 'static,

Converts a reference to this predicate into an RcPredicate.

This method clones the predicate and then converts it to an RcPredicate. The original predicate remains usable after this call.

§Returns

An RcPredicate wrapping a clone of this predicate.

Source

fn to_arc(&self) -> ArcPredicate<T>
where Self: Clone + Sized + Send + Sync + 'static, T: Send + Sync + 'static,

Converts a reference to this predicate into an ArcPredicate.

This method clones the predicate and then converts it to an ArcPredicate. The original predicate remains usable after this call.

§Returns

An ArcPredicate wrapping a clone of this predicate.

Source

fn to_fn(&self) -> impl Fn(&T) -> bool
where Self: Clone + Sized + 'static, T: 'static,

Converts a reference to this predicate into a closure that can be used directly with standard library methods.

This method clones the predicate and then converts it to a closure. The original predicate remains usable after this call.

The returned closure has signature Fn(&T) -> bool. Since Fn is a subtrait of FnMut, it can be used in any context that requires either Fn(&T) -> bool or FnMut(&T) -> bool, making it compatible with methods like Iterator::filter, Iterator::filter_map, Vec::retain, and similar standard library APIs.

§Returns

A closure implementing Fn(&T) -> bool (also usable as FnMut(&T) -> bool).

Examples found in repository?
examples/predicate_fn_mut_demo.rs (line 44)
37fn demo_with_vec_retain() {
38    println!("2. Using Vec::retain");
39
40    // RcPredicate example
41    let pred = RcPredicate::new(|x: &i32| *x % 2 == 0);
42    let mut numbers = vec![1, 2, 3, 4, 5, 6];
43    println!("   Original data: {:?}", numbers);
44    numbers.retain(pred.to_fn());
45    println!("   Retained even numbers: {:?}", numbers);
46    assert_eq!(numbers, vec![2, 4, 6]);
47
48    // Original predicate is still available
49    assert!(pred.test(&10));
50    println!("   ✓ RcPredicate::to_fn() can be used in retain");
51    println!("   ✓ Original predicate is still available\n");
52}
53
54/// Demonstrates usage with generic functions that require FnMut
55fn demo_with_generic_function() {
56    println!("3. Using generic functions (requires FnMut)");
57
58    fn count_matching<F>(items: &[i32], mut predicate: F) -> usize
59    where
60        F: FnMut(&i32) -> bool,
61    {
62        items.iter().filter(|x| predicate(x)).count()
63    }
64
65    let pred = RcPredicate::new(|x: &i32| *x > 10);
66    let count1 = count_matching(&[5, 15, 8, 20], pred.to_fn());
67    println!("   First call: count = {}", count1);
68    assert_eq!(count1, 2);
69
70    // Original predicate can be reused
71    let count2 = count_matching(&[12, 3, 18], pred.to_fn());
72    println!("   Second call: count = {}", count2);
73    assert_eq!(count2, 2);
74
75    println!("   ✓ RcPredicate::to_fn() can be passed to generic functions requiring FnMut");
76    println!("   ✓ Original predicate can be converted and used multiple times\n");
77}

Implementors§

Source§

impl<T: 'static> Predicate<T> for ArcPredicate<T>

Source§

impl<T: 'static> Predicate<T> for BoxPredicate<T>

Source§

impl<T: 'static> Predicate<T> for RcPredicate<T>

Source§

impl<T: 'static, F> Predicate<T> for F
where F: Fn(&T) -> bool + 'static,