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