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