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