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));

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

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,