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>);