BiPredicate

Trait BiPredicate 

Source
pub trait BiPredicate<T, U> {
    // Required method
    fn test(&self, first: &T, second: &U) -> bool;

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

A bi-predicate trait for testing whether two values satisfy a condition.

This trait represents a pure judgment operation - it tests whether two given values meet certain criteria without modifying either the values or the bi-predicate itself (from the user’s perspective). This semantic clarity distinguishes bi-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, xor, nand, nor) are intentionally not part of the trait. Instead, they are implemented on concrete types (BoxBiPredicate, RcBiPredicate, ArcBiPredicate), allowing each implementation to maintain its specific ownership characteristics:

  • BoxBiPredicate: Methods consume self (single ownership)
  • RcBiPredicate: Methods borrow &self (shared ownership)
  • ArcBiPredicate: Methods borrow &self (thread-safe shared ownership)

§Why &self Instead of &mut self?

Bi-predicates use &self because:

  1. Semantic Clarity: A bi-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, &U) -> bool automatically implements this trait, providing seamless integration with Rust’s closure system.

§Examples

§Basic Usage

use prism3_function::bi_predicate::BiPredicate;

let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
assert!(is_sum_positive.test(&5, &3));
assert!(!is_sum_positive.test(&-5, &-3));

§Type Conversion

use prism3_function::bi_predicate::{BiPredicate,
    BoxBiPredicate};

let closure = |x: &i32, y: &i32| x + y > 0;
let boxed: BoxBiPredicate<i32, i32> = closure.into_box();
assert!(boxed.test(&5, &3));

§Stateful BiPredicate with Interior Mutability

use prism3_function::bi_predicate::{BiPredicate,
    BoxBiPredicate};
use std::cell::Cell;

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

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

§Author

Haixing Hu

Required Methods§

Source

fn test(&self, first: &T, second: &U) -> bool

Tests whether the given values satisfy this bi-predicate.

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

true if the values satisfy this bi-predicate, false otherwise.

Provided Methods§

Source

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

Converts this bi-predicate into a BoxBiPredicate.

§Returns

A BoxBiPredicate wrapping this bi-predicate.

§Default Implementation

The default implementation wraps the bi-predicate in a closure that calls test, providing automatic conversion for custom types that only implement the core test method.

Source

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

Converts this bi-predicate into an RcBiPredicate.

§Returns

An RcBiPredicate wrapping this bi-predicate.

§Default Implementation

The default implementation wraps the bi-predicate in a closure that calls test, providing automatic conversion for custom types that only implement the core test method.

Source

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

Converts this bi-predicate into an ArcBiPredicate.

§Returns

An ArcBiPredicate wrapping this bi-predicate.

§Default Implementation

The default implementation wraps the bi-predicate in a closure that calls test, providing automatic conversion for custom types that only implement the core test method. Note that this requires Send + Sync bounds for thread-safe sharing.

Source

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

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

This method consumes the bi-predicate and returns a closure with signature Fn(&T, &U) -> bool. Since Fn is a subtrait of FnMut, the returned closure can be used in any context that requires either Fn(&T, &U) -> bool or FnMut(&T, &U) -> bool.

§Returns

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

§Default Implementation

The default implementation returns a closure that calls the test method, providing automatic conversion for custom types.

§Examples
§Using with Iterator Methods
use prism3_function::bi_predicate::{BiPredicate,
    BoxBiPredicate};

let pred = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0);

let pairs = vec![(1, 2), (-1, 3), (5, -6)];
let mut closure = pred.into_fn();
let positives: Vec<_> = pairs.iter()
    .filter(|(x, y)| closure(x, y))
    .collect();
