qubit_function/predicates/bi_predicate/arc_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 `ArcBiPredicate` public type.
12
13use std::ops::Not;
14
15use super::{
16 ALWAYS_FALSE_NAME,
17 ALWAYS_TRUE_NAME,
18 Arc,
19 BiPredicate,
20 BoxBiPredicate,
21 RcBiPredicate,
22 SendSyncBiPredicateFn,
23 impl_arc_conversions,
24 impl_closure_trait,
25 impl_predicate_clone,
26 impl_predicate_common_methods,
27 impl_predicate_debug_display,
28 impl_shared_predicate_methods,
29};
30
31/// An Arc-based bi-predicate with thread-safe shared ownership.
32///
33/// This type is suitable for scenarios where the bi-predicate needs
34/// to be shared across threads. Composition methods borrow `&self`,
35/// allowing the original bi-predicate to remain usable after
36/// composition.
37///
38/// # Examples
39///
40/// ```rust
41/// use qubit_function::{BiPredicate, ArcBiPredicate};
42///
43/// let pred = ArcBiPredicate::new(|x: &i32, y: &i32| x + y > 0);
44/// assert!(pred.test(&5, &3));
45///
46/// // Original bi-predicate remains usable after composition
47/// let combined = pred.and(ArcBiPredicate::new(|x, y| x > y));
48/// assert!(pred.test(&5, &3)); // Still works
49///
50/// // Can be cloned and sent across threads
51/// let pred_clone = pred.clone();
52/// std::thread::spawn(move || {
53/// assert!(pred_clone.test(&10, &5));
54/// }).join().expect("thread should not panic");
55/// ```
56///
57pub struct ArcBiPredicate<T, U> {
58 pub(super) function: Arc<SendSyncBiPredicateFn<T, U>>,
59 pub(super) name: Option<String>,
60}
61
62impl<T, U> ArcBiPredicate<T, U> {
63 // Generates: new(), new_with_name(), name(), set_name(), always_true(), always_false()
64 impl_predicate_common_methods!(
65 ArcBiPredicate<T, U>,
66 (Fn(&T, &U) -> bool + Send + Sync + 'static),
67 |f| Arc::new(f)
68 );
69
70 // Generates: and(), or(), nand(), xor(), nor()
71 impl_shared_predicate_methods!(
72 ArcBiPredicate<T, U>,
73 Send + Sync + 'static
74 );
75}
76
77impl<T, U> Not for ArcBiPredicate<T, U>
78where
79 T: 'static,
80 U: 'static,
81{
82 type Output = ArcBiPredicate<T, U>;
83
84 fn not(self) -> Self::Output {
85 let function = self.function;
86 ArcBiPredicate::new(move |first, second| !function(first, second))
87 }
88}
89
90impl<T, U> Not for &ArcBiPredicate<T, U>
91where
92 T: 'static,
93 U: 'static,
94{
95 type Output = ArcBiPredicate<T, U>;
96
97 fn not(self) -> Self::Output {
98 let function = self.function.clone();
99 ArcBiPredicate::new(move |first, second| !function(first, second))
100 }
101}
102
103// Generates: impl Clone for ArcBiPredicate<T, U>
104impl_predicate_clone!(ArcBiPredicate<T, U>);
105
106// Generates: impl Debug for ArcBiPredicate<T, U> and impl Display for ArcBiPredicate<T, U>
107impl_predicate_debug_display!(ArcBiPredicate<T, U>);
108
109// Implements BiPredicate trait for ArcBiPredicate<T, U>
110impl<T, U> BiPredicate<T, U> for ArcBiPredicate<T, U> {
111 fn test(&self, first: &T, second: &U) -> bool {
112 (self.function)(first, second)
113 }
114
115 // Generates: into_box, into_rc, into_arc, into_fn, to_box, to_rc, to_arc, to_fn
116 impl_arc_conversions!(
117 ArcBiPredicate<T, U>,
118 BoxBiPredicate,
119 RcBiPredicate,
120 Fn(first: &T, second: &U) -> bool
121 );
122}
123
124// Blanket implementation for all closures that match
125// Fn(&T, &U) -> bool. This provides optimal implementations for
126// closures by wrapping them directly into the target type.
127impl_closure_trait!(
128 BiPredicate<T, U>,
129 test,
130 Fn(first: &T, second: &U) -> bool
131);