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 {}