Skip to main content

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 { ... }
    fn into_rc(self) -> RcPredicate<T>
       where Self: Sized + 'static { ... }
    fn into_arc(self) -> ArcPredicate<T>
       where Self: Sized + Send + Sync + 'static { ... }
    fn into_fn(self) -> impl Fn(&T) -> bool
       where Self: Sized + 'static { ... }
    fn to_box(&self) -> BoxPredicate<T>
       where Self: Clone + Sized + 'static { ... }
    fn to_rc(&self) -> RcPredicate<T>
       where Self: Clone + Sized + 'static { ... }
    fn to_arc(&self) -> ArcPredicate<T>
       where Self: Clone + Sized + Send + Sync + 'static { ... }
    fn to_fn(&self) -> impl Fn(&T) -> bool
       where Self: Clone + Sized + '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 qubit_function::Predicate;

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

§Type Conversion

use qubit_function::{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 qubit_function::{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,

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,

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,

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,

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

fn to_box(&self) -> BoxPredicate<T>
where Self: Clone + Sized + '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,

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,

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,

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

Implementors§

Source§

impl<T> Predicate<T> for ArcPredicate<T>

Source§

impl<T> Predicate<T> for BoxPredicate<T>

Source§

impl<T> Predicate<T> for RcPredicate<T>

Source§

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