Skip to main content

qubit_function/predicates/bi_predicate/
fn_bi_predicate_ops.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10// qubit-style: allow explicit-imports
11//! Defines the `FnBiPredicateOps` public type.
12
13use super::{
14    BiPredicate,
15    BoxBiPredicate,
16};
17
18/// Extension trait providing logical composition methods for closures.
19///
20/// This trait is automatically implemented for all closures and
21/// function pointers that match `Fn(&T, &U) -> bool`, enabling method
22/// chaining starting from a closure.
23///
24/// # Examples
25///
26/// ```rust
27/// use qubit_function::{BiPredicate, FnBiPredicateOps};
28///
29/// let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
30/// let first_larger = |x: &i32, y: &i32| x > y;
31///
32/// // Combine bi-predicates using extension methods
33/// let pred = is_sum_positive.and(first_larger);
34/// assert!(pred.test(&10, &5));
35/// assert!(!pred.test(&3, &8));
36/// ```
37///
38pub trait FnBiPredicateOps<T, U>: Fn(&T, &U) -> bool + Sized {
39    /// Returns a bi-predicate that represents the logical AND of this
40    /// bi-predicate and another.
41    ///
42    /// # Parameters
43    ///
44    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
45    ///   is passed by value and will transfer ownership.** If you need to
46    ///   preserve the original bi-predicate, clone it first (if it implements
47    ///   `Clone`). Can be:
48    ///   - Another closure: `|x: &T, y: &U| -> bool`
49    ///   - A function pointer: `fn(&T, &U) -> bool`
50    ///   - A `BoxBiPredicate<T, U>`
51    ///   - An `RcBiPredicate<T, U>`
52    ///   - An `ArcBiPredicate<T, U>`
53    ///   - Any type implementing `BiPredicate<T, U>`
54    ///
55    /// # Returns
56    ///
57    /// A `BoxBiPredicate` representing the logical AND.
58    fn and<P>(self, other: P) -> BoxBiPredicate<T, U>
59    where
60        Self: 'static,
61        P: BiPredicate<T, U> + 'static,
62        T: 'static,
63        U: 'static,
64    {
65        BoxBiPredicate::new(move |first, second| self(first, second) && other.test(first, second))
66    }
67
68    /// Returns a bi-predicate that represents the logical OR of this
69    /// bi-predicate and another.
70    ///
71    /// # Parameters
72    ///
73    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
74    ///   is passed by value and will transfer ownership.** If you need to
75    ///   preserve the original bi-predicate, clone it first (if it implements
76    ///   `Clone`). Can be:
77    ///   - Another closure: `|x: &T, y: &U| -> bool`
78    ///   - A function pointer: `fn(&T, &U) -> bool`
79    ///   - A `BoxBiPredicate<T, U>`
80    ///   - An `RcBiPredicate<T, U>`
81    ///   - An `ArcBiPredicate<T, U>`
82    ///   - Any type implementing `BiPredicate<T, U>`
83    ///
84    /// # Returns
85    ///
86    /// A `BoxBiPredicate` representing the logical OR.
87    fn or<P>(self, other: P) -> BoxBiPredicate<T, U>
88    where
89        Self: 'static,
90        P: BiPredicate<T, U> + 'static,
91        T: 'static,
92        U: 'static,
93    {
94        BoxBiPredicate::new(move |first, second| self(first, second) || other.test(first, second))
95    }
96
97    /// Returns a bi-predicate that represents the logical negation of
98    /// this bi-predicate.
99    ///
100    /// # Returns
101    ///
102    /// A `BoxBiPredicate` representing the logical negation.
103    fn not(self) -> BoxBiPredicate<T, U>
104    where
105        Self: 'static,
106        T: 'static,
107        U: 'static,
108    {
109        BoxBiPredicate::new(move |first, second| !self(first, second))
110    }
111
112    /// Returns a bi-predicate that represents the logical NAND (NOT
113    /// AND) of this bi-predicate and another.
114    ///
115    /// NAND returns `true` unless both bi-predicates are `true`.
116    /// Equivalent to `!(self AND other)`.
117    ///
118    /// # Parameters
119    ///
120    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
121    ///   is passed by value and will transfer ownership.** If you need to
122    ///   preserve the original bi-predicate, clone it first (if it implements
123    ///   `Clone`). Can be:
124    ///   - Another closure: `|x: &T, y: &U| -> bool`
125    ///   - A function pointer: `fn(&T, &U) -> bool`
126    ///   - A `BoxBiPredicate<T, U>`
127    ///   - An `RcBiPredicate<T, U>`
128    ///   - An `ArcBiPredicate<T, U>`
129    ///   - Any type implementing `BiPredicate<T, U>`
130    ///
131    /// # Returns
132    ///
133    /// A `BoxBiPredicate` representing the logical NAND.
134    fn nand<P>(self, other: P) -> BoxBiPredicate<T, U>
135    where
136        Self: 'static,
137        P: BiPredicate<T, U> + 'static,
138        T: 'static,
139        U: 'static,
140    {
141        BoxBiPredicate::new(move |first, second| !(self(first, second) && other.test(first, second)))
142    }
143
144    /// Returns a bi-predicate that represents the logical XOR
145    /// (exclusive OR) of this bi-predicate and another.
146    ///
147    /// XOR returns `true` if exactly one of the bi-predicates is
148    /// `true`.
149    ///
150    /// # Parameters
151    ///
152    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
153    ///   is passed by value and will transfer ownership.** If you need to
154    ///   preserve the original bi-predicate, clone it first (if it implements
155    ///   `Clone`). Can be:
156    ///   - Another closure: `|x: &T, y: &U| -> bool`
157    ///   - A function pointer: `fn(&T, &U) -> bool`
158    ///   - A `BoxBiPredicate<T, U>`
159    ///   - An `RcBiPredicate<T, U>`
160    ///   - An `ArcBiPredicate<T, U>`
161    ///   - Any type implementing `BiPredicate<T, U>`
162    ///
163    /// # Returns
164    ///
165    /// A `BoxBiPredicate` representing the logical XOR.
166    fn xor<P>(self, other: P) -> BoxBiPredicate<T, U>
167    where
168        Self: 'static,
169        P: BiPredicate<T, U> + 'static,
170        T: 'static,
171        U: 'static,
172    {
173        BoxBiPredicate::new(move |first, second| self(first, second) ^ other.test(first, second))
174    }
175
176    /// Returns a bi-predicate that represents the logical NOR (NOT
177    /// OR) of this bi-predicate and another.
178    ///
179    /// NOR returns `true` only if both bi-predicates are `false`.
180    /// Equivalent to `!(self OR other)`.
181    ///
182    /// # Parameters
183    ///
184    /// * `other` - The other bi-predicate to combine with. **Note: This parameter
185    ///   is passed by value and will transfer ownership.** If you need to
186    ///   preserve the original bi-predicate, clone it first (if it implements
187    ///   `Clone`). Can be:
188    ///   - Another closure: `|x: &T, y: &U| -> bool`
189    ///   - A function pointer: `fn(&T, &U) -> bool`
190    ///   - A `BoxBiPredicate<T, U>`
191    ///   - An `RcBiPredicate<T, U>`
192    ///   - An `ArcBiPredicate<T, U>`
193    ///   - Any type implementing `BiPredicate<T, U>`
194    ///
195    /// # Returns
196    ///
197    /// A `BoxBiPredicate` representing the logical NOR.
198    fn nor<P>(self, other: P) -> BoxBiPredicate<T, U>
199    where
200        Self: 'static,
201        P: BiPredicate<T, U> + 'static,
202        T: 'static,
203        U: 'static,
204    {
205        BoxBiPredicate::new(move |first, second| !(self(first, second) || other.test(first, second)))
206    }
207}
208
209// Blanket implementation for all closures
210impl<T, U, F> FnBiPredicateOps<T, U> for F where F: Fn(&T, &U) -> bool {}