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, 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, 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};
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    ///     BoxFunction};
553    ///
554    /// let add = |x: &i32, y: &i32| *x + *y;
555    /// let to_string = BoxFunction::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    /// assert!(both_positive.test(&5, &3));
632    /// ```
633    fn when<P>(self, predicate: P) -> BoxConditionalBiFunction<T, U, R>
634    where
635        Self: 'static,
636        P: BiPredicate<T, U> + 'static,
637        T: 'static,
638        U: 'static,
639        R: 'static,
640    {
641        BoxBiFunction::new(self).when(predicate)
642    }
643}
644
645/// Blanket implementation of FnBiFunctionOps for all closures
646///
647/// Automatically implements `FnBiFunctionOps<T, U, R>` for any type that
648/// implements `Fn(&T, &U) -> R`.
649///
650/// # Author
651///
652/// Haixing Hu
653impl<T, U, R, F> FnBiFunctionOps<T, U, R> for F where F: Fn(&T, &U) -> R {}
654
655// ============================================================================
656// Type Aliases for BinaryOperator (BiFunction<T, T, R>)
657// ============================================================================
658
659/// Type alias for `BoxBiFunction<T, T, R>`
660///
661/// Represents a binary function that takes two values of type `T` and produces
662/// a value of type `R`, with single ownership semantics. Similar to Java's
663/// `BiFunction<T, T, R>` but with different type parameters.
664///
665/// # Examples
666///
667/// ```rust
668/// use qubit_function::{BoxBinaryFunction, BiFunction};
669///
670/// let add: BoxBinaryFunction<i32, i32> = BoxBinaryFunction::new(|x, y| *x + *y);
671/// assert_eq!(add.apply(&20, &22), 42);
672/// ```
673///
674/// # Author
675///
676/// Haixing Hu
677pub type BoxBinaryFunction<T, R> = BoxBiFunction<T, T, R>;
678
679/// Type alias for `ArcBiFunction<T, T, R>`
680///
681/// Represents a thread-safe binary function that takes two values of type `T`
682/// and produces a value of type `R`. Similar to Java's `BiFunction<T, T, R>`
683/// with shared, thread-safe ownership.
684///
685/// # Examples
686///
687/// ```rust
688/// use qubit_function::{ArcBinaryFunction, BiFunction};
689///
690/// let multiply: ArcBinaryFunction<i32, i32> = ArcBinaryFunction::new(|x, y| *x * *y);
691/// let multiply_clone = multiply.clone();
692/// assert_eq!(multiply.apply(&6, &7), 42);
693/// assert_eq!(multiply_clone.apply(&6, &7), 42);
694/// ```
695///
696/// # Author
697///
698/// Haixing Hu
699pub type ArcBinaryFunction<T, R> = ArcBiFunction<T, T, R>;
700
701/// Type alias for `RcBiFunction<T, T, R>`
702///
703/// Represents a single-threaded binary function that takes two values of type `T`
704/// and produces a value of type `R`. Similar to Java's `BiFunction<T, T, R>`
705/// with shared, single-threaded ownership.
706///
707/// # Examples
708///
709/// ```rust
710/// use qubit_function::{RcBinaryFunction, BiFunction};
711///
712/// let max: RcBinaryFunction<i32, i32> = RcBinaryFunction::new(|x, y| if x > y { *x } else { *y });
713/// let max_clone = max.clone();
714/// assert_eq!(max.apply(&30, &42), 42);
715/// assert_eq!(max_clone.apply(&30, &42), 42);
716/// ```
717///
718/// # Author
719///
720/// Haixing Hu
721pub type RcBinaryFunction<T, R> = RcBiFunction<T, T, R>;
722
723// ============================================================================
724// BoxConditionalBiFunction - Box-based Conditional BiFunction
725// ============================================================================
726
727/// BoxConditionalBiFunction struct
728///
729/// A conditional bi-function that only executes when a bi-predicate is
730/// satisfied. Uses `BoxBiFunction` and `BoxBiPredicate` for single
731/// ownership semantics.
732///
733/// This type is typically created by calling `BoxBiFunction::when()` and is
734/// designed to work with the `or_else()` method to create if-then-else logic.
735///
736/// # Features
737///
738/// - **Single Ownership**: Not cloneable, consumes `self` on use
739/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
740/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
741/// - **Implements BiFunction**: Can be used anywhere a `BiFunction` is expected
742///
743/// # Examples
744///
745/// ## With or_else Branch
746///
747/// ```rust
748/// use qubit_function::{BiFunction, BoxBiFunction};
749///
750/// let add = BoxBiFunction::new(|x: &i32, y: &i32| *x + *y);
751/// let multiply = BoxBiFunction::new(|x: &i32, y: &i32| *x * *y);
752/// let conditional = add.when(|x: &i32, y: &i32| *x > 0).or_else(multiply);
753///
754/// assert_eq!(conditional.apply(&5, &3), 8);  // when branch executed
755/// assert_eq!(conditional.apply(&-5, &3), -15); // or_else branch executed
756/// ```
757///
758/// # Author
759///
760/// Haixing Hu
761pub struct BoxConditionalBiFunction<T, U, R> {
762    function: BoxBiFunction<T, U, R>,
763    predicate: BoxBiPredicate<T, U>,
764}
765
766// Implement BoxConditionalBiFunction
767impl_box_conditional_function!(
768    BoxConditionalBiFunction<T, U, R>,
769    BoxBiFunction,
770    BiFunction
771);
772
773// Use macro to generate Debug and Display implementations
774impl_conditional_function_debug_display!(BoxConditionalBiFunction<T, U, R>);
775
776// ============================================================================
777// RcConditionalBiFunction - Rc-based Conditional BiFunction
778// ============================================================================
779
780/// RcConditionalBiFunction struct
781///
782/// A single-threaded conditional bi-function that only executes when a
783/// bi-predicate is satisfied. Uses `RcBiFunction` and `RcBiPredicate` for
784/// shared ownership within a single thread.
785///
786/// This type is typically created by calling `RcBiFunction::when()` and is
787/// designed to work with the `or_else()` method to create if-then-else logic.
788///
789/// # Features
790///
791/// - **Shared Ownership**: Cloneable via `Rc`, multiple owners allowed
792/// - **Single-Threaded**: Not thread-safe, cannot be sent across threads
793/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
794/// - **No Lock Overhead**: More efficient than `ArcConditionalBiFunction`
795///
796/// # Examples
797///
798/// ```rust
799/// use qubit_function::{BiFunction, RcBiFunction};
800///
801/// let add = RcBiFunction::new(|x: &i32, y: &i32| *x + *y);
802/// let multiply = RcBiFunction::new(|x: &i32, y: &i32| *x * *y);
803/// let conditional = add.when(|x: &i32, y: &i32| *x > 0).or_else(multiply);
804///
805/// let conditional_clone = conditional.clone();
806///
807/// assert_eq!(conditional.apply(&5, &3), 8);
808/// assert_eq!(conditional_clone.apply(&-5, &3), -15);
809/// ```
810///
811/// # Author
812///
813/// Haixing Hu
814pub struct RcConditionalBiFunction<T, U, R> {
815    function: RcBiFunction<T, U, R>,
816    predicate: RcBiPredicate<T, U>,
817}
818
819// Implement RcConditionalBiFunction
820impl_shared_conditional_function!(
821    RcConditionalBiFunction<T, U, R>,
822    RcBiFunction,
823    BiFunction,
824    into_rc,
825    'static
826);
827
828// Use macro to generate Debug and Display implementations
829impl_conditional_function_debug_display!(RcConditionalBiFunction<T, U, R>);
830
831// Implement Clone for RcConditionalBiFunction
832impl_conditional_function_clone!(RcConditionalBiFunction<T, U, R>);
833
834// ============================================================================
835// ArcConditionalBiFunction - Arc-based Conditional BiFunction
836// ============================================================================
837
838/// ArcConditionalBiFunction struct
839///
840/// A thread-safe conditional bi-function that only executes when a
841/// bi-predicate is satisfied. Uses `ArcBiFunction` and `ArcBiPredicate` for
842/// shared ownership across threads.
843///
844/// This type is typically created by calling `ArcBiFunction::when()` and is
845/// designed to work with the `or_else()` method to create if-then-else logic.
846///
847/// # Features
848///
849/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
850/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
851/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
852/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
853///
854/// # Examples
855///
856/// ```rust
857/// use qubit_function::{BiFunction, ArcBiFunction};
858///
859/// let add = ArcBiFunction::new(|x: &i32, y: &i32| *x + *y);
860/// let multiply = ArcBiFunction::new(|x: &i32, y: &i32| *x * *y);
861/// let conditional = add.when(|x: &i32, y: &i32| *x > 0).or_else(multiply);
862///
863/// let conditional_clone = conditional.clone();
864///
865/// assert_eq!(conditional.apply(&5, &3), 8);
866/// assert_eq!(conditional_clone.apply(&-5, &3), -15);
867/// ```
868///
869/// # Author
870///
871/// Haixing Hu
872pub struct ArcConditionalBiFunction<T, U, R> {
873    function: ArcBiFunction<T, U, R>,
874    predicate: ArcBiPredicate<T, U>,
875}
876
877// Implement ArcConditionalBiFunction
878impl_shared_conditional_function!(
879    ArcConditionalBiFunction<T, U, R>,
880    ArcBiFunction,
881    BiFunction,
882    into_arc,
883    Send + Sync + 'static
884);
885
886// Implement Debug and Display for ArcConditionalBiFunction
887impl_conditional_function_debug_display!(ArcConditionalBiFunction<T, U, R>);
888
889// Implement Clone for ArcConditionalBiFunction
890impl_conditional_function_clone!(ArcConditionalBiFunction<T, U, R>);