Skip to main content

qubit_function/functions/mutating_function_once/
box_mutating_function_once.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10// qubit-style: allow explicit-imports
11//! Defines the `BoxMutatingFunctionOnce` public type.
12
13use super::{
14    BoxConditionalMutatingFunctionOnce,
15    FunctionOnce,
16    MutatingFunctionOnce,
17    Predicate,
18    impl_box_function_methods,
19    impl_box_once_conversions,
20    impl_closure_once_trait,
21    impl_function_common_methods,
22    impl_function_debug_display,
23    impl_function_identity_method,
24};
25
26// =======================================================================
27// 2. BoxMutatingFunctionOnce - Single Ownership Implementation
28// =======================================================================
29
30/// BoxMutatingFunctionOnce struct
31///
32/// A one-time mutating function implementation based on
33/// `Box<dyn FnOnce(&mut T) -> R>` for single ownership scenarios. This is
34/// the only MutatingFunctionOnce implementation type because FnOnce
35/// conflicts with shared ownership semantics.
36///
37/// # Features
38///
39/// - **Single Ownership**: Not cloneable, consumes self on use
40/// - **Zero Overhead**: No reference counting or locking
41/// - **Move Semantics**: Can capture and move variables
42/// - **Method Chaining**: Compose multiple operations via `and_then`
43/// - **Returns Results**: Unlike MutatorOnce, returns information
44///
45/// # Use Cases
46///
47/// Choose `BoxMutatingFunctionOnce` when:
48/// - Need to store FnOnce closures (with moved captured variables)
49/// - One-time resource transfer operations with results
50/// - Post-initialization callbacks that return status
51/// - Complex operations requiring ownership transfer and results
52///
53/// # Performance
54///
55/// `BoxMutatingFunctionOnce` performance characteristics:
56/// - No reference counting overhead
57/// - No lock acquisition or runtime borrow checking
58/// - Direct function call through vtable
59/// - Minimal memory footprint (single pointer)
60///
61/// # Why No Arc/Rc Variants?
62///
63/// FnOnce can only be called once, which conflicts with Arc/Rc shared
64/// ownership semantics:
65/// - Arc/Rc implies multiple owners might need to call
66/// - FnOnce is consumed after calling, cannot be called again
67/// - These semantics make Arc/Rc variants meaningless
68///
69/// # Examples
70///
71/// ## Basic Usage
72///
73/// ```rust
74/// use qubit_function::{MutatingFunctionOnce, BoxMutatingFunctionOnce};
75///
76/// let data = vec![1, 2, 3];
77/// let func = BoxMutatingFunctionOnce::new(move |x: &mut Vec<i32>| {
78///     let old_len = x.len();
79///     x.extend(data); // Move data
80///     old_len
81/// });
82///
83/// let mut target = vec![0];
84/// let old_len = func.apply(&mut target);
85/// assert_eq!(old_len, 1);
86/// assert_eq!(target, vec![0, 1, 2, 3]);
87/// ```
88///
89/// ## Method Chaining
90///
91/// ```rust
92/// use qubit_function::{MutatingFunctionOnce, BoxMutatingFunctionOnce};
93///
94/// let data1 = vec![1, 2];
95/// let additional_len = 2;
96///
97/// let chained = BoxMutatingFunctionOnce::new(move |x: &mut Vec<i32>| {
98///     x.extend(data1);
99///     x.len()
100/// })
101/// .and_then(move |len: &usize| len + additional_len);
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///
109pub struct BoxMutatingFunctionOnce<T, R> {
110    pub(super) function: Box<dyn FnOnce(&mut T) -> R>,
111    pub(super) name: Option<String>,
112}
113
114impl<T, R> BoxMutatingFunctionOnce<T, R> {
115    // Generates: new(), new_with_name(), new_with_optional_name(), name(), set_name()
116    impl_function_common_methods!(
117        BoxMutatingFunctionOnce<T, R>,
118        (FnOnce(&mut T) -> R + 'static),
119        |f| Box::new(f)
120    );
121
122    // Generates: when(), and_then(), compose()
123    impl_box_function_methods!(
124        BoxMutatingFunctionOnce<T, R>,
125        BoxConditionalMutatingFunctionOnce,
126        FunctionOnce    // chains a non-mutating function after this mutating function
127    );
128}
129
130impl<T, R> MutatingFunctionOnce<T, R> for BoxMutatingFunctionOnce<T, R> {
131    fn apply(self, input: &mut T) -> R {
132        (self.function)(input)
133    }
134
135    impl_box_once_conversions!(
136        BoxMutatingFunctionOnce<T, R>,
137        MutatingFunctionOnce,
138        FnOnce(&mut T) -> R
139    );
140}
141
142// Generates: identity() method for BoxMutatingFunctionOnce<T, T>
143impl_function_identity_method!(BoxMutatingFunctionOnce<T, T>, mutating);
144
145// Generates: Debug and Display implementations for BoxMutatingFunctionOnce<T, R>
146impl_function_debug_display!(BoxMutatingFunctionOnce<T, R>);
147
148// =======================================================================
149// 3. Implement MutatingFunctionOnce trait for closures
150// =======================================================================
151
152// Implement MutatingFunctionOnce for all FnOnce(&mut T) -> R using macro
153impl_closure_once_trait!(
154    MutatingFunctionOnce<T, R>,
155    apply,
156    BoxMutatingFunctionOnce,
157    FnOnce(input: &mut T) -> R
158);