prism3_function/functions/
bi_function.rs

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