prism3_function/functions/
bi_mutating_function.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025.
4 *    3-Prism Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9
10//! # BiMutatingFunction Types
11//!
12//! Provides Rust implementations of bi-mutating-function traits for performing
13//! operations that accept two mutable references and return a result.
14//!
15//! It is similar to the `Fn(&mut T, &mut U) -> R` trait in the standard library.
16//!
17//! This module provides the `BiMutatingFunction<T, U, R>` trait and three
18//! implementations:
19//!
20//! - [`BoxBiMutatingFunction`]: Single ownership, not cloneable
21//! - [`ArcBiMutatingFunction`]: Thread-safe shared ownership, cloneable
22//! - [`RcBiMutatingFunction`]: Single-threaded shared ownership, cloneable
23//!
24//! # Author
25//!
26//! Haixing Hu
27
28use std::rc::Rc;
29use std::sync::Arc;
30
31use crate::functions::{
32    bi_mutating_function_once::BoxBiMutatingFunctionOnce,
33    macros::{
34        impl_box_conditional_function,
35        impl_box_function_methods,
36        impl_conditional_function_clone,
37        impl_conditional_function_debug_display,
38        impl_function_clone,
39        impl_function_common_methods,
40        impl_function_constant_method,
41        impl_function_debug_display,
42        impl_shared_conditional_function,
43        impl_shared_function_methods,
44    },
45    mutating_function::MutatingFunction,
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/// BiMutatingFunction trait - performs operations on two mutable references
65///
66/// Defines the behavior of a bi-mutating-function: computing a value of type `R`
67/// from mutable references to types `T` and `U`, potentially modifying both inputs.
68/// This is analogous to `Fn(&mut T, &mut U) -> R` in Rust's standard library.
69///
70/// # Type Parameters
71///
72/// * `T` - The type of the first input value (mutable reference)
73/// * `U` - The type of the second input value (mutable reference)
74/// * `R` - The type of the output value
75///
76/// # Author
77///
78/// Haixing Hu
79pub trait BiMutatingFunction<T, U, R> {
80    /// Applies the bi-mutating-function to two mutable references and returns a result
81    ///
82    /// # Parameters
83    ///
84    /// * `first` - Mutable reference to the first input value
85    /// * `second` - Mutable reference to the second input value
86    ///
87    /// # Returns
88    ///
89    /// The computed output value
90    fn apply(&self, first: &mut T, second: &mut U) -> R;
91
92    /// Converts to BoxBiMutatingFunction
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    /// `BoxBiMutatingFunction`. Types can override this method to provide more
101    /// efficient conversions.
102    ///
103    /// # Returns
104    ///
105    /// Returns `BoxBiMutatingFunction<T, U, R>`
106    fn into_box(self) -> BoxBiMutatingFunction<T, U, R>
107    where
108        Self: Sized + 'static,
109        T: 'static,
110        U: 'static,
111        R: 'static,
112    {
113        BoxBiMutatingFunction::new(move |t, u| self.apply(t, u))
114    }
115
116    /// Converts to RcBiMutatingFunction
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    /// `RcBiMutatingFunction`. Types can override this method to provide more
125    /// efficient conversions.
126    ///
127    /// # Returns
128    ///
129    /// Returns `RcBiMutatingFunction<T, U, R>`
130    fn into_rc(self) -> RcBiMutatingFunction<T, U, R>
131    where
132        Self: Sized + 'static,
133        T: 'static,
134        U: 'static,
135        R: 'static,
136    {
137        RcBiMutatingFunction::new(move |t, u| self.apply(t, u))
138    }
139
140    /// Converts to ArcBiMutatingFunction
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 `ArcBiMutatingFunction`. Types can override this method to provide
149    /// more efficient conversions.
150    ///
151    /// # Returns
152    ///
153    /// Returns `ArcBiMutatingFunction<T, U, R>`
154    fn into_arc(self) -> ArcBiMutatingFunction<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        ArcBiMutatingFunction::new(move |t, u| self.apply(t, u))
162    }
163
164    /// Converts bi-mutating-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(&mut T, &mut U) -> R`
178    fn into_fn(self) -> impl Fn(&mut T, &mut 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 BiMutatingFunctionOnce
189    ///
190    /// **⚠️ Consumes `self`**: The original bi-function becomes unavailable after calling this method.
191    ///
192    /// Converts a reusable bi-mutating-function to a one-time bi-mutating-function that consumes itself on use.
193    /// This enables passing `BiMutatingFunction` to functions that require `BiMutatingFunctionOnce`.
194    ///
195    /// # Returns
196    ///
197    /// Returns a `BoxBiMutatingFunctionOnce<T, U, R>`
198    fn into_once(self) -> BoxBiMutatingFunctionOnce<T, U, R>
199    where
200        Self: Sized + 'static,
201        T: 'static,
202        U: 'static,
203        R: 'static,
204    {
205        BoxBiMutatingFunctionOnce::new(move |t, u| self.apply(t, u))
206    }
207
208    /// Non-consuming conversion to `BoxBiMutatingFunction` using `&self`.
209    ///
210    /// Default implementation clones `self` and delegates to `into_box`.
211    fn to_box(&self) -> BoxBiMutatingFunction<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 `RcBiMutatingFunction` using `&self`.
222    ///
223    /// Default implementation clones `self` and delegates to `into_rc`.
224    fn to_rc(&self) -> RcBiMutatingFunction<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 `ArcBiMutatingFunction` using `&self`.
235    ///
236    /// Default implementation clones `self` and delegates to `into_arc`.
237    fn to_arc(&self) -> ArcBiMutatingFunction<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(&mut T, &mut U) -> R>` that clones `self` and calls
250    /// `apply` inside the boxed closure.
251    fn to_fn(&self) -> impl Fn(&mut T, &mut 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 BiMutatingFunctionOnce 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 `BoxBiMutatingFunctionOnce<T, U, R>`
269    fn to_once(&self) -> BoxBiMutatingFunctionOnce<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// BoxBiMutatingFunction - Box<dyn Fn(&mut T, &mut U) -> R>
282// ============================================================================
283
284/// BoxBiMutatingFunction - bi-mutating-function wrapper based on `Box<dyn Fn>`
285///
286/// A bi-mutating-function wrapper that provides single ownership with reusable
287/// computation. Borrows both inputs mutably and can be called multiple times.
288///
289/// # Features
290///
291/// - **Based on**: `Box<dyn Fn(&mut T, &mut U) -> R>`
292/// - **Ownership**: Single ownership, cannot be cloned
293/// - **Reusability**: Can be called multiple times (borrows inputs mutably each time)
294/// - **Thread Safety**: Not thread-safe (no `Send + Sync` requirement)
295///
296/// # Author
297///
298/// Haixing Hu
299pub struct BoxBiMutatingFunction<T, U, R> {
300    function: Box<dyn Fn(&mut T, &mut U) -> R>,
301    name: Option<String>,
302}
303
304// Implement BoxBiMutatingFunction
305impl<T, U, R> BoxBiMutatingFunction<T, U, R>
306where
307    T: 'static,
308    U: 'static,
309    R: 'static,
310{
311    // Generates: new(), new_with_name(), new_with_optional_name(), name(), set_name()
312    impl_function_common_methods!(
313        BoxBiMutatingFunction<T, U, R>,
314        (Fn(&mut T, &mut U) -> R + 'static),
315        |f| Box::new(f)
316    );
317
318    // Generates: when(), and_then()
319    impl_box_function_methods!(
320        BoxBiMutatingFunction<T, U, R>,
321        BoxConditionalBiMutatingFunction,
322        MutatingFunction
323    );
324}
325
326// Implement BiMutatingFunction trait for BoxBiMutatingFunction
327impl<T, U, R> BiMutatingFunction<T, U, R> for BoxBiMutatingFunction<T, U, R> {
328    fn apply(&self, first: &mut T, second: &mut U) -> R {
329        (self.function)(first, second)
330    }
331
332    // Generates: into_box(), into_rc(), into_fn(), into_once()
333    impl_box_conversions!(
334        BoxBiMutatingFunction<T, U, R>,
335        RcBiMutatingFunction,
336        Fn(&mut T, &mut U) -> R,
337        BoxBiMutatingFunctionOnce
338    );
339}
340
341// Implement constant method for BoxBiMutatingFunction
342impl_function_constant_method!(BoxBiMutatingFunction<T, U, R>);
343
344// Implement Debug and Display for BoxBiMutatingFunction
345impl_function_debug_display!(BoxBiMutatingFunction<T, U, R>);
346
347// ============================================================================
348// RcBiMutatingFunction - Rc<dyn Fn(&mut T, &mut U) -> R>
349// ============================================================================
350
351/// RcBiMutatingFunction - single-threaded bi-mutating-function wrapper
352///
353/// A single-threaded, clonable bi-mutating-function wrapper optimized for scenarios
354/// that require sharing without thread-safety overhead.
355///
356/// # Features
357///
358/// - **Based on**: `Rc<dyn Fn(&mut T, &mut U) -> R>`
359/// - **Ownership**: Shared ownership via reference counting (non-atomic)
360/// - **Reusability**: Can be called multiple times (borrows inputs mutably each time)
361/// - **Thread Safety**: Not thread-safe (no `Send + Sync`)
362/// - **Clonable**: Cheap cloning via `Rc::clone`
363///
364/// # Author
365///
366/// Haixing Hu
367pub struct RcBiMutatingFunction<T, U, R> {
368    function: Rc<dyn Fn(&mut T, &mut U) -> R>,
369    name: Option<String>,
370}
371
372impl<T, U, R> RcBiMutatingFunction<T, U, R>
373where
374    T: 'static,
375    U: 'static,
376    R: 'static,
377{
378    // Generates: new(), new_with_name(), new_with_optional_name(), name(), set_name()
379    impl_function_common_methods!(
380        RcBiMutatingFunction<T, U, R>,
381        (Fn(&mut T, &mut U) -> R + 'static),
382        |f| Rc::new(f)
383    );
384
385    // Generate into_box(), into_rc(), into_fn(), into_once(), to_box(), to_rc(), to_fn(), to_once()
386    impl_shared_function_methods!(
387        RcBiMutatingFunction<T, U, R>,
388        RcConditionalBiMutatingFunction,
389        into_rc,
390        MutatingFunction,
391        'static
392    );
393}
394
395// Implement BiMutatingFunction trait for RcBiMutatingFunction
396impl<T, U, R> BiMutatingFunction<T, U, R> for RcBiMutatingFunction<T, U, R> {
397    fn apply(&self, first: &mut T, second: &mut U) -> R {
398        (self.function)(first, second)
399    }
400
401    // Generate into_box(), into_rc(), into_fn(), into_once(), to_box(), to_rc(), to_fn(), to_once()
402    impl_rc_conversions!(
403        RcBiMutatingFunction<T, U, R>,
404        BoxBiMutatingFunction,
405        BoxBiMutatingFunctionOnce,
406        Fn(first: &mut T, second: &mut U) -> R
407    );
408}
409
410// Implement constant method for RcBiMutatingFunction
411impl_function_constant_method!(RcBiMutatingFunction<T, U, R>);
412
413// Implement Debug and Display for RcBiMutatingFunction
414impl_function_debug_display!(RcBiMutatingFunction<T, U, R>);
415
416// Implement Clone for RcBiMutatingFunction
417impl_function_clone!(RcBiMutatingFunction<T, U, R>);
418
419// ============================================================================
420// ArcBiMutatingFunction - Arc<dyn Fn(&mut T, &mut U) -> R + Send + Sync>
421// ============================================================================
422
423/// ArcBiMutatingFunction - thread-safe bi-mutating-function wrapper
424///
425/// A thread-safe, clonable bi-mutating-function wrapper suitable for multi-threaded
426/// scenarios. Can be called multiple times and shared across threads.
427///
428/// # Features
429///
430/// - **Based on**: `Arc<dyn Fn(&mut T, &mut U) -> R + Send + Sync>`
431/// - **Ownership**: Shared ownership via reference counting
432/// - **Reusability**: Can be called multiple times (borrows inputs mutably each time)
433/// - **Thread Safety**: Thread-safe (`Send + Sync` required)
434/// - **Clonable**: Cheap cloning via `Arc::clone`
435///
436/// # Author
437///
438/// Haixing Hu
439pub struct ArcBiMutatingFunction<T, U, R> {
440    function: Arc<dyn Fn(&mut T, &mut U) -> R + Send + Sync>,
441    name: Option<String>,
442}
443
444impl<T, U, R> ArcBiMutatingFunction<T, U, R>
445where
446    T: 'static,
447    U: 'static,
448    R: 'static,
449{
450    // Generates: new(), new_with_name(), new_with_optional_name(), name(), set_name()
451    impl_function_common_methods!(
452        ArcBiMutatingFunction<T, U, R>,
453        (Fn(&mut T, &mut U) -> R + Send + Sync + 'static),
454        |f| Arc::new(f)
455    );
456
457    // Generate into_box(), into_rc(), into_fn(), into_once(), to_box(), to_rc(), to_fn(), to_once()
458    impl_shared_function_methods!(
459        ArcBiMutatingFunction<T, U, R>,
460        ArcConditionalBiMutatingFunction,
461        into_arc,
462        MutatingFunction,
463        Send + Sync + 'static
464    );
465}
466
467// Implement BiMutatingFunction trait for ArcBiMutatingFunction
468impl<T, U, R> BiMutatingFunction<T, U, R> for ArcBiMutatingFunction<T, U, R> {
469    fn apply(&self, first: &mut T, second: &mut U) -> R {
470        (self.function)(first, second)
471    }
472
473    // Generate into_box(), into_rc(), into_fn(), into_once(), to_box(), to_rc(), to_fn(), to_once()
474    impl_arc_conversions!(
475        ArcBiMutatingFunction<T, U, R>,
476        BoxBiMutatingFunction,
477        RcBiMutatingFunction,
478        BoxBiMutatingFunctionOnce,
479        Fn(first: &mut T, second: &mut U) -> R
480    );
481}
482
483// Implement constant method for ArcBiMutatingFunction
484impl_function_constant_method!(ArcBiMutatingFunction<T, U, R>, Send + Sync + 'static);
485
486// Implement Debug and Display for ArcBiMutatingFunction
487impl_function_debug_display!(ArcBiMutatingFunction<T, U, R>);
488
489// Implement Clone for ArcBiMutatingFunction
490impl_function_clone!(ArcBiMutatingFunction<T, U, R>);
491
492// ============================================================================
493// Blanket implementation for standard Fn trait
494// ============================================================================
495
496// Implement BiMutatingFunction<T, U, R> for any type that implements Fn(&mut T, &mut U) -> R
497impl_closure_trait!(
498    BiMutatingFunction<T, U, R>,
499    apply,
500    BoxBiMutatingFunctionOnce,
501    Fn(first: &mut T, second: &mut U) -> R
502);
503
504// ============================================================================
505// FnBiMutatingFunctionOps - Extension trait for Fn(&mut T, &mut U) -> R bi-functions
506// ============================================================================
507
508/// Extension trait for closures implementing `Fn(&mut T, &mut U) -> R`
509///
510/// Provides composition methods (`and_then`, `when`) for bi-mutating-function
511/// closures and function pointers without requiring explicit wrapping in
512/// `BoxBiMutatingFunction`.
513///
514/// This trait is automatically implemented for all closures and function
515/// pointers that implement `Fn(&mut T, &mut U) -> R`.
516///
517/// # Design Rationale
518///
519/// While closures automatically implement `BiMutatingFunction<T, U, R>` through
520/// blanket implementation, they don't have access to instance methods like
521/// `and_then` and `when`. This extension trait provides those methods,
522/// returning `BoxBiMutatingFunction` for maximum flexibility.
523///
524/// # Examples
525///
526/// ## Chain composition with and_then
527///
528/// ```rust
529/// use prism3_function::{BiMutatingFunction, FnBiMutatingFunctionOps};
530///
531/// let swap_and_sum = |x: &mut i32, y: &mut i32| {
532///     let temp = *x;
533///     *x = *y;
534///     *y = temp;
535///     *x + *y
536/// };
537/// let double = |x: i32| x * 2;
538///
539/// let composed = swap_and_sum.and_then(double);
540/// let mut a = 3;
541/// let mut b = 5;
542/// assert_eq!(composed.apply(&mut a, &mut b), 16); // (5 + 3) * 2 = 16
543/// ```
544///
545/// ## Conditional execution with when
546///
547/// ```rust
548/// use prism3_function::{BiMutatingFunction, FnBiMutatingFunctionOps};
549///
550/// let swap_and_sum = |x: &mut i32, y: &mut i32| {
551///     let temp = *x;
552///     *x = *y;
553///     *y = temp;
554///     *x + *y
555/// };
556/// let multiply = |x: &mut i32, y: &mut i32| {
557///     *x *= *y;
558///     *x
559/// };
560///
561/// let conditional = swap_and_sum.when(|x: &mut i32, y: &mut i32| *x > 0 && *y > 0).or_else(multiply);
562///
563/// let mut a = 5;
564/// let mut b = 3;
565/// assert_eq!(conditional.apply(&mut a, &mut b), 8);   // swap_and_sum: (3 + 5)
566///
567/// let mut a = -5;
568/// let mut b = 3;
569/// assert_eq!(conditional.apply(&mut a, &mut b), -15); // multiply: (-5 * 3)
570/// ```
571///
572/// # Author
573///
574/// Haixing Hu
575pub trait FnBiMutatingFunctionOps<T, U, R>: Fn(&mut T, &mut U) -> R + Sized + 'static {
576    /// Chain composition - applies self first, then after
577    ///
578    /// Creates a new bi-mutating-function that applies this bi-mutating-function first,
579    /// then applies the after function to the result. Consumes self and
580    /// returns a `BoxBiMutatingFunction`.
581    ///
582    /// # Type Parameters
583    ///
584    /// * `S` - The output type of the after function
585    /// * `F` - The type of the after function (must implement Function<R, S>)
586    ///
587    /// # Parameters
588    ///
589    /// * `after` - The function to apply after self. **Note: This parameter
590    ///   is passed by value and will transfer ownership.** If you need to
591    ///   preserve the original function, clone it first (if it implements
592    ///   `Clone`). Can be:
593    ///   - A closure: `|x: R| -> S`
594    ///   - A function pointer: `fn(R) -> S`
595    ///   - A `BoxFunction<R, S>`
596    ///   - An `RcFunction<R, S>`
597    ///   - An `ArcFunction<R, S>`
598    ///   - Any type implementing `Function<R, S>`
599    ///
600    /// # Returns
601    ///
602    /// A new `BoxBiMutatingFunction<T, U, S>` representing the composition
603    ///
604    /// # Examples
605    ///
606    /// ## Direct value passing (ownership transfer)
607    ///
608    /// ```rust
609    /// use prism3_function::{BiMutatingFunction, FnBiMutatingFunctionOps,
610    ///     BoxFunction};
611    ///
612    /// let swap = |x: &mut i32, y: &mut i32| {
613    ///     let temp = *x;
614    ///     *x = *y;
615    ///     *y = temp;
616    ///     *x + *y
617    /// };
618    /// let to_string = BoxFunction::new(|x: i32| x.to_string());
619    ///
620    /// // to_string is moved here
621    /// let composed = swap.and_then(to_string);
622    /// let mut a = 20;
623    /// let mut b = 22;
624    /// assert_eq!(composed.apply(&mut a, &mut b), "42");
625    /// // to_string.apply(10); // Would not compile - moved
626    /// ```
627    ///
628    /// ## Preserving original with clone
629    ///
630    /// ```rust
631    /// use prism3_function::{BiMutatingFunction, FnBiMutatingFunctionOps,
632    ///     BoxFunction};
633    ///
634    /// let swap = |x: &mut i32, y: &mut i32| {
635    ///     let temp = *x;
636    ///     *x = *y;
637    ///     *y = temp;
638    ///     *x + *y
639    /// };
640    /// let to_string = BoxFunction::new(|x: i32| x.to_string());
641    ///
642    /// // Clone to preserve original
643    /// let composed = swap.and_then(to_string.clone());
644    /// let mut a = 20;
645    /// let mut b = 22;
646    /// assert_eq!(composed.apply(&mut a, &mut b), "42");
647    ///
648    /// // Original still usable
649    /// assert_eq!(to_string.apply(&10), "10");
650    /// ```
651    fn and_then<S, F>(self, after: F) -> BoxBiMutatingFunction<T, U, S>
652    where
653        S: 'static,
654        F: crate::functions::function::Function<R, S> + 'static,
655        T: 'static,
656        U: 'static,
657        R: 'static,
658    {
659        BoxBiMutatingFunction::new(move |t: &mut T, u: &mut U| after.apply(&self(t, u)))
660    }
661
662    /// Creates a conditional bi-mutating-function
663    ///
664    /// Returns a bi-mutating-function that only executes when a bi-predicate is
665    /// satisfied. You must call `or_else()` to provide an alternative
666    /// bi-mutating-function for when the condition is not satisfied.
667    ///
668    /// # Parameters
669    ///
670    /// * `predicate` - The condition to check. **Note: This parameter is passed
671    ///   by value and will transfer ownership.** If you need to preserve the
672    ///   original bi-predicate, clone it first (if it implements `Clone`).
673    ///   Can be:
674    ///   - A closure: `|x: &mut T, y: &mut U| -> bool`
675    ///   - A function pointer: `fn(&mut T, &mut U) -> bool`
676    ///   - A `BoxBiPredicate<T, U>`
677    ///   - An `RcBiPredicate<T, U>`
678    ///   - An `ArcBiPredicate<T, U>`
679    ///   - Any type implementing `BiPredicate<T, U>`
680    ///
681    /// # Returns
682    ///
683    /// Returns `BoxConditionalBiMutatingFunction<T, U, R>`
684    ///
685    /// # Examples
686    ///
687    /// ## Basic usage with or_else
688    ///
689    /// ```rust
690    /// use prism3_function::{BiMutatingFunction, FnBiMutatingFunctionOps};
691    ///
692    /// let swap_and_sum = |x: &mut i32, y: &mut i32| {
693    ///     let temp = *x;
694    ///     *x = *y;
695    ///     *y = temp;
696    ///     *x + *y
697    /// };
698    /// let multiply = |x: &mut i32, y: &mut i32| {
699    ///     *x *= *y;
700    ///     *x
701    /// };
702    /// let conditional = swap_and_sum.when(|x: &mut i32, y: &mut i32| *x > 0)
703    ///     .or_else(multiply);
704    ///
705    /// let mut a = 5;
706    /// let mut b = 3;
707    /// assert_eq!(conditional.apply(&mut a, &mut b), 8);
708    /// ```
709    ///
710    /// ## Preserving bi-predicate with clone
711    ///
712    /// ```rust
713    /// use prism3_function::{BiMutatingFunction, FnBiMutatingFunctionOps,
714    ///     RcBiPredicate};
715    ///
716    /// let swap_and_sum = |x: &mut i32, y: &mut i32| {
717    ///     let temp = *x;
718    ///     *x = *y;
719    ///     *y = temp;
720    ///     *x + *y
721    /// };
722    /// let both_positive = RcBiPredicate::new(|x: &mut i32, y: &mut i32|
723    ///     *x > 0 && *y > 0);
724    ///
725    /// // Clone to preserve original bi-predicate
726    /// let conditional = swap_and_sum.when(both_positive.clone())
727    ///     .or_else(|x: &mut i32, y: &mut i32| *x * *y);
728    ///
729    /// let mut a = 5;
730    /// let mut b = 3;
731    /// assert_eq!(conditional.apply(&mut a, &mut b), 8);
732    ///
733    /// // Original bi-predicate still usable
734    /// let mut test_a = 5;
735    /// let mut test_b = 3;
736    /// assert!(both_positive.test(&mut test_a, &mut test_b));
737    /// ```
738    fn when<P>(self, predicate: P) -> BoxConditionalBiMutatingFunction<T, U, R>
739    where
740        P: BiPredicate<T, U> + 'static,
741        T: 'static,
742        U: 'static,
743        R: 'static,
744    {
745        BoxBiMutatingFunction::new(self).when(predicate)
746    }
747}
748
749/// Blanket implementation of FnBiMutatingFunctionOps for all closures
750///
751/// Automatically implements `FnBiMutatingFunctionOps<T, U, R>` for any type that
752/// implements `Fn(&mut T, &mut U) -> R`.
753///
754/// # Author
755///
756/// Haixing Hu
757impl<T, U, R, F> FnBiMutatingFunctionOps<T, U, R> for F where F: Fn(&mut T, &mut U) -> R + 'static {}
758
759// ============================================================================
760// Type Aliases for BinaryMutatingOperator (BiMutatingFunction<T, U, R> where T == U)
761// ============================================================================
762
763/// Type alias for `BoxBiMutatingFunction<T, T, R>`
764///
765/// Represents a binary mutating function that takes two values of type `T` and produces
766/// a value of type `R`, with single ownership semantics. Similar to Java's
767/// `BiFunction<T, T, R>` but with mutable references.
768///
769/// # Examples
770///
771/// ```rust
772/// use prism3_function::{BoxBinaryMutatingFunction, BiMutatingFunction};
773///
774/// let swap_and_sum: BoxBinaryMutatingFunction<i32, i32> = BoxBinaryMutatingFunction::new(|x, y| {
775///     let temp = *x;
776///     *x = *y;
777///     *y = temp;
778///     *x + *y
779/// });
780/// let mut a = 5;
781/// let mut b = 10;
782/// assert_eq!(swap_and_sum.apply(&mut a, &mut b), 15);
783/// assert_eq!(a, 10);
784/// assert_eq!(b, 5);
785/// ```
786///
787/// # Author
788///
789/// Haixing Hu
790pub type BoxBinaryMutatingFunction<T, R> = BoxBiMutatingFunction<T, T, R>;
791
792/// Type alias for `ArcBiMutatingFunction<T, T, R>`
793///
794/// Represents a thread-safe binary mutating function that takes two values of type `T`
795/// and produces a value of type `R`. Similar to Java's `BiFunction<T, T, R>`
796/// with shared, thread-safe ownership and mutable references.
797///
798/// # Examples
799///
800/// ```rust
801/// use prism3_function::{ArcBinaryMutatingFunction, BiMutatingFunction};
802///
803/// let swap_and_sum: ArcBinaryMutatingFunction<i32, i32> = ArcBinaryMutatingFunction::new(|x, y| {
804///     let temp = *x;
805///     *x = *y;
806///     *y = temp;
807///     *x + *y
808/// });
809/// let swap_clone = swap_and_sum.clone();
810/// let mut a = 5;
811/// let mut b = 10;
812/// assert_eq!(swap_and_sum.apply(&mut a, &mut b), 15);
813/// assert_eq!(swap_clone.apply(&mut a, &mut b), 25);
814/// ```
815///
816/// # Author
817///
818/// Haixing Hu
819pub type ArcBinaryMutatingFunction<T, R> = ArcBiMutatingFunction<T, T, R>;
820
821/// Type alias for `RcBiMutatingFunction<T, T, R>`
822///
823/// Represents a single-threaded binary mutating function that takes two values of type `T`
824/// and produces a value of type `R`. Similar to Java's `BiFunction<T, T, R>`
825/// with shared, single-threaded ownership and mutable references.
826///
827/// # Examples
828///
829/// ```rust
830/// use prism3_function::{RcBinaryMutatingFunction, BiMutatingFunction};
831///
832/// let swap_and_sum: RcBinaryMutatingFunction<i32, i32> = RcBinaryMutatingFunction::new(|x, y| {
833///     let temp = *x;
834///     *x = *y;
835///     *y = temp;
836///     *x + *y
837/// });
838/// let swap_clone = swap_and_sum.clone();
839/// let mut a = 5;
840/// let mut b = 10;
841/// assert_eq!(swap_and_sum.apply(&mut a, &mut b), 15);
842/// assert_eq!(swap_clone.apply(&mut a, &mut b), 25);
843/// ```
844///
845/// # Author
846///
847/// Haixing Hu
848pub type RcBinaryMutatingFunction<T, R> = RcBiMutatingFunction<T, T, R>;
849
850// ============================================================================
851// BoxConditionalBiMutatingFunction - Box-based Conditional BiMutatingFunction
852// ============================================================================
853
854/// BoxConditionalBiMutatingFunction struct
855///
856/// A conditional bi-mutating-function that only executes when a bi-predicate is
857/// satisfied. Uses `BoxBiMutatingFunction` and `BoxBiPredicate` for single
858/// ownership semantics.
859///
860/// This type is typically created by calling `BoxBiMutatingFunction::when()` and is
861/// designed to work with the `or_else()` method to create if-then-else logic.
862///
863/// # Features
864///
865/// - **Single Ownership**: Not cloneable, ownership moves on use
866/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
867/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
868/// - **Implements BiMutatingFunction**: Can be used anywhere a `BiMutatingFunction` is expected
869///
870/// # Author
871///
872/// Haixing Hu
873pub struct BoxConditionalBiMutatingFunction<T, U, R> {
874    function: BoxBiMutatingFunction<T, U, R>,
875    predicate: BoxBiPredicate<T, U>,
876}
877
878// Implement BoxConditionalBiMutatingFunction
879impl_box_conditional_function!(
880    BoxConditionalBiMutatingFunction<T, U, R>,
881    BoxBiMutatingFunction,
882    BiMutatingFunction
883);
884
885// Use macro to generate Debug and Display implementations
886impl_conditional_function_debug_display!(BoxConditionalBiMutatingFunction<T, U, R>);
887
888// ============================================================================
889// RcConditionalBiMutatingFunction - Rc-based Conditional BiMutatingFunction
890// ============================================================================
891
892/// RcConditionalBiMutatingFunction struct
893///
894/// A single-threaded conditional bi-mutating-function that only executes when a
895/// bi-predicate is satisfied. Uses `RcBiMutatingFunction` and `RcBiPredicate` for
896/// shared ownership within a single thread.
897///
898/// This type is typically created by calling `RcBiMutatingFunction::when()` and is
899/// designed to work with the `or_else()` method to create if-then-else logic.
900///
901/// # Features
902///
903/// - **Shared Ownership**: Cloneable via `Rc`, multiple owners allowed
904/// - **Single-Threaded**: Not thread-safe, cannot be sent across threads
905/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
906/// - **No Lock Overhead**: More efficient than `ArcConditionalBiMutatingFunction`
907///
908/// # Author
909///
910/// Haixing Hu
911pub struct RcConditionalBiMutatingFunction<T, U, R> {
912    function: RcBiMutatingFunction<T, U, R>,
913    predicate: RcBiPredicate<T, U>,
914}
915
916// Implement RcConditionalBiMutatingFunction
917impl_shared_conditional_function!(
918    RcConditionalBiMutatingFunction<T, U, R>,
919    RcBiMutatingFunction,
920    BiMutatingFunction,
921    into_rc,
922    'static
923);
924
925// Use macro to generate Debug and Display implementations
926impl_conditional_function_debug_display!(RcConditionalBiMutatingFunction<T, U, R>);
927
928// Generate Clone implementation
929impl_conditional_function_clone!(RcConditionalBiMutatingFunction<T, U, R>);
930
931// ============================================================================
932// ArcConditionalBiMutatingFunction - Arc-based Conditional BiMutatingFunction
933// ============================================================================
934
935/// ArcConditionalBiMutatingFunction struct
936///
937/// A thread-safe conditional bi-mutating-function that only executes when a
938/// bi-predicate is satisfied. Uses `ArcBiMutatingFunction` and `ArcBiPredicate` for
939/// shared ownership across threads.
940///
941/// This type is typically created by calling `ArcBiMutatingFunction::when()` and is
942/// designed to work with the `or_else()` method to create if-then-else logic.
943///
944/// # Features
945///
946/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
947/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
948/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
949/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
950///
951/// # Author
952///
953/// Haixing Hu
954pub struct ArcConditionalBiMutatingFunction<T, U, R> {
955    function: ArcBiMutatingFunction<T, U, R>,
956    predicate: ArcBiPredicate<T, U>,
957}
958
959// Implement ArcConditionalBiMutatingFunction
960impl_shared_conditional_function!(
961    ArcConditionalBiMutatingFunction<T, U, R>,
962    ArcBiMutatingFunction,
963    BiMutatingFunction,
964    into_arc,
965    Send + Sync + 'static
966);
967
968// Use macro to generate Debug and Display implementations
969impl_conditional_function_debug_display!(ArcConditionalBiMutatingFunction<T, U, R>);
970
971// Generate Clone implementation
972impl_conditional_function_clone!(ArcConditionalBiMutatingFunction<T, U, R>);