Skip to main content

qubit_function/functions/
bi_function.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9
10//! # BiFunction Types
11//!
12//! Provides Rust implementations of bi-function traits for computing output values
13//! from two input references. BiFunctions borrow input values (not consuming them)
14//! and produce output values.
15//!
16//! It is similar to the `Fn(&T, &U) -> R` trait in the standard library.
17//!
18//! This module provides the `BiFunction<T, U, R>` trait and three
19//! implementations:
20//!
21//! - [`BoxBiFunction`]: Single ownership, not cloneable
22//! - [`ArcBiFunction`]: Thread-safe shared ownership, cloneable
23//! - [`RcBiFunction`]: Single-threaded shared ownership, cloneable
24//!
25//! # Author
26//!
27//! Haixing Hu
28use std::rc::Rc;
29use std::sync::Arc;
30
31use crate::functions::{
32    bi_function_once::BoxBiFunctionOnce,
33    function::Function,
34    macros::{
35        impl_box_conditional_function,
36        impl_box_function_methods,
37        impl_conditional_function_clone,
38        impl_conditional_function_debug_display,
39        impl_function_clone,
40        impl_function_common_methods,
41        impl_function_constant_method,
42        impl_function_debug_display,
43        impl_shared_conditional_function,
44        impl_shared_function_methods,
45    },
46};
47use crate::macros::{
48    impl_arc_conversions,
49    impl_box_conversions,
50    impl_closure_trait,
51    impl_rc_conversions,
52};
53use crate::predicates::bi_predicate::{
54    ArcBiPredicate,
55    BiPredicate,
56    BoxBiPredicate,
57    RcBiPredicate,
58};
59
60// ============================================================================
61// Core Trait
62// ============================================================================
63
64/// BiFunction trait - computes output from two input references
65///
66/// Defines the behavior of a bi-function: computing a value of type `R`
67/// from references to types `T` and `U` without consuming the inputs. This is analogous to
68/// `Fn(&T, &U) -> R` in Rust's standard library, similar to Java's `BiFunction<T, U, R>`.
69///
70/// # Type Parameters
71///
72/// * `T` - The type of the first input value (borrowed)
73/// * `U` - The type of the second input value (borrowed)
74/// * `R` - The type of the output value
75///
76/// # Author
77///
78/// Haixing Hu
79pub trait BiFunction<T, U, R> {
80    /// Applies the bi-function to two input references to produce an output value
81    ///
82    /// # Parameters
83    ///
84    /// * `first` - Reference to the first input value
85    /// * `second` - Reference to the second input value
86    ///
87    /// # Returns
88    ///
89    /// The computed output value
90    fn apply(&self, first: &T, second: &U) -> R;
91
92    /// Converts to BoxBiFunction
93    ///
94    /// **⚠️ Consumes `self`**: The original bi-function becomes
95    /// unavailable after calling this method.
96    ///
97    /// # Default Implementation
98    ///
99    /// The default implementation wraps `self` in a `Box` and creates a
100    /// `BoxBiFunction`. Types can override this method to provide more
101    /// efficient conversions.
102    ///
103    /// # Returns
104    ///
105    /// Returns `BoxBiFunction<T, U, R>`
106    fn into_box(self) -> BoxBiFunction<T, U, R>
107    where
108        Self: Sized + 'static,
109    {
110        BoxBiFunction::new(move |t, u| self.apply(t, u))
111    }
112
113    /// Converts to RcBiFunction
114    ///
115    /// **⚠️ Consumes `self`**: The original bi-function becomes
116    /// unavailable after calling this method.
117    ///
118    /// # Default Implementation
119    ///
120    /// The default implementation wraps `self` in an `Rc` and creates an
121    /// `RcBiFunction`. Types can override this method to provide more
122    /// efficient conversions.
123    ///
124    /// # Returns
125    ///
126    /// Returns `RcBiFunction<T, U, R>`
127    fn into_rc(self) -> RcBiFunction<T, U, R>
128    where
129        Self: Sized + 'static,
130    {
131        RcBiFunction::new(move |t, u| self.apply(t, u))
132    }
133
134    /// Converts to ArcBiFunction
135    ///
136    /// **⚠️ Consumes `self`**: The original bi-function becomes
137    /// unavailable after calling this method.
138    ///
139    /// # Default Implementation
140    ///
141    /// The default implementation wraps `self` in an `Arc` and creates
142    /// an `ArcBiFunction`. Types can override this method to provide
143    /// more efficient conversions.
144    ///
145    /// # Returns
146    ///
147    /// Returns `ArcBiFunction<T, U, R>`
148    fn into_arc(self) -> ArcBiFunction<T, U, R>
149    where
150        Self: Sized + Send + Sync + 'static,
151    {
152        ArcBiFunction::new(move |t, u| self.apply(t, u))
153    }
154
155    /// Converts bi-function to a closure
156    ///
157    /// **⚠️ Consumes `self`**: The original bi-function becomes
158    /// unavailable after calling this method.
159    ///
160    /// # Default Implementation
161    ///
162    /// The default implementation creates a closure that captures `self`
163    /// and calls its `apply` method. Types can override this method
164    /// to provide more efficient conversions.
165    ///
166    /// # Returns
167    ///
168    /// Returns a closure that implements `Fn(&T, &U) -> R`
169    fn into_fn(self) -> impl Fn(&T, &U) -> R
170    where
171        Self: Sized + 'static,
172    {
173        move |t, u| self.apply(t, u)
174    }
175
176    /// Converts to BiFunctionOnce
177    ///
178    /// **⚠️ Consumes `self`**: The original bi-function becomes unavailable after calling this method.
179    ///
180    /// Converts a reusable bi-function to a one-time bi-function that consumes itself on use.
181    /// This enables passing `BiFunction` to functions that require `BiFunctionOnce`.
182    ///
183    /// # Returns
184    ///
185    /// Returns a `BoxBiFunctionOnce<T, U, R>`
186    fn into_once(self) -> BoxBiFunctionOnce<T, U, R>
187    where
188        Self: Sized + 'static,
189    {
190        BoxBiFunctionOnce::new(move |t, u| self.apply(t, u))
191    }
192
193    /// Non-consuming conversion to `BoxBiFunction` using `&self`.
194    ///
195    /// Default implementation clones `self` and delegates to `into_box`.
196    fn to_box(&self) -> BoxBiFunction<T, U, R>
197    where
198        Self: Sized + Clone + 'static,
199    {
200        self.clone().into_box()
201    }
202
203    /// Non-consuming conversion to `RcBiFunction` using `&self`.
204    ///
205    /// Default implementation clones `self` and delegates to `into_rc`.
206    fn to_rc(&self) -> RcBiFunction<T, U, R>
207    where
208        Self: Sized + Clone + 'static,
209    {
210        self.clone().into_rc()
211    }
212
213    /// Non-consuming conversion to `ArcBiFunction` using `&self`.
214    ///
215    /// Default implementation clones `self` and delegates to `into_arc`.
216    fn to_arc(&self) -> ArcBiFunction<T, U, R>
217    where
218        Self: Sized + Clone + Send + Sync + 'static,
219    {
220        self.clone().into_arc()
221    }
222
223    /// Non-consuming conversion to a boxed function using `&self`.
224    ///
225    /// Returns a `Box<dyn Fn(&T, &U) -> R>` that clones `self` and calls
226    /// `apply` inside the boxed closure.
227    fn to_fn(&self) -> impl Fn(&T, &U) -> R
228    where
229        Self: Sized + Clone + 'static,
230    {
231        self.clone().into_fn()
232    }
233
234    /// Convert to BiFunctionOnce without consuming self
235    ///
236    /// **⚠️ Requires Clone**: This method requires `Self` to implement `Clone`.
237    /// Clones the current bi-function and converts the clone to a one-time bi-function.
238    ///
239    /// # Returns
240    ///
241    /// Returns a `BoxBiFunctionOnce<T, U, R>`
242    fn to_once(&self) -> BoxBiFunctionOnce<T, U, R>
243    where
244        Self: Clone + 'static,
245    {
246        self.clone().into_once()
247    }
248}
249
250// ============================================================================
251// BoxBiFunction - Box<dyn Fn(&T, &U) -> R>
252// ============================================================================
253
254/// BoxBiFunction - bi-function wrapper based on `Box<dyn Fn>`
255///
256/// A bi-function wrapper that provides single ownership with reusable
257/// computation. Borrows both inputs and can be called multiple times.
258///
259/// # Features
260///
261/// - **Based on**: `Box<dyn Fn(&T, &U) -> R>`
262/// - **Ownership**: Single ownership, cannot be cloned
263/// - **Reusability**: Can be called multiple times (borrows inputs each time)
264/// - **Thread Safety**: Not thread-safe (no `Send + Sync` requirement)
265///
266/// # Author
267///
268/// Haixing Hu
269pub struct BoxBiFunction<T, U, R> {
270    function: Box<dyn Fn(&T, &U) -> R>,
271    name: Option<String>,
272}
273
274// Implement BoxBiFunction
275impl<T, U, R> BoxBiFunction<T, U, R> {
276    impl_function_common_methods!(
277        BoxBiFunction<T, U, R>,
278        (Fn(&T, &U) -> R + 'static),
279        |f| Box::new(f)
280    );
281
282    impl_box_function_methods!(
283        BoxBiFunction<T, U, R>,
284        BoxConditionalBiFunction,
285        Function
286    );
287}
288
289// Implement BiFunction trait for BoxBiFunction
290impl<T, U, R> BiFunction<T, U, R> for BoxBiFunction<T, U, R> {
291    fn apply(&self, first: &T, second: &U) -> R {
292        (self.function)(first, second)
293    }
294
295    // Generates: into_box(), into_rc(), into_fn(), into_once()
296    impl_box_conversions!(
297        BoxBiFunction<T, U, R>,
298        RcBiFunction,
299        Fn(&T, &U) -> R,
300        BoxBiFunctionOnce
301    );
302}
303
304// Implement constant method for BoxBiFunction
305impl_function_constant_method!(BoxBiFunction<T, U, R>);
306
307// Implement Debug and Display for BoxBiFunction
308impl_function_debug_display!(BoxBiFunction<T, U, R>);
309
310// ============================================================================
311// RcBiFunction - Rc<dyn Fn(&T, &U) -> R>
312// ============================================================================
313
314/// RcBiFunction - single-threaded bi-function wrapper
315///
316/// A single-threaded, clonable bi-function wrapper optimized for scenarios
317/// that require sharing without thread-safety overhead.
318///
319/// # Features
320///
321/// - **Based on**: `Rc<dyn Fn(&T, &U) -> R>`
322/// - **Ownership**: Shared ownership via reference counting (non-atomic)
323/// - **Reusability**: Can be called multiple times (borrows inputs each time)
324/// - **Thread Safety**: Not thread-safe (no `Send + Sync`)
325/// - **Clonable**: Cheap cloning via `Rc::clone`
326///
327/// # Author
328///
329/// Haixing Hu
330pub struct RcBiFunction<T, U, R> {
331    function: Rc<dyn Fn(&T, &U) -> R>,
332    name: Option<String>,
333}
334
335impl<T, U, R> RcBiFunction<T, U, R> {
336    impl_function_common_methods!(
337        RcBiFunction<T, U, R>,
338        (Fn(&T, &U) -> R + 'static),
339        |f| Rc::new(f)
340    );
341    impl_shared_function_methods!(
342        RcBiFunction<T, U, R>,
343        RcConditionalBiFunction,
344        into_rc,
345        Function,
346        'static
347    );
348}
349
350// Implement BiFunction trait for RcBiFunction
351impl<T, U, R> BiFunction<T, U, R> for RcBiFunction<T, U, R> {
352    fn apply(&self, first: &T, second: &U) -> R {
353        (self.function)(first, second)
354    }
355
356    // Generate into_box(), into_rc(), into_fn(), into_once(), to_box(), to_rc(), to_fn(), to_once()
357    impl_rc_conversions!(
358        RcBiFunction<T, U, R>,
359        BoxBiFunction,
360        BoxBiFunctionOnce,
361        Fn(first: &T, second: &U) -> R
362    );
363}
364
365// Implement constant method for RcBiFunction
366impl_function_constant_method!(RcBiFunction<T, U, R>);
367
368// Implement Debug and Display for RcBiFunction
369impl_function_debug_display!(RcBiFunction<T, U, R>);
370
371// Implement Clone for RcBiFunction
372impl_function_clone!(RcBiFunction<T, U, R>);
373
374// ============================================================================
375// ArcBiFunction - Arc<dyn Fn(&T, &U) -> R + Send + Sync>
376// ============================================================================
377
378/// ArcBiFunction - thread-safe bi-function wrapper
379///
380/// A thread-safe, clonable bi-function wrapper suitable for multi-threaded
381/// scenarios. Can be called multiple times and shared across threads.
382///
383/// # Features
384///
385/// - **Based on**: `Arc<dyn Fn(&T, &U) -> R + Send + Sync>`
386/// - **Ownership**: Shared ownership via reference counting
387/// - **Reusability**: Can be called multiple times (borrows inputs each time)
388/// - **Thread Safety**: Thread-safe (`Send + Sync` required)
389/// - **Clonable**: Cheap cloning via `Arc::clone`
390///
391/// # Author
392///
393/// Haixing Hu
394pub struct ArcBiFunction<T, U, R> {
395    function: Arc<dyn Fn(&T, &U) -> R + Send + Sync>,
396    name: Option<String>,
397}
398
399impl<T, U, R> ArcBiFunction<T, U, R> {
400    impl_function_common_methods!(
401        ArcBiFunction<T, U, R>,
402        (Fn(&T, &U) -> R + Send + Sync + 'static),
403        |f| Arc::new(f)
404    );
405    impl_shared_function_methods!(
406        ArcBiFunction<T, U, R>,
407        ArcConditionalBiFunction,
408        into_arc,
409        Function,
410        Send + Sync + 'static
411    );
412}
413
414// Implement constant method for ArcBiFunction
415impl_function_constant_method!(ArcBiFunction<T, U, R>, Send + Sync + 'static);
416
417// Implement Debug and Display for ArcBiFunction
418impl_function_debug_display!(ArcBiFunction<T, U, R>);
419
420// Implement Clone for ArcBiFunction
421impl_function_clone!(ArcBiFunction<T, U, R>);
422
423// Implement BiFunction trait for ArcBiFunction
424impl<T, U, R> BiFunction<T, U, R> for ArcBiFunction<T, U, R> {
425    fn apply(&self, first: &T, second: &U) -> R {
426        (self.function)(first, second)
427    }
428
429    // Use macro to implement conversion methods
430    impl_arc_conversions!(
431        ArcBiFunction<T, U, R>,
432        BoxBiFunction,
433        RcBiFunction,
434        BoxBiFunctionOnce,
435        Fn(t: &T, u: &U) -> R
436    );
437}
438
439// ============================================================================
440// Blanket implementation for standard Fn trait
441// ============================================================================
442
443// Implement BiFunction<T, U, R> for any type that implements Fn(&T, &U) -> R
444impl_closure_trait!(
445    BiFunction<T, U, R>,
446    apply,
447    BoxBiFunctionOnce,
448    Fn(first: &T, second: &U) -> R
449);
450
451// ============================================================================
452// FnBiFunctionOps - Extension trait for Fn(&T, &U) -> R bi-functions
453// ============================================================================
454
455/// Extension trait for closures implementing `Fn(&T, &U) -> R`
456///
457/// Provides composition methods (`and_then`, `when`) for bi-function
458/// closures and function pointers without requiring explicit wrapping in
459/// `BoxBiFunction`.
460///
461/// This trait is automatically implemented for all closures and function
462/// pointers that implement `Fn(&T, &U) -> R`.
463///
464/// # Design Rationale
465///
466/// While closures automatically implement `BiFunction<T, U, R>` through
467/// blanket implementation, they don't have access to instance methods like
468/// `and_then` and `when`. This extension trait provides those methods,
469/// returning `BoxBiFunction` for maximum flexibility.
470///
471/// # Examples
472///
473/// ## Chain composition with and_then
474///
475/// ```rust
476/// use qubit_function::{BiFunction, Function, FnBiFunctionOps};
477///
478/// let add = |x: &i32, y: &i32| *x + *y;
479/// let double = |x: &i32| x * 2;
480///
481/// let composed = add.and_then(double);
482/// assert_eq!(composed.apply(&3, &5), 16); // (3 + 5) * 2
483/// ```
484///
485/// ## Conditional execution with when
486///
487/// ```rust
488/// use qubit_function::{BiFunction, BiPredicate, FnBiFunctionOps};
489///
490/// let add = |x: &i32, y: &i32| *x + *y;
491/// let multiply = |x: &i32, y: &i32| *x * *y;
492///
493/// let conditional = add.when(|x: &i32, y: &i32| *x > 0 && *y > 0).or_else(multiply);
494///
495/// assert_eq!(conditional.apply(&5, &3), 8);   // add
496/// assert_eq!(conditional.apply(&-5, &3), -15); // multiply
497/// ```
498///
499/// # Author
500///
501/// Haixing Hu
502pub trait FnBiFunctionOps<T, U, R>: Fn(&T, &U) -> R + Sized {
503    /// Chain composition - applies self first, then after
504    ///
505    /// Creates a new bi-function that applies this bi-function first,
506    /// then applies the after function to the result. Consumes self and
507    /// returns a `BoxBiFunction`.
508    ///
509    /// # Type Parameters
510    ///
511    /// * `S` - The output type of the after function
512    /// * `F` - The type of the after function (must implement Function<R, S>)
513    ///
514    /// # Parameters
515    ///
516    /// * `after` - The function to apply after self. **Note: This parameter
517    ///   is passed by value and will transfer ownership.** If you need to
518    ///   preserve the original function, clone it first (if it implements
519    ///   `Clone`). Can be:
520    ///   - A closure: `|x: R| -> S`
521    ///   - A function pointer: `fn(R) -> S`
522    ///   - A `BoxFunction<R, S>`
523    ///   - An `RcFunction<R, S>`
524    ///   - An `ArcFunction<R, S>`
525    ///   - Any type implementing `Function<R, S>`
526    ///
527    /// # Returns
528    ///
529    /// A new `BoxBiFunction<T, U, S>` representing the composition
530    ///
531    /// # Examples
532    ///
533    /// ## Direct value passing (ownership transfer)
534    ///
535    /// ```rust
536    /// use qubit_function::{BiFunction, FnBiFunctionOps,
537    ///     BoxFunction, Function};
538    ///
539    /// let add = |x: &i32, y: &i32| *x + *y;
540    /// let to_string = BoxFunction::new(|x: &i32| x.to_string());
541    ///
542    /// // to_string is moved here
543    /// let composed = add.and_then(to_string);
544    /// assert_eq!(composed.apply(&20, &22), "42");
545    /// // to_string.apply(10); // Would not compile - moved
546    /// ```
547    ///
548    /// ## Preserving original with clone
549    ///
550    /// ```rust
551    /// use qubit_function::{BiFunction, FnBiFunctionOps,
552    ///     Function, RcFunction};
553    ///
554    /// let add = |x: &i32, y: &i32| *x + *y;
555    /// let to_string = RcFunction::new(|x: &i32| x.to_string());
556    ///
557    /// // Clone to preserve original
558    /// let composed = add.and_then(to_string.clone());
559    /// assert_eq!(composed.apply(&20, &22), "42");
560    ///
561    /// // Original still usable
562    /// assert_eq!(to_string.apply(&10), "10");
563    /// ```
564    fn and_then<S, F>(self, after: F) -> BoxBiFunction<T, U, S>
565    where
566        Self: 'static,
567        S: 'static,
568        F: crate::functions::function::Function<R, S> + 'static,
569        T: 'static,
570        U: 'static,
571        R: 'static,
572    {
573        BoxBiFunction::new(move |t: &T, u: &U| after.apply(&self(t, u)))
574    }
575
576    /// Creates a conditional bi-function
577    ///
578    /// Returns a bi-function that only executes when a bi-predicate is
579    /// satisfied. You must call `or_else()` to provide an alternative
580    /// bi-function for when the condition is not satisfied.
581    ///
582    /// # Parameters
583    ///
584    /// * `predicate` - The condition to check. **Note: This parameter is passed
585    ///   by value and will transfer ownership.** If you need to preserve the
586    ///   original bi-predicate, clone it first (if it implements `Clone`).
587    ///   Can be:
588    ///   - A closure: `|x: &T, y: &U| -> bool`
589    ///   - A function pointer: `fn(&T, &U) -> bool`
590    ///   - A `BoxBiPredicate<T, U>`
591    ///   - An `RcBiPredicate<T, U>`
592    ///   - An `ArcBiPredicate<T, U>`
593    ///   - Any type implementing `BiPredicate<T, U>`
594    ///
595    /// # Returns
596    ///
597    /// Returns `BoxConditionalBiFunction<T, U, R>`
598    ///
599    /// # Examples
600    ///
601    /// ## Basic usage with or_else
602    ///
603    /// ```rust
604    /// use qubit_function::{BiFunction, FnBiFunctionOps};
605    ///
606    /// let add = |x: &i32, y: &i32| *x + *y;
607    /// let conditional = add.when(|x: &i32, y: &i32| *x > 0)
608    ///     .or_else(|x: &i32, y: &i32| *x * *y);
609    ///
610    /// assert_eq!(conditional.apply(&5, &3), 8);
611    /// assert_eq!(conditional.apply(&-5, &3), -15);
612    /// ```
613    ///
614    /// ## Preserving bi-predicate with clone
615    ///
616    /// ```rust
617    /// use qubit_function::{BiFunction, FnBiFunctionOps,
618    ///     RcBiPredicate};
619    ///
620    /// let add = |x: &i32, y: &i32| *x + *y;
621    /// let both_positive = RcBiPredicate::new(|x: &i32, y: &i32|
622    ///     *x > 0 && *y > 0);
623    ///
624    /// // Clone to preserve original bi-predicate
625    /// let conditional = add.when(both_positive.clone())
626    ///     .or_else(|x: &i32, y: &i32| *x * *y);
627    ///
628    /// assert_eq!(conditional.apply(&5, &3), 8);
629    ///
630    /// // Original bi-predicate still usable
631    /// use qubit_function::BiPredicate;
632    /// assert!(both_positive.test(&5, &3));
633    /// ```
634    fn when<P>(self, predicate: P) -> BoxConditionalBiFunction<T, U, R>
635    where
636        Self: 'static,
637        P: BiPredicate<T, U> + 'static,
638        T: 'static,
639        U: 'static,
640        R: 'static,
641    {
642        BoxBiFunction::new(self).when(predicate)
643    }
644}
645
646/// Blanket implementation of FnBiFunctionOps for all closures
647///
648/// Automatically implements `FnBiFunctionOps<T, U, R>` for any type that
649/// implements `Fn(&T, &U) -> R`.
650///
651/// # Author
652///
653/// Haixing Hu
654impl<T, U, R, F> FnBiFunctionOps<T, U, R> for F where F: Fn(&T, &U) -> R {}
655
656// ============================================================================
657// Type Aliases for BinaryOperator (BiFunction<T, T, R>)
658// ============================================================================
659
660/// Type alias for `BoxBiFunction<T, T, R>`
661///
662/// Represents a binary function that takes two values of type `T` and produces
663/// a value of type `R`, with single ownership semantics. Similar to Java's
664/// `BiFunction<T, T, R>` but with different type parameters.
665///
666/// # Examples
667///
668/// ```rust
669/// use qubit_function::{BoxBinaryFunction, BiFunction};
670///
671/// let add: BoxBinaryFunction<i32, i32> = BoxBinaryFunction::new(|x, y| *x + *y);
672/// assert_eq!(add.apply(&20, &22), 42);
673/// ```
674///
675/// # Author
676///
677/// Haixing Hu
678pub type BoxBinaryFunction<T, R> = BoxBiFunction<T, T, R>;
679
680/// Type alias for `ArcBiFunction<T, T, R>`
681///
682/// Represents a thread-safe binary function that takes two values of type `T`
683/// and produces a value of type `R`. Similar to Java's `BiFunction<T, T, R>`
684/// with shared, thread-safe ownership.
685///
686/// # Examples
687///
688/// ```rust
689/// use qubit_function::{ArcBinaryFunction, BiFunction};
690///
691/// let multiply: ArcBinaryFunction<i32, i32> = ArcBinaryFunction::new(|x, y| *x * *y);
692/// let multiply_clone = multiply.clone();
693/// assert_eq!(multiply.apply(&6, &7), 42);
694/// assert_eq!(multiply_clone.apply(&6, &7), 42);
695/// ```
696///
697/// # Author
698///
699/// Haixing Hu
700pub type ArcBinaryFunction<T, R> = ArcBiFunction<T, T, R>;
701
702/// Type alias for `RcBiFunction<T, T, R>`
703///
704/// Represents a single-threaded binary function that takes two values of type `T`
705/// and produces a value of type `R`. Similar to Java's `BiFunction<T, T, R>`
706/// with shared, single-threaded ownership.
707///
708/// # Examples
709///
710/// ```rust
711/// use qubit_function::{RcBinaryFunction, BiFunction};
712///
713/// let max: RcBinaryFunction<i32, i32> = RcBinaryFunction::new(|x, y| if x > y { *x } else { *y });
714/// let max_clone = max.clone();
715/// assert_eq!(max.apply(&30, &42), 42);
716/// assert_eq!(max_clone.apply(&30, &42), 42);
717/// ```
718///
719/// # Author
720///
721/// Haixing Hu
722pub type RcBinaryFunction<T, R> = RcBiFunction<T, T, R>;
723
724// ============================================================================
725// BoxConditionalBiFunction - Box-based Conditional BiFunction
726// ============================================================================
727
728/// BoxConditionalBiFunction struct
729///
730/// A conditional bi-function that only executes when a bi-predicate is
731/// satisfied. Uses `BoxBiFunction` and `BoxBiPredicate` for single
732/// ownership semantics.
733///
734/// This type is typically created by calling `BoxBiFunction::when()` and is
735/// designed to work with the `or_else()` method to create if-then-else logic.
736///
737/// # Features
738///
739/// - **Single Ownership**: Not cloneable, consumes `self` on use
740/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
741/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
742/// - **Implements BiFunction**: Can be used anywhere a `BiFunction` is expected
743///
744/// # Examples
745///
746/// ## With or_else Branch
747///
748/// ```rust
749/// use qubit_function::{BiFunction, BoxBiFunction};
750///
751/// let add = BoxBiFunction::new(|x: &i32, y: &i32| *x + *y);
752/// let multiply = BoxBiFunction::new(|x: &i32, y: &i32| *x * *y);
753/// let conditional = add.when(|x: &i32, y: &i32| *x > 0).or_else(multiply);
754///
755/// assert_eq!(conditional.apply(&5, &3), 8);  // when branch executed
756/// assert_eq!(conditional.apply(&-5, &3), -15); // or_else branch executed
757/// ```
758///
759/// # Author
760///
761/// Haixing Hu
762pub struct BoxConditionalBiFunction<T, U, R> {
763    function: BoxBiFunction<T, U, R>,
764    predicate: BoxBiPredicate<T, U>,
765}
766
767// Implement BoxConditionalBiFunction
768impl_box_conditional_function!(
769    BoxConditionalBiFunction<T, U, R>,
770    BoxBiFunction,
771    BiFunction
772);
773
774// Use macro to generate Debug and Display implementations
775impl_conditional_function_debug_display!(BoxConditionalBiFunction<T, U, R>);
776
777// ============================================================================
778// RcConditionalBiFunction - Rc-based Conditional BiFunction
779// ============================================================================
780
781/// RcConditionalBiFunction struct
782///
783/// A single-threaded conditional bi-function that only executes when a
784/// bi-predicate is satisfied. Uses `RcBiFunction` and `RcBiPredicate` for
785/// shared ownership within a single thread.
786///
787/// This type is typically created by calling `RcBiFunction::when()` and is
788/// designed to work with the `or_else()` method to create if-then-else logic.
789///
790/// # Features
791///
792/// - **Shared Ownership**: Cloneable via `Rc`, multiple owners allowed
793/// - **Single-Threaded**: Not thread-safe, cannot be sent across threads
794/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
795/// - **No Lock Overhead**: More efficient than `ArcConditionalBiFunction`
796///
797/// # Examples
798///
799/// ```rust
800/// use qubit_function::{BiFunction, RcBiFunction};
801///
802/// let add = RcBiFunction::new(|x: &i32, y: &i32| *x + *y);
803/// let multiply = RcBiFunction::new(|x: &i32, y: &i32| *x * *y);
804/// let conditional = add.when(|x: &i32, y: &i32| *x > 0).or_else(multiply);
805///
806/// let conditional_clone = conditional.clone();
807///
808/// assert_eq!(conditional.apply(&5, &3), 8);
809/// assert_eq!(conditional_clone.apply(&-5, &3), -15);
810/// ```
811///
812/// # Author
813///
814/// Haixing Hu
815pub struct RcConditionalBiFunction<T, U, R> {
816    function: RcBiFunction<T, U, R>,
817    predicate: RcBiPredicate<T, U>,
818}
819
820// Implement RcConditionalBiFunction
821impl_shared_conditional_function!(
822    RcConditionalBiFunction<T, U, R>,
823    RcBiFunction,
824    BiFunction,
825    into_rc,
826    'static
827);
828
829// Use macro to generate Debug and Display implementations
830impl_conditional_function_debug_display!(RcConditionalBiFunction<T, U, R>);
831
832// Implement Clone for RcConditionalBiFunction
833impl_conditional_function_clone!(RcConditionalBiFunction<T, U, R>);
834
835// ============================================================================
836// ArcConditionalBiFunction - Arc-based Conditional BiFunction
837// ============================================================================
838
839/// ArcConditionalBiFunction struct
840///
841/// A thread-safe conditional bi-function that only executes when a
842/// bi-predicate is satisfied. Uses `ArcBiFunction` and `ArcBiPredicate` for
843/// shared ownership across threads.
844///
845/// This type is typically created by calling `ArcBiFunction::when()` and is
846/// designed to work with the `or_else()` method to create if-then-else logic.
847///
848/// # Features
849///
850/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
851/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
852/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
853/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
854///
855/// # Examples
856///
857/// ```rust
858/// use qubit_function::{BiFunction, ArcBiFunction};
859///
860/// let add = ArcBiFunction::new(|x: &i32, y: &i32| *x + *y);
861/// let multiply = ArcBiFunction::new(|x: &i32, y: &i32| *x * *y);
862/// let conditional = add.when(|x: &i32, y: &i32| *x > 0).or_else(multiply);
863///
864/// let conditional_clone = conditional.clone();
865///
866/// assert_eq!(conditional.apply(&5, &3), 8);
867/// assert_eq!(conditional_clone.apply(&-5, &3), -15);
868/// ```
869///
870/// # Author
871///
872/// Haixing Hu
873pub struct ArcConditionalBiFunction<T, U, R> {
874    function: ArcBiFunction<T, U, R>,
875    predicate: ArcBiPredicate<T, U>,
876}
877
878// Implement ArcConditionalBiFunction
879impl_shared_conditional_function!(
880    ArcConditionalBiFunction<T, U, R>,
881    ArcBiFunction,
882    BiFunction,
883    into_arc,
884    Send + Sync + 'static
885);
886
887// Implement Debug and Display for ArcConditionalBiFunction
888impl_conditional_function_debug_display!(ArcConditionalBiFunction<T, U, R>);
889
890// Implement Clone for ArcConditionalBiFunction
891impl_conditional_function_clone!(ArcConditionalBiFunction<T, U, R>);