qubit_function/functions/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//! # MutatingFunctionOnce Types
10//!
11//! Provides Java-like one-time `MutatingFunction` interface implementations
12//! for performing operations that consume self, accept a mutable reference,
13//! and return a result.
14//!
15//! It is similar to the `FnOnce(&mut T) -> R` trait in the standard library.
16//!
17//! This module provides a unified `MutatingFunctionOnce` trait and a
18//! Box-based single ownership implementation:
19//!
20//! - **`BoxMutatingFunctionOnce<T, R>`**: Box-based single ownership
21//! implementation for one-time use scenarios
22//!
23//! # Design Philosophy
24//!
25//! The key difference between `MutatingFunctionOnce` and
26//! `MutatingFunction`:
27//!
28//! - **MutatingFunction**: `&self`, can be called multiple times, uses
29//! `Fn(&mut T) -> R`
30//! - **MutatingFunctionOnce**: `self`, can only be called once, uses
31//! `FnOnce(&mut T) -> R`
32//!
33//! ## MutatingFunctionOnce vs MutatingFunction
34//!
35//! | Feature | MutatingFunction | MutatingFunctionOnce |
36//! |---------|------------------|----------------------|
37//! | **Self Parameter** | `&self` | `self` |
38//! | **Call Count** | Multiple | Once |
39//! | **Closure Type** | `Fn(&mut T) -> R` | `FnOnce(&mut T) -> R` |
40//! | **Use Cases** | Repeatable operations | One-time resource
41//! transfers |
42//!
43//! # Why MutatingFunctionOnce?
44//!
45//! Core value of MutatingFunctionOnce:
46//!
47//! 1. **Store FnOnce closures**: Allows moving captured variables
48//! 2. **Delayed execution**: Store in data structures, execute later
49//! 3. **Resource transfer**: Suitable for scenarios requiring ownership
50//! transfer
51//! 4. **Return results**: Unlike MutatorOnce, returns information about the
52//! operation
53//!
54//! # Why Only Box Variant?
55//!
56//! - **Arc/Rc conflicts with FnOnce semantics**: FnOnce can only be called
57//! once, while shared ownership implies multiple references
58//! - **Box is perfect match**: Single ownership aligns perfectly with
59//! one-time call semantics
60//!
61//! # Use Cases
62//!
63//! ## BoxMutatingFunctionOnce
64//!
65//! - Post-initialization callbacks (moving data, returning status)
66//! - Resource transfer with result (moving Vec, returning old value)
67//! - One-time complex operations (requiring moved capture variables)
68//! - Validation with fixes (fix data once, return validation result)
69//!
70//! # Examples
71//!
72//! ## Basic Usage
73//!
74//! ```rust
75//! use qubit_function::{BoxMutatingFunctionOnce, MutatingFunctionOnce};
76//!
77//! let data = vec![1, 2, 3];
78//! let func = BoxMutatingFunctionOnce::new(move |x: &mut Vec<i32>| {
79//! let old_len = x.len();
80//! x.extend(data); // Move data
81//! old_len
82//! });
83//!
84//! let mut target = vec![0];
85//! let old_len = func.apply(&mut target);
86//! assert_eq!(old_len, 1);
87//! assert_eq!(target, vec![0, 1, 2, 3]);
88//! ```
89//!
90//! ## Method Chaining
91//!
92//! ```rust
93//! use qubit_function::{BoxMutatingFunctionOnce, MutatingFunctionOnce};
94//!
95//! let data1 = vec![1, 2];
96//!
97//! let chained = BoxMutatingFunctionOnce::new(move |x: &mut Vec<i32>| {
98//! x.extend(data1);
99//! x.len()
100//! })
101//! .and_then(|len: &usize| len + 2);
102//!
103//! let mut target = vec![0];
104//! let final_len = chained.apply(&mut target);
105//! assert_eq!(final_len, 5);
106//! assert_eq!(target, vec![0, 1, 2]);
107//! ```
108//!
109//! ## Validation Pattern
110//!
111//! ```rust
112//! use qubit_function::{BoxMutatingFunctionOnce, MutatingFunctionOnce};
113//!
114//! struct Data {
115//! value: i32,
116//! }
117//!
118//! let validator = BoxMutatingFunctionOnce::new(|data: &mut Data| {
119//! if data.value < 0 {
120//! data.value = 0;
121//! Err("Fixed negative value")
122//! } else {
123//! Ok("Valid")
124//! }
125//! });
126//!
127//! let mut data = Data { value: -5 };
128//! let result = validator.apply(&mut data);
129//! assert_eq!(data.value, 0);
130//! assert!(result.is_err());
131//! ```
132//!
133//! # Author
134//!
135//! Haixing Hu
136use crate::functions::{
137 function_once::FunctionOnce,
138 macros::{
139 impl_box_conditional_function,
140 impl_box_function_methods,
141 impl_conditional_function_debug_display,
142 impl_fn_ops_trait,
143 impl_function_common_methods,
144 impl_function_debug_display,
145 impl_function_identity_method,
146 },
147};
148use crate::macros::{
149 impl_box_once_conversions,
150 impl_closure_once_trait,
151};
152use crate::predicates::predicate::{
153 BoxPredicate,
154 Predicate,
155};
156
157// =======================================================================
158// 1. MutatingFunctionOnce Trait - One-time Function Interface
159// =======================================================================
160
161/// MutatingFunctionOnce trait - One-time mutating function interface
162///
163/// It is similar to the `FnOnce(&mut T) -> R` trait in the standard library.
164///
165/// Defines the core behavior of all one-time mutating function types.
166/// Performs operations that consume self, accept a mutable reference,
167/// potentially modify it, and return a result.
168///
169/// This trait is automatically implemented by:
170/// - All closures implementing `FnOnce(&mut T) -> R`
171/// - `BoxMutatingFunctionOnce<T, R>`
172///
173/// # Design Rationale
174///
175/// This trait provides a unified abstraction for one-time mutating function
176/// operations. The key difference from `MutatingFunction`:
177/// - `MutatingFunction` uses `&self`, can be called multiple times
178/// - `MutatingFunctionOnce` uses `self`, can only be called once
179///
180/// # Features
181///
182/// - **Unified Interface**: All one-time mutating functions share the same
183/// `apply` method signature
184/// - **Automatic Implementation**: Closures automatically implement this
185/// trait with zero overhead
186/// - **Type Conversions**: Provides `into_box` method for type conversion
187/// - **Generic Programming**: Write functions that work with any one-time
188/// mutating function type
189///
190/// # Examples
191///
192/// ## Generic Function
193///
194/// ```rust
195/// use qubit_function::{MutatingFunctionOnce, BoxMutatingFunctionOnce};
196///
197/// fn apply<F: MutatingFunctionOnce<Vec<i32>, usize>>(
198/// func: F,
199/// initial: Vec<i32>
200/// ) -> (Vec<i32>, usize) {
201/// let mut val = initial;
202/// let result = func.apply(&mut val);
203/// (val, result)
204/// }
205///
206/// let data = vec![1, 2, 3];
207/// let func = BoxMutatingFunctionOnce::new(move |x: &mut Vec<i32>| {
208/// let old_len = x.len();
209/// x.extend(data);
210/// old_len
211/// });
212/// let (vec, old_len) = apply(func, vec![0]);
213/// assert_eq!(vec, vec![0, 1, 2, 3]);
214/// assert_eq!(old_len, 1);
215/// ```
216///
217/// ## Type Conversion
218///
219/// ```rust
220/// use qubit_function::MutatingFunctionOnce;
221///
222/// let data = vec![1, 2, 3];
223/// let closure = move |x: &mut Vec<i32>| {
224/// let old_len = x.len();
225/// x.extend(data);
226/// old_len
227/// };
228/// let box_func = closure.into_box();
229/// ```
230///
231/// # Author
232///
233/// Haixing Hu
234pub trait MutatingFunctionOnce<T, R> {
235 /// Performs the one-time mutating function operation
236 ///
237 /// Consumes self and executes an operation on the given mutable
238 /// reference, potentially modifying it, and returns a result. The
239 /// operation can only be called once.
240 ///
241 /// # Parameters
242 ///
243 /// * `t - A mutable reference to the input value
244 ///
245 /// # Returns
246 ///
247 /// The computed result value
248 ///
249 /// # Examples
250 ///
251 /// ```rust
252 /// use qubit_function::{MutatingFunctionOnce,
253 /// BoxMutatingFunctionOnce};
254 ///
255 /// let data = vec![1, 2, 3];
256 /// let func = BoxMutatingFunctionOnce::new(move |x: &mut Vec<i32>| {
257 /// let old_len = x.len();
258 /// x.extend(data);
259 /// old_len
260 /// });
261 ///
262 /// let mut target = vec![0];
263 /// let old_len = func.apply(&mut target);
264 /// assert_eq!(old_len, 1);
265 /// assert_eq!(target, vec![0, 1, 2, 3]);
266 /// ```
267 fn apply(self, t: &mut T) -> R;
268
269 /// Converts to `BoxMutatingFunctionOnce` (consuming)
270 ///
271 /// Consumes `self` and returns an owned `BoxMutatingFunctionOnce<T, R>`.
272 /// The default implementation simply wraps the consuming
273 /// `apply(self, &mut T)` call in a `Box<dyn FnOnce(&mut T) -> R>`.
274 /// Types that can provide a cheaper or identity conversion (for example
275 /// `BoxMutatingFunctionOnce` itself) should override this method.
276 ///
277 /// # Note
278 ///
279 /// - This method consumes the source value.
280 /// - Implementors may return `self` directly when `Self` is already a
281 /// `BoxMutatingFunctionOnce<T, R>` to avoid the extra wrapper
282 /// allocation.
283 fn into_box(self) -> BoxMutatingFunctionOnce<T, R>
284 where
285 Self: Sized + 'static,
286 {
287 BoxMutatingFunctionOnce::new(move |t| self.apply(t))
288 }
289
290 /// Converts to a consuming closure `FnOnce(&mut T) -> R`
291 ///
292 /// Consumes `self` and returns a closure that, when invoked, calls
293 /// `apply(self, &mut T)`. This is the default, straightforward
294 /// implementation; types that can produce a more direct function pointer
295 /// or avoid additional captures may override it.
296 fn into_fn(self) -> impl FnOnce(&mut T) -> R
297 where
298 Self: Sized + 'static,
299 {
300 move |t| self.apply(t)
301 }
302
303 /// Non-consuming adapter to `BoxMutatingFunctionOnce`
304 ///
305 /// Creates a `BoxMutatingFunctionOnce<T, R>` that does not consume
306 /// `self`. The default implementation requires `Self: Clone` and clones
307 /// the receiver for the stored closure; the clone is consumed when the
308 /// boxed function is invoked. Types that can provide a zero-cost adapter
309 /// (for example clonable closures) should override this method to avoid
310 /// unnecessary allocations.
311 fn to_box(&self) -> BoxMutatingFunctionOnce<T, R>
312 where
313 Self: Sized + Clone + 'static,
314 {
315 self.clone().into_box()
316 }
317
318 /// Non-consuming adapter to a callable `FnOnce(&mut T) -> R`
319 ///
320 /// Returns a closure that does not consume `self`. The default requires
321 /// `Self: Clone` and clones `self` for the captured closure; the clone is
322 /// consumed when the returned closure is invoked. Implementors may
323 /// provide more efficient adapters for specific types.
324 fn to_fn(&self) -> impl FnOnce(&mut T) -> R
325 where
326 Self: Sized + Clone + 'static,
327 {
328 self.clone().into_fn()
329 }
330}
331
332// =======================================================================
333// 2. BoxMutatingFunctionOnce - Single Ownership Implementation
334// =======================================================================
335
336/// BoxMutatingFunctionOnce struct
337///
338/// A one-time mutating function implementation based on
339/// `Box<dyn FnOnce(&mut T) -> R>` for single ownership scenarios. This is
340/// the only MutatingFunctionOnce implementation type because FnOnce
341/// conflicts with shared ownership semantics.
342///
343/// # Features
344///
345/// - **Single Ownership**: Not cloneable, consumes self on use
346/// - **Zero Overhead**: No reference counting or locking
347/// - **Move Semantics**: Can capture and move variables
348/// - **Method Chaining**: Compose multiple operations via `and_then`
349/// - **Returns Results**: Unlike MutatorOnce, returns information
350///
351/// # Use Cases
352///
353/// Choose `BoxMutatingFunctionOnce` when:
354/// - Need to store FnOnce closures (with moved captured variables)
355/// - One-time resource transfer operations with results
356/// - Post-initialization callbacks that return status
357/// - Complex operations requiring ownership transfer and results
358///
359/// # Performance
360///
361/// `BoxMutatingFunctionOnce` performance characteristics:
362/// - No reference counting overhead
363/// - No lock acquisition or runtime borrow checking
364/// - Direct function call through vtable
365/// - Minimal memory footprint (single pointer)
366///
367/// # Why No Arc/Rc Variants?
368///
369/// FnOnce can only be called once, which conflicts with Arc/Rc shared
370/// ownership semantics:
371/// - Arc/Rc implies multiple owners might need to call
372/// - FnOnce is consumed after calling, cannot be called again
373/// - This semantic incompatibility makes Arc/Rc variants meaningless
374///
375/// # Examples
376///
377/// ## Basic Usage
378///
379/// ```rust
380/// use qubit_function::{MutatingFunctionOnce, BoxMutatingFunctionOnce};
381///
382/// let data = vec![1, 2, 3];
383/// let func = BoxMutatingFunctionOnce::new(move |x: &mut Vec<i32>| {
384/// let old_len = x.len();
385/// x.extend(data); // Move data
386/// old_len
387/// });
388///
389/// let mut target = vec![0];
390/// let old_len = func.apply(&mut target);
391/// assert_eq!(old_len, 1);
392/// assert_eq!(target, vec![0, 1, 2, 3]);
393/// ```
394///
395/// ## Method Chaining
396///
397/// ```rust
398/// use qubit_function::{MutatingFunctionOnce, BoxMutatingFunctionOnce};
399///
400/// let data1 = vec![1, 2];
401/// let additional_len = 2;
402///
403/// let chained = BoxMutatingFunctionOnce::new(move |x: &mut Vec<i32>| {
404/// x.extend(data1);
405/// x.len()
406/// })
407/// .and_then(move |len: &usize| len + additional_len);
408///
409/// let mut target = vec![0];
410/// let final_len = chained.apply(&mut target);
411/// assert_eq!(final_len, 5);
412/// assert_eq!(target, vec![0, 1, 2]);
413/// ```
414///
415/// # Author
416///
417/// Haixing Hu
418pub struct BoxMutatingFunctionOnce<T, R> {
419 function: Box<dyn FnOnce(&mut T) -> R>,
420 name: Option<String>,
421}
422
423impl<T, R> BoxMutatingFunctionOnce<T, R> {
424 // Generates: new(), new_with_name(), new_with_optional_name(), name(), set_name()
425 impl_function_common_methods!(
426 BoxMutatingFunctionOnce<T, R>,
427 (FnOnce(&mut T) -> R + 'static),
428 |f| Box::new(f)
429 );
430
431 // Generates: when(), and_then(), compose()
432 impl_box_function_methods!(
433 BoxMutatingFunctionOnce<T, R>,
434 BoxConditionalMutatingFunctionOnce,
435 FunctionOnce // chains a non-mutating function after this mutating function
436 );
437}
438
439impl<T, R> MutatingFunctionOnce<T, R> for BoxMutatingFunctionOnce<T, R> {
440 fn apply(self, input: &mut T) -> R {
441 (self.function)(input)
442 }
443
444 impl_box_once_conversions!(
445 BoxMutatingFunctionOnce<T, R>,
446 MutatingFunctionOnce,
447 FnOnce(&mut T) -> R
448 );
449}
450
451// Generates: identity() method for BoxMutatingFunctionOnce<T, T>
452impl_function_identity_method!(BoxMutatingFunctionOnce<T, T>, mutating);
453
454// Generates: Debug and Display implementations for BoxMutatingFunctionOnce<T, R>
455impl_function_debug_display!(BoxMutatingFunctionOnce<T, R>);
456
457// =======================================================================
458// 3. Implement MutatingFunctionOnce trait for closures
459// =======================================================================
460
461// Implement MutatingFunctionOnce for all FnOnce(&mut T) -> R using macro
462impl_closure_once_trait!(
463 MutatingFunctionOnce<T, R>,
464 apply,
465 BoxMutatingFunctionOnce,
466 FnOnce(input: &mut T) -> R
467);
468
469// =======================================================================
470// 4. Provide extension methods for closures
471// =======================================================================
472
473// Generates: FnMutatingFunctionOnceOps trait and blanket implementation
474impl_fn_ops_trait!(
475 (FnOnce(&mut T) -> R),
476 FnMutatingFunctionOnceOps,
477 BoxMutatingFunctionOnce,
478 FunctionOnce,
479 BoxConditionalMutatingFunctionOnce
480);
481
482// ============================================================================
483// BoxConditionalMutatingFunctionOnce - Box-based Conditional Mutating Function
484// ============================================================================
485
486/// BoxConditionalMutatingFunctionOnce struct
487///
488/// A conditional consuming transformer that only executes when a predicate is
489/// satisfied. Uses `BoxMutatingFunctionOnce` and `BoxPredicate` for single
490/// ownership semantics.
491///
492/// This type is typically created by calling `BoxMutatingFunctionOnce::when()` and
493/// is designed to work with the `or_else()` method to create if-then-else
494/// logic.
495///
496/// # Features
497///
498/// - **Single Ownership**: Not cloneable, consumes `self` on use
499/// - **One-time Use**: Can only be called once
500/// - **Conditional Execution**: Only transforms when predicate returns `true`
501/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
502///
503/// # Examples
504///
505/// ## With or_else Branch
506///
507/// ```rust
508/// use qubit_function::{MutatingFunctionOnce, BoxMutatingFunctionOnce};
509///
510/// let double = BoxMutatingFunctionOnce::new(|x: &mut i32| {
511/// *x *= 2;
512/// *x
513/// });
514/// let negate = BoxMutatingFunctionOnce::new(|x: &mut i32| {
515/// *x = -*x;
516/// *x
517/// });
518/// let conditional = double.when(|x: &i32| *x > 0).or_else(negate);
519/// let mut positive = 5;
520/// assert_eq!(conditional.apply(&mut positive), 10); // when branch executed
521///
522/// let double2 = BoxMutatingFunctionOnce::new(|x: &mut i32| {
523/// *x *= 2;
524/// *x
525/// });
526/// let negate2 = BoxMutatingFunctionOnce::new(|x: &mut i32| {
527/// *x = -*x;
528/// *x
529/// });
530/// let conditional2 = double2.when(|x: &i32| *x > 0).or_else(negate2);
531/// let mut negative = -5;
532/// assert_eq!(conditional2.apply(&mut negative), 5); // or_else branch executed
533/// ```
534///
535/// # Author
536///
537/// Haixing Hu
538pub struct BoxConditionalMutatingFunctionOnce<T, R> {
539 function: BoxMutatingFunctionOnce<T, R>,
540 predicate: BoxPredicate<T>,
541}
542
543// Use macro to generate conditional function implementations
544impl_box_conditional_function!(
545 BoxConditionalMutatingFunctionOnce<T, R>,
546 BoxMutatingFunctionOnce,
547 MutatingFunctionOnce
548);
549
550// Use macro to generate conditional function debug and display implementations
551impl_conditional_function_debug_display!(BoxConditionalMutatingFunctionOnce<T, R>);