qubit_function/predicates/stateful_bi_predicate/box_stateful_bi_predicate.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 `BoxStatefulBiPredicate` public type.
12
13use std::ops::Not;
14
15use super::{
16 ALWAYS_FALSE_NAME,
17 ALWAYS_TRUE_NAME,
18 RcStatefulBiPredicate,
19 StatefulBiPredicate,
20 impl_box_conversions,
21 impl_predicate_common_methods,
22 impl_predicate_debug_display,
23};
24
25type BoxStatefulBiPredicateFn<T, U> = dyn FnMut(&T, &U) -> bool;
26
27/// A Box-based stateful bi-predicate with single ownership.
28///
29/// This type stores a `Box<dyn FnMut(&T, &U) -> bool>`, so each call may
30/// update the predicate's internal state. Composition methods consume `self`,
31/// matching the single-ownership model.
32pub struct BoxStatefulBiPredicate<T, U> {
33 pub(super) function: Box<BoxStatefulBiPredicateFn<T, U>>,
34 pub(super) name: Option<String>,
35}
36
37impl<T, U> BoxStatefulBiPredicate<T, U> {
38 // Generates: new(), new_with_name(), name(), set_name(), always_true(), always_false()
39 impl_predicate_common_methods!(
40 BoxStatefulBiPredicate<T, U>,
41 (FnMut(&T, &U) -> bool + 'static),
42 |f| Box::new(f)
43 );
44
45 /// Returns a bi-predicate representing logical AND with another predicate.
46 ///
47 /// This method consumes `self` and evaluates `other` only when this
48 /// predicate returns `true`.
49 ///
50 /// # Parameters
51 ///
52 /// * `other` - The other bi-predicate to combine with.
53 ///
54 /// # Returns
55 ///
56 /// A new `BoxStatefulBiPredicate` representing logical AND.
57 #[inline]
58 pub fn and<P>(mut self, mut other: P) -> BoxStatefulBiPredicate<T, U>
59 where
60 P: StatefulBiPredicate<T, U> + 'static,
61 T: 'static,
62 U: 'static,
63 {
64 BoxStatefulBiPredicate::new(move |first, second| {
65 self.test(first, second) && other.test(first, second)
66 })
67 }
68
69 /// Returns a bi-predicate representing logical OR with another predicate.
70 ///
71 /// This method consumes `self` and evaluates `other` only when this
72 /// predicate returns `false`.
73 ///
74 /// # Parameters
75 ///
76 /// * `other` - The other bi-predicate to combine with.
77 ///
78 /// # Returns
79 ///
80 /// A new `BoxStatefulBiPredicate` representing logical OR.
81 #[inline]
82 pub fn or<P>(mut self, mut other: P) -> BoxStatefulBiPredicate<T, U>
83 where
84 P: StatefulBiPredicate<T, U> + 'static,
85 T: 'static,
86 U: 'static,
87 {
88 BoxStatefulBiPredicate::new(move |first, second| {
89 self.test(first, second) || other.test(first, second)
90 })
91 }
92
93 /// Returns a bi-predicate representing logical NAND with another predicate.
94 ///
95 /// NAND returns `true` unless both predicates return `true`.
96 ///
97 /// # Parameters
98 ///
99 /// * `other` - The other bi-predicate to combine with.
100 ///
101 /// # Returns
102 ///
103 /// A new `BoxStatefulBiPredicate` representing logical NAND.
104 #[inline]
105 pub fn nand<P>(mut self, mut other: P) -> BoxStatefulBiPredicate<T, U>
106 where
107 P: StatefulBiPredicate<T, U> + 'static,
108 T: 'static,
109 U: 'static,
110 {
111 BoxStatefulBiPredicate::new(move |first, second| {
112 !(self.test(first, second) && other.test(first, second))
113 })
114 }
115
116 /// Returns a bi-predicate representing logical XOR with another predicate.
117 ///
118 /// XOR evaluates both predicates and returns `true` when exactly one
119 /// predicate returns `true`.
120 ///
121 /// # Parameters
122 ///
123 /// * `other` - The other bi-predicate to combine with.
124 ///
125 /// # Returns
126 ///
127 /// A new `BoxStatefulBiPredicate` representing logical XOR.
128 #[inline]
129 pub fn xor<P>(mut self, mut other: P) -> BoxStatefulBiPredicate<T, U>
130 where
131 P: StatefulBiPredicate<T, U> + 'static,
132 T: 'static,
133 U: 'static,
134 {
135 BoxStatefulBiPredicate::new(move |first, second| {
136 self.test(first, second) ^ other.test(first, second)
137 })
138 }
139
140 /// Returns a bi-predicate representing logical NOR with another predicate.
141 ///
142 /// NOR returns `true` only when both predicates return `false`.
143 ///
144 /// # Parameters
145 ///
146 /// * `other` - The other bi-predicate to combine with.
147 ///
148 /// # Returns
149 ///
150 /// A new `BoxStatefulBiPredicate` representing logical NOR.
151 #[inline]
152 pub fn nor<P>(mut self, mut other: P) -> BoxStatefulBiPredicate<T, U>
153 where
154 P: StatefulBiPredicate<T, U> + 'static,
155 T: 'static,
156 U: 'static,
157 {
158 BoxStatefulBiPredicate::new(move |first, second| {
159 !(self.test(first, second) || other.test(first, second))
160 })
161 }
162}
163
164impl<T, U> Not for BoxStatefulBiPredicate<T, U>
165where
166 T: 'static,
167 U: 'static,
168{
169 type Output = BoxStatefulBiPredicate<T, U>;
170
171 fn not(mut self) -> Self::Output {
172 BoxStatefulBiPredicate::new(move |first, second| !self.test(first, second))
173 }
174}
175
176// Generates: impl Debug for BoxStatefulBiPredicate<T, U> and impl Display for BoxStatefulBiPredicate<T, U>
177impl_predicate_debug_display!(BoxStatefulBiPredicate<T, U>);
178
179impl<T, U> StatefulBiPredicate<T, U> for BoxStatefulBiPredicate<T, U> {
180 fn test(&mut self, first: &T, second: &U) -> bool {
181 (self.function)(first, second)
182 }
183
184 // Generates: into_box(), into_rc(), into_fn()
185 impl_box_conversions!(
186 BoxStatefulBiPredicate<T, U>,
187 RcStatefulBiPredicate,
188 FnMut(&T, &U) -> bool
189 );
190}