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