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