qubit_function/consumers/consumer_once.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # ConsumerOnce Types
10//!
11//! Provides implementations of one-time consumer interfaces for executing one-time operations
12//! that accept a single input parameter but return no result.
13//!
14//! It is similar to the `FnOnce(&T)` trait in the standard library.
15//!
16//! This module provides a unified `ConsumerOnce` trait and one concrete implementation:
17//!
18//! - **`BoxConsumerOnce<T>`**: Box-based single ownership implementation
19//!
20//! # Why No Arc/Rc Variants?
21//!
22//! Unlike `Consumer` and `ReadonlyConsumer`, this module does **not** provide `ArcConsumerOnce`
23//! or `RcConsumerOnce` implementations. This is a design decision based on the fact that
24//! `FnOnce` semantics are fundamentally incompatible with shared ownership. See design docs for details.
25//!
26//! # Design Philosophy
27//!
28//! ConsumerOnce uses `FnOnce(&T)` semantics for truly one-time consumption operations.
29//!
30//! Unlike Consumer, ConsumerOnce consumes itself on first call. Suitable for initialization
31//! callbacks, cleanup callbacks, and similar scenarios.
32//!
33//! # Author
34//!
35//! Haixing Hu
36
37use crate::consumers::macros::{
38 impl_box_conditional_consumer,
39 impl_box_consumer_methods,
40 impl_conditional_consumer_debug_display,
41 impl_consumer_common_methods,
42 impl_consumer_debug_display,
43};
44use crate::macros::{
45 impl_box_once_conversions,
46 impl_closure_once_trait,
47};
48use crate::predicates::predicate::{
49 BoxPredicate,
50 Predicate,
51};
52
53// ============================================================================
54// 1. ConsumerOnce Trait - Unified ConsumerOnce Interface
55// ============================================================================
56
57/// ConsumerOnce trait - Unified one-time consumer interface
58///
59/// It is similar to the `FnOnce(&T)` trait in the standard library.
60///
61/// Defines the core behavior of all one-time consumer types. Similar to consumers
62/// implementing `FnOnce(&T)`, executes operations that accept a value reference but
63/// return no result (only side effects), consuming itself in the process.
64///
65/// # Automatic Implementation
66///
67/// - All closures implementing `FnOnce(&T)`
68/// - `BoxConsumerOnce<T>`
69///
70/// # Features
71///
72/// - **Unified Interface**: All consumer types share the same `accept` method signature
73/// - **Automatic Implementation**: Closures automatically implement this trait with zero overhead
74/// - **Type Conversion**: Can be converted to BoxConsumerOnce
75/// - **Generic Programming**: Write functions that work with any one-time consumer type
76///
77/// # Examples
78///
79/// ```rust
80/// use qubit_function::{ConsumerOnce, BoxConsumerOnce};
81/// use std::sync::{Arc, Mutex};
82///
83/// fn apply_consumer<C: ConsumerOnce<i32>>(consumer: C, value: &i32) {
84/// consumer.accept(value);
85/// }
86///
87/// let log = Arc::new(Mutex::new(Vec::new()));
88/// let l = log.clone();
89/// let box_con = BoxConsumerOnce::new(move |x: &i32| {
90/// l.lock().unwrap().push(*x);
91/// });
92/// apply_consumer(box_con, &5);
93/// assert_eq!(*log.lock().unwrap(), vec![5]);
94/// ```
95///
96/// # Author
97///
98/// Haixing Hu
99pub trait ConsumerOnce<T> {
100 /// Execute one-time consumption operation
101 ///
102 /// Executes an operation on the given reference. The operation typically reads
103 /// the input value or produces side effects, but does not modify the input
104 /// value itself. Consumes self.
105 ///
106 /// # Parameters
107 ///
108 /// * `value` - Reference to the value to be consumed
109 ///
110 /// # Examples
111 ///
112 /// ```rust
113 /// use qubit_function::{ConsumerOnce, BoxConsumerOnce};
114 ///
115 /// let consumer = BoxConsumerOnce::new(|x: &i32| println!("{}", x));
116 /// consumer.accept(&5);
117 /// ```
118 fn accept(self, value: &T);
119
120 /// Convert to BoxConsumerOnce
121 ///
122 /// **⚠️ Consumes `self`**: The original consumer will be unavailable after calling this method.
123 ///
124 /// # Default Implementation
125 ///
126 /// The default implementation wraps `self` in a `BoxConsumerOnce` by calling
127 /// `accept` on the consumer. Types can override this method to provide more
128 /// efficient conversions.
129 ///
130 /// # Returns
131 ///
132 /// Returns the wrapped `BoxConsumerOnce<T>`
133 ///
134 /// # Examples
135 ///
136 /// ```rust
137 /// use qubit_function::ConsumerOnce;
138 /// use std::sync::{Arc, Mutex};
139 ///
140 /// let log = Arc::new(Mutex::new(Vec::new()));
141 /// let l = log.clone();
142 /// let closure = move |x: &i32| {
143 /// l.lock().unwrap().push(*x);
144 /// };
145 /// let box_consumer = closure.into_box();
146 /// box_consumer.accept(&5);
147 /// assert_eq!(*log.lock().unwrap(), vec![5]);
148 /// ```
149 fn into_box(self) -> BoxConsumerOnce<T>
150 where
151 Self: Sized + 'static,
152 {
153 BoxConsumerOnce::new(move |t| self.accept(t))
154 }
155
156 /// Convert to closure
157 ///
158 /// **⚠️ Consumes `self`**: The original consumer will be unavailable after calling this method.
159 ///
160 /// Converts a one-time consumer to a closure that can be used directly in places
161 /// where the standard library requires `FnOnce`.
162 ///
163 /// # Default Implementation
164 ///
165 /// The default implementation creates a closure that captures `self` and calls
166 /// its `accept` method. Types can override this method to provide more efficient
167 /// conversions.
168 ///
169 /// # Returns
170 ///
171 /// Returns a closure implementing `FnOnce(&T)`
172 ///
173 /// # Examples
174 ///
175 /// ```rust
176 /// use qubit_function::ConsumerOnce;
177 /// use std::sync::{Arc, Mutex};
178 ///
179 /// let log = Arc::new(Mutex::new(Vec::new()));
180 /// let l = log.clone();
181 /// let closure = move |x: &i32| {
182 /// l.lock().unwrap().push(*x * 2);
183 /// };
184 /// let func = closure.into_fn();
185 /// func(&5);
186 /// assert_eq!(*log.lock().unwrap(), vec![10]);
187 /// ```
188 fn into_fn(self) -> impl FnOnce(&T)
189 where
190 Self: Sized + 'static,
191 {
192 move |t| self.accept(t)
193 }
194
195 /// Convert to BoxConsumerOnce without consuming self
196 ///
197 /// **⚠️ Requires Clone**: This method requires `Self` to implement
198 /// `Clone`. Clones the current consumer and wraps it in a
199 /// `BoxConsumerOnce`.
200 ///
201 /// # Default Implementation
202 ///
203 /// The default implementation clones `self` and then calls
204 /// `into_box()` on the clone. Types can override this method to
205 /// provide more efficient conversions.
206 ///
207 /// # Returns
208 ///
209 /// Returns the wrapped `BoxConsumerOnce<T>`
210 ///
211 /// # Examples
212 ///
213 /// ```rust
214 /// use qubit_function::ConsumerOnce;
215 /// use std::sync::{Arc, Mutex};
216 ///
217 /// let log = Arc::new(Mutex::new(Vec::new()));
218 /// let l = log.clone();
219 /// let closure = move |x: &i32| {
220 /// l.lock().unwrap().push(*x);
221 /// };
222 /// let box_consumer = closure.to_box();
223 /// box_consumer.accept(&5);
224 /// assert_eq!(*log.lock().unwrap(), vec![5]);
225 /// ```
226 fn to_box(&self) -> BoxConsumerOnce<T>
227 where
228 Self: Sized + Clone + 'static,
229 {
230 self.clone().into_box()
231 }
232
233 /// Convert to closure without consuming self
234 ///
235 /// **⚠️ Requires Clone**: This method requires `Self` to implement
236 /// `Clone`. Clones the current consumer and then converts the clone
237 /// to a closure.
238 ///
239 /// # Default Implementation
240 ///
241 /// The default implementation clones `self` and then calls
242 /// `into_fn()` on the clone. Types can override this method to
243 /// provide more efficient conversions.
244 ///
245 /// # Returns
246 ///
247 /// Returns a closure implementing `FnOnce(&T)`
248 ///
249 /// # Examples
250 ///
251 /// ```rust
252 /// use qubit_function::ConsumerOnce;
253 /// use std::sync::{Arc, Mutex};
254 ///
255 /// let log = Arc::new(Mutex::new(Vec::new()));
256 /// let l = log.clone();
257 /// let closure = move |x: &i32| {
258 /// l.lock().unwrap().push(*x * 2);
259 /// };
260 /// let func = closure.to_fn();
261 /// func(&5);
262 /// assert_eq!(*log.lock().unwrap(), vec![10]);
263 /// ```
264 fn to_fn(&self) -> impl FnOnce(&T)
265 where
266 Self: Sized + Clone + 'static,
267 {
268 self.clone().into_fn()
269 }
270}
271
272// ============================================================================
273// 2. BoxConsumerOnce - Single Ownership Implementation
274// ============================================================================
275
276/// BoxConsumerOnce struct
277///
278/// One-time consumer implementation based on `Box<dyn FnOnce(&T)>` for single ownership scenarios.
279/// This is the simplest consumer type for truly one-time use.
280///
281/// # Features
282///
283/// - **Single Ownership**: Not cloneable, transfers ownership on use
284/// - **Zero Overhead**: No reference counting or lock overhead
285/// - **One-time Use**: Consumes self on first call
286/// - **Builder Pattern**: Method chaining naturally consumes `self`
287///
288/// # Use Cases
289///
290/// Choose `BoxConsumerOnce` when:
291/// - Consumer is truly used only once
292/// - Building pipelines where ownership flows naturally
293/// - Consumer captures values that should be consumed
294/// - Performance critical and cannot accept shared overhead
295///
296/// # Performance
297///
298/// `BoxConsumerOnce` has the best performance:
299/// - No reference counting overhead
300/// - No lock acquisition or runtime borrow checking
301/// - Direct function call through vtable
302/// - Minimal memory footprint (single pointer)
303///
304/// # Examples
305///
306/// ```rust
307/// use qubit_function::{ConsumerOnce, BoxConsumerOnce};
308///
309/// let consumer = BoxConsumerOnce::new(|x: &i32| {
310/// println!("Value: {}", x);
311/// });
312/// consumer.accept(&5);
313/// ```
314///
315/// # Author
316///
317/// Haixing Hu
318pub struct BoxConsumerOnce<T> {
319 function: Box<dyn FnOnce(&T)>,
320 name: Option<String>,
321}
322
323// All methods require T: 'static because Box<dyn FnOnce(&T)> requires it
324impl<T> BoxConsumerOnce<T> {
325 // Generates: new(), new_with_name(), name(), set_name(), noop()
326 impl_consumer_common_methods!(BoxConsumerOnce<T>, (FnOnce(&T) + 'static), |f| Box::new(f));
327
328 // Generates: when() and and_then() methods that consume self
329 impl_box_consumer_methods!(BoxConsumerOnce<T>, BoxConditionalConsumerOnce, ConsumerOnce);
330}
331
332impl<T> ConsumerOnce<T> for BoxConsumerOnce<T> {
333 fn accept(self, value: &T) {
334 (self.function)(value)
335 }
336
337 impl_box_once_conversions!(BoxConsumerOnce<T>, ConsumerOnce, FnOnce(&T));
338}
339
340// Use macro to generate Debug and Display implementations
341impl_consumer_debug_display!(BoxConsumerOnce<T>);
342
343// ============================================================================
344// 3. Implement ConsumerOnce trait for closures
345// ============================================================================
346
347// Implement ConsumerOnce for all FnOnce(&T) using macro
348impl_closure_once_trait!(
349 ConsumerOnce<T>,
350 accept,
351 BoxConsumerOnce,
352 FnOnce(value: &T)
353);
354
355// ============================================================================
356// 4. Extension methods for closures
357// ============================================================================
358
359/// Extension trait providing one-time consumer composition methods for closures
360///
361/// Provides `and_then` and other composition methods for all closures implementing `FnOnce(&T)`,
362/// allowing closures to chain methods directly without explicit wrapper types.
363///
364/// # Features
365///
366/// - **Natural Syntax**: Chain operations directly on closures
367/// - **Returns BoxConsumerOnce**: Composed results can continue chaining
368/// - **Zero Cost**: No overhead when composing closures
369/// - **Automatic Implementation**: All `FnOnce(&T)` closures automatically get these methods
370///
371/// # Examples
372///
373/// ```rust
374/// use qubit_function::{ConsumerOnce, FnConsumerOnceOps};
375/// use std::sync::{Arc, Mutex};
376///
377/// let log = Arc::new(Mutex::new(Vec::new()));
378/// let l1 = log.clone();
379/// let l2 = log.clone();
380/// let chained = (move |x: &i32| {
381/// l1.lock().unwrap().push(*x * 2);
382/// }).and_then(move |x: &i32| {
383/// l2.lock().unwrap().push(*x + 10);
384/// });
385/// chained.accept(&5);
386/// assert_eq!(*log.lock().unwrap(), vec![10, 15]);
387/// ```
388///
389/// # Author
390///
391/// Haixing Hu
392pub trait FnConsumerOnceOps<T>: FnOnce(&T) + Sized {
393 /// Sequentially chain another one-time consumer
394 ///
395 /// Returns a new consumer that executes the current operation first, then the next operation.
396 /// Consumes the current closure and returns `BoxConsumerOnce<T>`.
397 ///
398 /// # Type Parameters
399 ///
400 /// * `C` - Type of the next consumer
401 ///
402 /// # Parameters
403 ///
404 /// * `next` - Consumer to execute after the current operation. **Note: This
405 /// parameter is passed by value and will transfer ownership.** Since
406 /// `BoxConsumerOnce` cannot be cloned, the parameter will be consumed.
407 /// Can be:
408 /// - A closure: `|x: &T|`
409 /// - A `BoxConsumerOnce<T>`
410 /// - Any type implementing `ConsumerOnce<T>`
411 ///
412 /// # Returns
413 ///
414 /// Returns a combined `BoxConsumerOnce<T>`
415 ///
416 /// # Examples
417 ///
418 /// ```rust
419 /// use qubit_function::{ConsumerOnce, FnConsumerOnceOps};
420 /// use std::sync::{Arc, Mutex};
421 ///
422 /// let log = Arc::new(Mutex::new(Vec::new()));
423 /// let l1 = log.clone();
424 /// let l2 = log.clone();
425 /// let chained = (move |x: &i32| {
426 /// l1.lock().unwrap().push(*x * 2);
427 /// }).and_then(move |x: &i32| {
428 /// l2.lock().unwrap().push(*x + 10);
429 /// }).and_then(|x: &i32| println!("Result: {}", x));
430 ///
431 /// chained.accept(&5);
432 /// assert_eq!(*log.lock().unwrap(), vec![10, 15]);
433 /// ```
434 fn and_then<C>(self, next: C) -> BoxConsumerOnce<T>
435 where
436 Self: 'static,
437 C: ConsumerOnce<T> + 'static,
438 T: 'static,
439 {
440 let first = self;
441 let second = next;
442 BoxConsumerOnce::new(move |t| {
443 first(t);
444 second.accept(t);
445 })
446 }
447}
448
449/// Implement FnConsumerOnceOps for all closure types
450impl<T, F> FnConsumerOnceOps<T> for F where F: FnOnce(&T) {}
451
452// ============================================================================
453// 5. BoxConditionalConsumerOnce - Box-based Conditional Consumer
454// ============================================================================
455
456/// BoxConditionalConsumerOnce struct
457///
458/// A conditional one-time consumer that only executes when a predicate is satisfied.
459/// Uses `BoxConsumerOnce` and `BoxPredicate` for single ownership semantics.
460///
461/// This type is typically created by calling `BoxConsumerOnce::when()` and is
462/// designed to work with the `or_else()` method to create if-then-else logic.
463///
464/// # Features
465///
466/// - **Single Ownership**: Not cloneable, consumes `self` on use
467/// - **Conditional Execution**: Only consumes when predicate returns `true`
468/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
469/// - **Implements ConsumerOnce**: Can be used anywhere a `ConsumerOnce` is expected
470///
471/// # Examples
472///
473/// ## Basic Conditional Execution
474///
475/// ```rust
476/// use qubit_function::{ConsumerOnce, BoxConsumerOnce};
477/// use std::sync::{Arc, Mutex};
478///
479/// let log = Arc::new(Mutex::new(Vec::new()));
480/// let l = log.clone();
481/// let consumer = BoxConsumerOnce::new(move |x: &i32| {
482/// l.lock().unwrap().push(*x);
483/// });
484/// let conditional = consumer.when(|x: &i32| *x > 0);
485///
486/// conditional.accept(&5);
487/// assert_eq!(*log.lock().unwrap(), vec![5]); // Executed
488/// ```
489///
490/// ## With or_else Branch
491///
492/// ```rust
493/// use qubit_function::{ConsumerOnce, BoxConsumerOnce};
494/// use std::sync::{Arc, Mutex};
495///
496/// let log = Arc::new(Mutex::new(Vec::new()));
497/// let l1 = log.clone();
498/// let l2 = log.clone();
499/// let consumer = BoxConsumerOnce::new(move |x: &i32| {
500/// l1.lock().unwrap().push(*x);
501/// })
502/// .when(|x: &i32| *x > 0)
503/// .or_else(move |x: &i32| {
504/// l2.lock().unwrap().push(-*x);
505/// });
506///
507/// consumer.accept(&5);
508/// assert_eq!(*log.lock().unwrap(), vec![5]); // when branch executed
509/// ```
510///
511/// # Author
512///
513/// Haixing Hu
514pub struct BoxConditionalConsumerOnce<T> {
515 consumer: BoxConsumerOnce<T>,
516 predicate: BoxPredicate<T>,
517}
518
519// Generate and_then and or_else methods using macro
520impl_box_conditional_consumer!(BoxConditionalConsumerOnce<T>, BoxConsumerOnce, ConsumerOnce);
521
522impl<T> ConsumerOnce<T> for BoxConditionalConsumerOnce<T> {
523 fn accept(self, value: &T) {
524 if self.predicate.test(value) {
525 self.consumer.accept(value);
526 }
527 }
528
529 fn into_fn(self) -> impl FnOnce(&T) {
530 let pred = self.predicate;
531 let consumer = self.consumer;
532 move |t: &T| {
533 if pred.test(t) {
534 consumer.accept(t);
535 }
536 }
537 }
538
539 // do NOT override ConsumerOnce::to_xxxx() because BoxConditionalConsumerOnce is not Clone
540 // and calling BoxConditionalConsumerOnce::to_xxxx() will cause a compile error
541}
542
543// Use macro to generate Debug and Display implementations
544impl_conditional_consumer_debug_display!(BoxConditionalConsumerOnce<T>);