Skip to main content

qubit_function/functions/
bi_mutating_function.rs

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