qubit_function/predicates/bi_predicate/fn_bi_predicate_ops.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! Defines the `FnBiPredicateOps` public type.
10
11#![allow(unused_imports)]
12
13use super::*;
14
15/// Extension trait providing logical composition methods for closures.
16///
17/// This trait is automatically implemented for all closures and
18/// function pointers that match `Fn(&T, &U) -> bool`, enabling method
19/// chaining starting from a closure.
20///
21/// # Examples
22///
23/// ```rust
24/// use qubit_function::{BiPredicate, FnBiPredicateOps};
25///
26/// let is_sum_positive = |x: &i32, y: &i32| x + y > 0;
27/// let first_larger = |x: &i32, y: &i32| x > y;
28///
29/// // Combine bi-predicates using extension methods
30/// let pred = is_sum_positive.and(first_larger);
31/// assert!(pred.test(&10, &5));
32/// assert!(!pred.test(&3, &8));
33/// ```
34///
35/// # Author
36///
37/// Haixing Hu
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| {
142 !(self(first, second) && other.test(first, second))
143 })
144 }
145
146 /// Returns a bi-predicate that represents the logical XOR
147 /// (exclusive OR) of this bi-predicate and another.
148 ///
149 /// XOR returns `true` if exactly one of the bi-predicates is
150 /// `true`.
151 ///
152 /// # Parameters
153 ///
154 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
155 /// is passed by value and will transfer ownership.** If you need to
156 /// preserve the original bi-predicate, clone it first (if it implements
157 /// `Clone`). Can be:
158 /// - Another closure: `|x: &T, y: &U| -> bool`
159 /// - A function pointer: `fn(&T, &U) -> bool`
160 /// - A `BoxBiPredicate<T, U>`
161 /// - An `RcBiPredicate<T, U>`
162 /// - An `ArcBiPredicate<T, U>`
163 /// - Any type implementing `BiPredicate<T, U>`
164 ///
165 /// # Returns
166 ///
167 /// A `BoxBiPredicate` representing the logical XOR.
168 fn xor<P>(self, other: P) -> BoxBiPredicate<T, U>
169 where
170 Self: 'static,
171 P: BiPredicate<T, U> + 'static,
172 T: 'static,
173 U: 'static,
174 {
175 BoxBiPredicate::new(move |first, second| self(first, second) ^ other.test(first, second))
176 }
177
178 /// Returns a bi-predicate that represents the logical NOR (NOT
179 /// OR) of this bi-predicate and another.
180 ///
181 /// NOR returns `true` only if both bi-predicates are `false`.
182 /// Equivalent to `!(self OR other)`.
183 ///
184 /// # Parameters
185 ///
186 /// * `other` - The other bi-predicate to combine with. **Note: This parameter
187 /// is passed by value and will transfer ownership.** If you need to
188 /// preserve the original bi-predicate, clone it first (if it implements
189 /// `Clone`). Can be:
190 /// - Another closure: `|x: &T, y: &U| -> bool`
191 /// - A function pointer: `fn(&T, &U) -> bool`
192 /// - A `BoxBiPredicate<T, U>`
193 /// - An `RcBiPredicate<T, U>`
194 /// - An `ArcBiPredicate<T, U>`
195 /// - Any type implementing `BiPredicate<T, U>`
196 ///
197 /// # Returns
198 ///
199 /// A `BoxBiPredicate` representing the logical NOR.
200 fn nor<P>(self, other: P) -> BoxBiPredicate<T, U>
201 where
202 Self: 'static,
203 P: BiPredicate<T, U> + 'static,
204 T: 'static,
205 U: 'static,
206 {
207 BoxBiPredicate::new(move |first, second| {
208 !(self(first, second) || other.test(first, second))
209 })
210 }
211}
212
213// Blanket implementation for all closures
214impl<T, U, F> FnBiPredicateOps<T, U> for F where F: Fn(&T, &U) -> bool {}