prism3_function/functions/
bi_mutating_function_once.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025.
4 *    3-Prism Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9
10//! # BiMutatingFunctionOnce Types
11//!
12//! Provides Rust implementations of consuming bi-mutating-function traits similar to
13//! Rust's `FnOnce(&mut T, &mut U) -> R` trait, but with value-oriented semantics for functional
14//! programming patterns with two mutable input references.
15//!
16//! This module provides the `BiMutatingFunctionOnce<T, U, R>` trait and one-time use
17//! implementations:
18//!
19//! - [`BoxBiMutatingFunctionOnce`]: Single ownership, one-time use
20//!
21//! # Author
22//!
23//! Haixing Hu
24use crate::functions::{
25    macros::{
26        impl_box_conditional_function,
27        impl_box_function_methods,
28        impl_conditional_function_debug_display,
29        impl_function_common_methods,
30        impl_function_constant_method,
31        impl_function_debug_display,
32    },
33    mutating_function_once::MutatingFunctionOnce,
34};
35use crate::macros::{
36    impl_box_once_conversions,
37    impl_closure_once_trait,
38};
39use crate::predicates::bi_predicate::{
40    BiPredicate,
41    BoxBiPredicate,
42};
43
44// ============================================================================
45// Core Trait
46// ============================================================================
47
48/// BiMutatingFunctionOnce trait - consuming bi-mutating-function that takes
49/// mutable references
50///
51/// Defines the behavior of a consuming bi-mutating-function: computing a value of
52/// type `R` from mutable references to types `T` and `U` by taking ownership of self.
53/// This trait is analogous to `FnOnce(&mut T, &mut U) -> R`.
54///
55/// # Type Parameters
56///
57/// * `T` - The type of the first input value (mutable reference)
58/// * `U` - The type of the second input value (mutable reference)
59/// * `R` - The type of the output value
60///
61/// # Author
62///
63/// Haixing Hu
64pub trait BiMutatingFunctionOnce<T, U, R> {
65    /// Computes output from two mutable references, consuming self
66    ///
67    /// # Parameters
68    ///
69    /// * `first` - Mutable reference to the first input value
70    /// * `second` - Mutable reference to the second input value
71    ///
72    /// # Returns
73    ///
74    /// The computed output value
75    fn apply(self, first: &mut T, second: &mut U) -> R;
76
77    /// Converts to BoxBiMutatingFunctionOnce
78    ///
79    /// **⚠️ Consumes `self`**: The original bi-function becomes unavailable
80    /// after calling this method.
81    ///
82    /// # Returns
83    ///
84    /// Returns `BoxBiMutatingFunctionOnce<T, U, R>`
85    fn into_box(self) -> BoxBiMutatingFunctionOnce<T, U, R>
86    where
87        Self: Sized + 'static,
88        T: 'static,
89        U: 'static,
90        R: 'static,
91    {
92        BoxBiMutatingFunctionOnce::new(move |t: &mut T, u: &mut U| self.apply(t, u))
93    }
94
95    /// Converts bi-mutating-function to a closure
96    ///
97    /// **⚠️ Consumes `self`**: The original bi-function becomes unavailable
98    /// after calling this method.
99    ///
100    /// # Returns
101    ///
102    /// Returns a closure that implements `FnOnce(&mut T, &mut U) -> R`
103    fn into_fn(self) -> impl FnOnce(&mut T, &mut U) -> R
104    where
105        Self: Sized + 'static,
106        T: 'static,
107        U: 'static,
108        R: 'static,
109    {
110        move |t: &mut T, u: &mut U| self.apply(t, u)
111    }
112
113    /// Converts bi-mutating-function to a boxed function pointer
114    ///
115    /// **📌 Borrows `&self`**: The original bi-function remains usable
116    /// after calling this method.
117    ///
118    /// # Returns
119    ///
120    /// Returns a boxed function pointer that implements `FnOnce(&mut T, &mut U) -> R`
121    ///
122    /// # Examples
123    ///
124    /// ```rust
125    /// use prism3_function::BiMutatingFunctionOnce;
126    ///
127    /// let swap_and_sum = |x: &mut i32, y: &mut i32| {
128    ///     let temp = *x;
129    ///     *x = *y;
130    ///     *y = temp;
131    ///     *x + *y
132    /// };
133    /// let func = swap_and_sum.to_box();
134    /// let mut a = 20;
135    /// let mut b = 22;
136    /// assert_eq!(func.apply(&mut a, &mut b), 42);
137    /// ```
138    fn to_box(&self) -> BoxBiMutatingFunctionOnce<T, U, R>
139    where
140        Self: Clone + 'static,
141        T: 'static,
142        U: 'static,
143        R: 'static,
144    {
145        self.clone().into_box()
146    }
147
148    /// Converts bi-mutating-function to a closure
149    ///
150    /// **📌 Borrows `&self`**: The original bi-function remains usable
151    /// after calling this method.
152    ///
153    /// # Returns
154    ///
155    /// Returns a closure that implements `FnOnce(&mut T, &mut U) -> R`
156    ///
157    /// # Examples
158    ///
159    /// ```rust
160    /// use prism3_function::BiMutatingFunctionOnce;
161    ///
162    /// let swap_and_sum = |x: &mut i32, y: &mut i32| {
163    ///     let temp = *x;
164    ///     *x = *y;
165    ///     *y = temp;
166    ///     *x + *y
167    /// };
168    /// let func = swap_and_sum.to_fn();
169    /// let mut a = 20;
170    /// let mut b = 22;
171    /// assert_eq!(func(&mut a, &mut b), 42);
172    /// ```
173    fn to_fn(&self) -> impl FnOnce(&mut T, &mut U) -> R
174    where
175        Self: Clone + 'static,
176        T: 'static,
177        U: 'static,
178        R: 'static,
179    {
180        self.clone().into_fn()
181    }
182}
183
184// ============================================================================
185// BoxBiMutatingFunctionOnce - Box<dyn FnOnce(&mut T, &mut U) -> R>
186// ============================================================================
187
188/// BoxBiMutatingFunctionOnce - consuming bi-mutating-function wrapper based on
189/// `Box<dyn FnOnce>`
190///
191/// A bi-mutating-function wrapper that provides single ownership with one-time use
192/// semantics. Consumes self and borrows both input values mutably.
193///
194/// # Features
195///
196/// - **Based on**: `Box<dyn FnOnce(&mut T, &mut U) -> R>`
197/// - **Ownership**: Single ownership, cannot be cloned
198/// - **Reusability**: Can only be called once (consumes self)
199/// - **Thread Safety**: Not thread-safe (no `Send + Sync` requirement)
200///
201/// # Author
202///
203/// Haixing Hu
204pub struct BoxBiMutatingFunctionOnce<T, U, R> {
205    function: Box<dyn FnOnce(&mut T, &mut U) -> R>,
206    name: Option<String>,
207}
208
209// Implement BoxBiMutatingFunctionOnce
210impl<T, U, R> BoxBiMutatingFunctionOnce<T, U, R>
211where
212    T: 'static,
213    U: 'static,
214    R: 'static,
215{
216    // Generate new(), new_with_name(), new_with_optional_name(), name(), set_name()
217    impl_function_common_methods!(
218        BoxBiMutatingFunctionOnce<T, U, R>,
219        (FnOnce(&mut T, &mut U) -> R + 'static),
220        |f| Box::new(f)
221    );
222
223    // Generate when(), and_then()
224    impl_box_function_methods!(
225        BoxBiMutatingFunctionOnce<T, U, R>,
226        BoxConditionalBiMutatingFunctionOnce,
227        MutatingFunctionOnce
228    );
229}
230
231// Implement BiMutatingFunctionOnce trait for BoxBiMutatingFunctionOnce
232impl<T, U, R> BiMutatingFunctionOnce<T, U, R> for BoxBiMutatingFunctionOnce<T, U, R> {
233    fn apply(self, first: &mut T, second: &mut U) -> R {
234        (self.function)(first, second)
235    }
236
237    // Generate into_box(), into_fn(), to_box()
238    impl_box_once_conversions!(
239        BoxBiMutatingFunctionOnce<T, U, R>,
240        BiMutatingFunctionOnce,
241        FnOnce(&mut T, &mut U) -> R
242    );
243}
244
245// Implement constant method for BoxBiMutatingFunctionOnce
246impl_function_constant_method!(BoxBiMutatingFunctionOnce<T, U, R>);
247
248// Use macro to generate Debug and Display implementations
249impl_function_debug_display!(BoxBiMutatingFunctionOnce<T, U, R>);
250
251// ============================================================================
252// Blanket implementation for standard FnOnce trait
253// ============================================================================
254
255// Implement BiMutatingFunctionOnce for all FnOnce(&mut T, &mut U) -> R using macro
256impl_closure_once_trait!(
257    BiMutatingFunctionOnce<T, U, R>,
258    apply,
259    BoxBiMutatingFunctionOnce,
260    FnOnce(first: &mut T, second: &mut U) -> R
261);
262
263// ============================================================================
264// FnBiMutatingFunctionOnceOps - Extension trait for FnOnce(&mut T, &mut U) -> R bi-functions
265// ============================================================================
266
267/// Extension trait for closures implementing `FnOnce(&mut T, &mut U) -> R`
268///
269/// Provides composition methods (`and_then`, `when`) for one-time use
270/// bi-mutating-function closures and function pointers without requiring explicit
271/// wrapping in `BoxBiMutatingFunctionOnce`.
272///
273/// This trait is automatically implemented for all closures and function
274/// pointers that implement `FnOnce(&mut T, &mut U) -> R`.
275///
276/// # Design Rationale
277///
278/// While closures automatically implement `BiMutatingFunctionOnce<T, U, R>` through
279/// blanket implementation, they don't have access to instance methods like
280/// `and_then` and `when`. This extension trait provides those methods,
281/// returning `BoxBiMutatingFunctionOnce` for maximum flexibility.
282///
283/// # Examples
284///
285/// ## Chain composition with and_then
286///
287/// ```rust
288/// use prism3_function::{BiMutatingFunctionOnce, FnBiMutatingFunctionOnceOps};
289///
290/// let swap_and_sum = |x: &mut i32, y: &mut i32| {
291///     let temp = *x;
292///     *x = *y;
293///     *y = temp;
294///     *x + *y
295/// };
296/// let double = |x: i32| x * 2;
297///
298/// let composed = swap_and_sum.and_then(double);
299/// let mut a = 3;
300/// let mut b = 5;
301/// assert_eq!(composed.apply(&mut a, &mut b), 16); // (5 + 3) * 2 = 16
302/// ```
303///
304/// ## Conditional execution with when
305///
306/// ```rust
307/// use prism3_function::{BiMutatingFunctionOnce, FnBiMutatingFunctionOnceOps};
308///
309/// let swap_and_sum = |x: &mut i32, y: &mut i32| {
310///     let temp = *x;
311///     *x = *y;
312///     *y = temp;
313///     *x + *y
314/// };
315/// let multiply = |x: &mut i32, y: &mut i32| {
316///     *x *= *y;
317///     *x
318/// };
319///
320/// let conditional = swap_and_sum.when(|x: &mut i32, y: &mut i32| *x > 0 && *y > 0).or_else(multiply);
321/// let mut a = 5;
322/// let mut b = 3;
323/// assert_eq!(conditional.apply(&mut a, &mut b), 8); // swap_and_sum executed
324///
325/// let conditional2 = swap_and_sum.when(|x: &mut i32, y: &mut i32| *x > 0 && *y > 0).or_else(multiply);
326/// let mut a = -5;
327/// let mut b = 3;
328/// assert_eq!(conditional2.apply(&mut a, &mut b), -15); // multiply executed
329/// ```
330///
331/// # Author
332///
333/// Haixing Hu
334pub trait FnBiMutatingFunctionOnceOps<T, U, R>:
335    FnOnce(&mut T, &mut U) -> R + Sized + 'static
336{
337    /// Chain composition - applies self first, then after
338    ///
339    /// Creates a new bi-mutating-function that applies this bi-mutating-function first,
340    /// then applies the after function to the result. Consumes self and
341    /// returns a `BoxBiMutatingFunctionOnce`.
342    ///
343    /// # Type Parameters
344    ///
345    /// * `S` - The output type of the after function
346    /// * `F` - The type of the after function (must implement Function<R, S>)
347    ///
348    /// # Parameters
349    ///
350    /// * `after` - The function to apply after self. **Note: This parameter
351    ///   is passed by value and will transfer ownership.** Since this is a
352    ///   `FnOnce` bi-mutating-function, the parameter will be consumed. Can be:
353    ///   - A closure: `|x: R| -> S`
354    ///   - A function pointer: `fn(R) -> S`
355    ///   - A `BoxFunction<R, S>`
356    ///   - An `RcFunction<R, S>`
357    ///   - An `ArcFunction<R, S>`
358    ///   - Any type implementing `Function<R, S>`
359    ///
360    /// # Returns
361    ///
362    /// A new `BoxBiMutatingFunctionOnce<T, U, S>` representing the composition
363    ///
364    /// # Examples
365    ///
366    /// ```rust
367    /// use prism3_function::{BiMutatingFunctionOnce, FnBiMutatingFunctionOnceOps,
368    ///     BoxFunction};
369    ///
370    /// let swap_and_sum = |x: &mut i32, y: &mut i32| {
371    ///     let temp = *x;
372    ///     *x = *y;
373    ///     *y = temp;
374    ///     *x + *y
375    /// };
376    /// let to_string = BoxFunction::new(|x: i32| x.to_string());
377    ///
378    /// // to_string is moved and consumed
379    /// let composed = swap_and_sum.and_then(to_string);
380    /// let mut a = 20;
381    /// let mut b = 22;
382    /// assert_eq!(composed.apply(&mut a, &mut b), "42");
383    /// // to_string.apply(10); // Would not compile - moved
384    /// ```
385    fn and_then<S, F>(self, after: F) -> BoxBiMutatingFunctionOnce<T, U, S>
386    where
387        S: 'static,
388        F: crate::functions::function::Function<R, S> + 'static,
389        T: 'static,
390        U: 'static,
391        R: 'static,
392    {
393        BoxBiMutatingFunctionOnce::new(move |t: &mut T, u: &mut U| after.apply(&self(t, u)))
394    }
395
396    /// Creates a conditional bi-mutating-function
397    ///
398    /// Returns a bi-mutating-function that only executes when a bi-predicate is
399    /// satisfied. You must call `or_else()` to provide an alternative
400    /// bi-mutating-function for when the condition is not satisfied.
401    ///
402    /// # Parameters
403    ///
404    /// * `predicate` - The condition to check. **Note: This parameter is passed
405    ///   by value and will transfer ownership.** If you need to preserve the
406    ///   original bi-predicate, clone it first (if it implements `Clone`).
407    ///   Can be:
408    ///   - A closure: `|x: &mut T, y: &mut U| -> bool`
409    ///   - A function pointer: `fn(&mut T, &mut U) -> bool`
410    ///   - A `BoxBiPredicate<T, U>`
411    ///   - An `RcBiPredicate<T, U>`
412    ///   - An `ArcBiPredicate<T, U>`
413    ///   - Any type implementing `BiPredicate<T, U>`
414    ///
415    /// # Returns
416    ///
417    /// Returns `BoxConditionalBiMutatingFunctionOnce<T, U, R>`
418    ///
419    /// # Examples
420    ///
421    /// ## Basic usage with or_else
422    ///
423    /// ```rust
424    /// use prism3_function::{BiMutatingFunctionOnce, FnBiMutatingFunctionOnceOps};
425    ///
426    /// let swap_and_sum = |x: &mut i32, y: &mut i32| {
427    ///     let temp = *x;
428    ///     *x = *y;
429    ///     *y = temp;
430    ///     *x + *y
431    /// };
432    /// let multiply = |x: &mut i32, y: &mut i32| {
433    ///     *x *= *y;
434    ///     *x
435    /// };
436    /// let conditional = swap_and_sum.when(|x: &mut i32, y: &mut i32| *x > 0)
437    ///     .or_else(multiply);
438    ///
439    /// let mut a = 5;
440    /// let mut b = 3;
441    /// assert_eq!(conditional.apply(&mut a, &mut b), 8);
442    /// ```
443    ///
444    /// ## Preserving bi-predicate with clone
445    ///
446    /// ```rust
447    /// use prism3_function::{BiMutatingFunctionOnce, FnBiMutatingFunctionOnceOps,
448    ///     RcBiPredicate};
449    ///
450    /// let swap_and_sum = |x: &mut i32, y: &mut i32| {
451    ///     let temp = *x;
452    ///     *x = *y;
453    ///     *y = temp;
454    ///     *x + *y
455    /// };
456    /// let both_positive = RcBiPredicate::new(|x: &mut i32, y: &mut i32|
457    ///     *x > 0 && *y > 0);
458    ///
459    /// // Clone to preserve original bi-predicate
460    /// let conditional = swap_and_sum.when(both_positive.clone())
461    ///     .or_else(|x: &mut i32, y: &mut i32| *x * *y);
462    ///
463    /// let mut a = 5;
464    /// let mut b = 3;
465    /// assert_eq!(conditional.apply(&mut a, &mut b), 8);
466    ///
467    /// // Original bi-predicate still usable
468    /// let mut test_a = 5;
469    /// let mut test_b = 3;
470    /// assert!(both_positive.test(&mut test_a, &mut test_b));
471    /// ```
472    fn when<P>(self, predicate: P) -> BoxConditionalBiMutatingFunctionOnce<T, U, R>
473    where
474        P: BiPredicate<T, U> + 'static,
475        T: 'static,
476        U: 'static,
477        R: 'static,
478    {
479        BoxBiMutatingFunctionOnce::new(self).when(predicate)
480    }
481}
482
483/// Blanket implementation of FnBiMutatingFunctionOnceOps for all closures
484///
485/// Automatically implements `FnBiMutatingFunctionOnceOps<T, U, R>` for any type that
486/// implements `FnOnce(&mut T, &mut U) -> R`.
487///
488/// # Author
489///
490/// Haixing Hu
491impl<T, U, R, F> FnBiMutatingFunctionOnceOps<T, U, R> for F
492where
493    F: FnOnce(&mut T, &mut U) -> R + 'static,
494    T: 'static,
495    U: 'static,
496    R: 'static,
497{
498    // empty
499}
500
501// ============================================================================
502// BoxConditionalBiMutatingFunctionOnce - Box-based Conditional BiMutatingFunction
503// ============================================================================
504
505/// BoxConditionalBiMutatingFunctionOnce struct
506///
507/// A conditional consuming bi-mutating-function that only executes when a bi-predicate
508/// is satisfied. Uses `BoxBiMutatingFunctionOnce` and `BoxBiPredicate` for single
509/// ownership semantics.
510///
511/// This type is typically created by calling `BoxBiMutatingFunctionOnce::when()` and
512/// is designed to work with the `or_else()` method to create if-then-else logic.
513///
514/// # Features
515///
516/// - **Single Ownership**: Not cloneable, consumes `self` on use
517/// - **One-time Use**: Can only be called once
518/// - **Conditional Execution**: Only computes when bi-predicate returns `true`
519/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
520///
521/// # Author
522///
523/// Haixing Hu
524pub struct BoxConditionalBiMutatingFunctionOnce<T, U, R> {
525    function: BoxBiMutatingFunctionOnce<T, U, R>,
526    predicate: BoxBiPredicate<T, U>,
527}
528
529// Implement BoxConditionalBiMutatingFunctionOnce
530impl_box_conditional_function!(
531    BoxConditionalBiMutatingFunctionOnce<T, U, R>,
532    BoxBiMutatingFunctionOnce,
533    BiMutatingFunctionOnce
534);
535
536// Use macro to generate Debug and Display implementations
537impl_conditional_function_debug_display!(BoxConditionalBiMutatingFunctionOnce<T, U, R>);