Skip to main content

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);