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
testmethod 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 consumeself(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:
- Semantic Clarity: A predicate is a judgment, not a mutation
- Flexibility: Can be used in immutable contexts
- Simplicity: No need for
mutin user code - Interior Mutability: State (if needed) can be managed with
RefCell,Cell, orMutex
§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§
Provided Methods§
Sourcefn into_box(self) -> BoxPredicate<T>where
Self: Sized + 'static,
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.
Sourcefn into_rc(self) -> RcPredicate<T>where
Self: Sized + 'static,
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.
Sourcefn into_arc(self) -> ArcPredicate<T>
fn into_arc(self) -> ArcPredicate<T>
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.
Sourcefn into_fn(self) -> impl Fn(&T) -> boolwhere
Self: Sized + 'static,
fn into_fn(self) -> impl Fn(&T) -> boolwhere
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?
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
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}Sourcefn to_box(&self) -> BoxPredicate<T>
fn to_box(&self) -> BoxPredicate<T>
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.
Sourcefn to_rc(&self) -> RcPredicate<T>
fn to_rc(&self) -> RcPredicate<T>
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.
Sourcefn to_arc(&self) -> ArcPredicate<T>
fn to_arc(&self) -> ArcPredicate<T>
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.
Sourcefn to_fn(&self) -> impl Fn(&T) -> bool
fn to_fn(&self) -> impl Fn(&T) -> bool
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?
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}