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