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