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