assert_eq!(positives, vec![&(1, 2), &(-1, 3)]);
Examples found in repository?
examples/always_bi_predicate_demo.rs (line 145)
11fn main() {
12    println!("=== BoxBiPredicate always_true/always_false Demo ===\n");
13
14    // BoxBiPredicate::always_true
15    let always_true: BoxBiPredicate<i32, i32> = BoxBiPredicate::always_true();
16    println!("BoxBiPredicate::always_true():");
17    println!("  test(&42, &10): {}", always_true.test(&42, &10));
18    println!("  test(&-1, &5): {}", always_true.test(&-1, &5));
19    println!("  test(&0, &0): {}", always_true.test(&0, &0));
20    println!("  name: {:?}", always_true.name());
21
22    // BoxBiPredicate::always_false
23    let always_false: BoxBiPredicate<i32, i32> = BoxBiPredicate::always_false();
24    println!("\nBoxBiPredicate::always_false():");
25    println!("  test(&42, &10): {}", always_false.test(&42, &10));
26    println!("  test(&-1, &5): {}", always_false.test(&-1, &5));
27    println!("  test(&0, &0): {}", always_false.test(&0, &0));
28    println!("  name: {:?}", always_false.name());
29
30    println!("\n=== RcBiPredicate always_true/always_false Demo ===\n");
31
32    // RcBiPredicate::always_true
33    let rc_always_true: RcBiPredicate<String, i32> = RcBiPredicate::always_true();
34    println!("RcBiPredicate::always_true():");
35    println!(
36        "  test(&\"hello\", &5): {}",
37        rc_always_true.test(&"hello".to_string(), &5)
38    );
39    println!(
40        "  test(&\"world\", &-3): {}",
41        rc_always_true.test(&"world".to_string(), &-3)
42    );
43    println!("  name: {:?}", rc_always_true.name());
44
45    // RcBiPredicate::always_false
46    let rc_always_false: RcBiPredicate<String, i32> = RcBiPredicate::always_false();
47    println!("\nRcBiPredicate::always_false():");
48    println!(
49        "  test(&\"hello\", &5): {}",
50        rc_always_false.test(&"hello".to_string(), &5)
51    );
52    println!(
53        "  test(&\"world\", &-3): {}",
54        rc_always_false.test(&"world".to_string(), &-3)
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\", &1): {}",
63        rc_always_true.test(&"test".to_string(), &1)
64    );
65    println!(
66        "  Clone: test(&\"test\", &2): {}",
67        rc_clone.test(&"test".to_string(), &2)
68    );
69
70    println!("\n=== ArcBiPredicate always_true/always_false Demo ===\n");
71
72    // ArcBiPredicate::always_true
73    let arc_always_true: ArcBiPredicate<i32, i32> = ArcBiPredicate::always_true();
74    println!("ArcBiPredicate::always_true():");
75    println!("  test(&100, &50): {}", arc_always_true.test(&100, &50));
76    println!("  test(&-100, &25): {}", arc_always_true.test(&-100, &25));
77    println!("  name: {:?}", arc_always_true.name());
78
79    // ArcBiPredicate::always_false
80    let arc_always_false: ArcBiPredicate<i32, i32> = ArcBiPredicate::always_false();
81    println!("\nArcBiPredicate::always_false():");
82    println!("  test(&100, &50): {}", arc_always_false.test(&100, &50));
83    println!("  test(&-100, &25): {}", arc_always_false.test(&-100, &25));
84    println!("  name: {:?}", arc_always_false.name());
85
86    println!("\n=== Combining with other bi-predicates ===\n");
87
88    // Combining with always_true (AND)
89    let sum_positive = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
90    let combined_and_true = sum_positive.and(BoxBiPredicate::always_true());
91    println!("sum_positive AND always_true:");
92    println!(
93        "  test(&5, &3): {} (equivalent to sum_positive)",
94        combined_and_true.test(&5, &3)
95    );
96    println!(
97        "  test(&-3, &-5): {} (equivalent to sum_positive)",
98        combined_and_true.test(&-3, &-5)
99    );
100
101    // Combining with always_false (AND)
102    let sum_positive = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
103    let combined_and_false = sum_positive.and(BoxBiPredicate::always_false());
104    println!("\nsum_positive AND always_false:");
105    println!(
106        "  test(&5, &3): {} (always false)",
107        combined_and_false.test(&5, &3)
108    );
109    println!(
110        "  test(&-3, &-5): {} (always false)",
111        combined_and_false.test(&-3, &-5)
112    );
113
114    // Combining with always_true (OR)
115    let sum_positive = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
116    let combined_or_true = sum_positive.or(BoxBiPredicate::always_true());
117    println!("\nsum_positive OR always_true:");
118    println!(
119        "  test(&5, &3): {} (always true)",
120        combined_or_true.test(&5, &3)
121    );
122    println!(
123        "  test(&-3, &-5): {} (always true)",
124        combined_or_true.test(&-3, &-5)
125    );
126
127    // Combining with always_false (OR)
128    let sum_positive = BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
129    let combined_or_false = sum_positive.or(BoxBiPredicate::always_false());
130    println!("\nsum_positive OR always_false:");
131    println!(
132        "  test(&5, &3): {} (equivalent to sum_positive)",
133        combined_or_false.test(&5, &3)
134    );
135    println!(
136        "  test(&-3, &-5): {} (equivalent to sum_positive)",
137        combined_or_false.test(&-3, &-5)
138    );
139
140    println!("\n=== Practical scenarios: Default pass/reject filters ===\n");
141
142    // Scenario 1: Default pass-all filter
143    let pairs = vec![(1, 2), (3, 4), (5, 6)];
144    let pass_all = BoxBiPredicate::<i32, i32>::always_true();
145    let closure = pass_all.into_fn();
146    let filtered: Vec<_> = pairs.iter().filter(|(x, y)| closure(x, y)).collect();
147    println!("Default pass all elements: {:?} -> {:?}", pairs, filtered);
148
149    // Scenario 2: Default reject-all filter
150    let pairs = vec![(1, 2), (3, 4), (5, 6)];
151    let reject_all = BoxBiPredicate::<i32, i32>::always_false();
152    let closure = reject_all.into_fn();
153    let filtered: Vec<_> = pairs.iter().filter(|(x, y)| closure(x, y)).collect();
154    println!("Default reject all elements: {:?} -> {:?}", pairs, filtered);
155
156    // Scenario 3: Configurable filter
157    fn configurable_filter(enable_filter: bool) -> BoxBiPredicate<i32, i32> {
158        if enable_filter {
159            BoxBiPredicate::new(|x: &i32, y: &i32| x + y > 5)
160        } else {
161            BoxBiPredicate::always_true()
162        }
163    }
164
165    let pairs = vec![(1, 2), (3, 4), (5, 6)];
166
167    let filter_enabled = configurable_filter(true);
168    let closure = filter_enabled.into_fn();
169    let filtered: Vec<_> = pairs.iter().filter(|(x, y)| closure(x, y)).collect();
170    println!("\nFilter enabled: {:?} -> {:?}", pairs, filtered);
171
172    let filter_disabled = configurable_filter(false);
173    let closure = filter_disabled.into_fn();
174    let filtered: Vec<_> = pairs.iter().filter(|(x, y)| closure(x, y)).collect();
175    println!("Filter disabled: {:?} -> {:?}", pairs, filtered);
176}
Source

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

Source

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

Source

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

Source

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

Implementors§

Source§

impl<T, U> BiPredicate<T, U> for ArcBiPredicate<T, U>

Source§

impl<T, U> BiPredicate<T, U> for BoxBiPredicate<T, U>

Source§

impl<T, U> BiPredicate<T, U> for RcBiPredicate<T, U>

Source§

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