prism3_function/consumers/
consumer_once.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025.
4 *    3-Prism 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 prism3_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 prism3_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 prism3_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        T: 'static,
153    {
154        BoxConsumerOnce::new(move |t| self.accept(t))
155    }
156
157    /// Convert to closure
158    ///
159    /// **⚠️ Consumes `self`**: The original consumer will be unavailable after calling this method.
160    ///
161    /// Converts a one-time consumer to a closure that can be used directly in places
162    /// where the standard library requires `FnOnce`.
163    ///
164    /// # Default Implementation
165    ///
166    /// The default implementation creates a closure that captures `self` and calls
167    /// its `accept` method. Types can override this method to provide more efficient
168    /// conversions.
169    ///
170    /// # Returns
171    ///
172    /// Returns a closure implementing `FnOnce(&T)`
173    ///
174    /// # Examples
175    ///
176    /// ```rust
177    /// use prism3_function::ConsumerOnce;
178    /// use std::sync::{Arc, Mutex};
179    ///
180    /// let log = Arc::new(Mutex::new(Vec::new()));
181    /// let l = log.clone();
182    /// let closure = move |x: &i32| {
183    ///     l.lock().unwrap().push(*x * 2);
184    /// };
185    /// let func = closure.into_fn();
186    /// func(&5);
187    /// assert_eq!(*log.lock().unwrap(), vec![10]);
188    /// ```
189    fn into_fn(self) -> impl FnOnce(&T)
190    where
191        Self: Sized + 'static,
192        T: 'static,
193    {
194        move |t| self.accept(t)
195    }
196
197    /// Convert to BoxConsumerOnce without consuming self
198    ///
199    /// **⚠️ Requires Clone**: This method requires `Self` to implement
200    /// `Clone`. Clones the current consumer and wraps it in a
201    /// `BoxConsumerOnce`.
202    ///
203    /// # Default Implementation
204    ///
205    /// The default implementation clones `self` and then calls
206    /// `into_box()` on the clone. Types can override this method to
207    /// provide more efficient conversions.
208    ///
209    /// # Returns
210    ///
211    /// Returns the wrapped `BoxConsumerOnce<T>`
212    ///
213    /// # Examples
214    ///
215    /// ```rust
216    /// use prism3_function::ConsumerOnce;
217    /// use std::sync::{Arc, Mutex};
218    ///
219    /// let log = Arc::new(Mutex::new(Vec::new()));
220    /// let l = log.clone();
221    /// let closure = move |x: &i32| {
222    ///     l.lock().unwrap().push(*x);
223    /// };
224    /// let box_consumer = closure.to_box();
225    /// box_consumer.accept(&5);
226    /// assert_eq!(*log.lock().unwrap(), vec![5]);
227    /// ```
228    fn to_box(&self) -> BoxConsumerOnce<T>
229    where
230        Self: Sized + Clone + 'static,
231        T: 'static,
232    {
233        self.clone().into_box()
234    }
235
236    /// Convert to closure without consuming self
237    ///
238    /// **⚠️ Requires Clone**: This method requires `Self` to implement
239    /// `Clone`. Clones the current consumer and then converts the clone
240    /// to a closure.
241    ///
242    /// # Default Implementation
243    ///
244    /// The default implementation clones `self` and then calls
245    /// `into_fn()` on the clone. Types can override this method to
246    /// provide more efficient conversions.
247    ///
248    /// # Returns
249    ///
250    /// Returns a closure implementing `FnOnce(&T)`
251    ///
252    /// # Examples
253    ///
254    /// ```rust
255    /// use prism3_function::ConsumerOnce;
256    /// use std::sync::{Arc, Mutex};
257    ///
258    /// let log = Arc::new(Mutex::new(Vec::new()));
259    /// let l = log.clone();
260    /// let closure = move |x: &i32| {
261    ///     l.lock().unwrap().push(*x * 2);
262    /// };
263    /// let func = closure.to_fn();
264    /// func(&5);
265    /// assert_eq!(*log.lock().unwrap(), vec![10]);
266    /// ```
267    fn to_fn(&self) -> impl FnOnce(&T)
268    where
269        Self: Sized + Clone + 'static,
270        T: 'static,
271    {
272        self.clone().into_fn()
273    }
274}
275
276// ============================================================================
277// 2. BoxConsumerOnce - Single Ownership Implementation
278// ============================================================================
279
280/// BoxConsumerOnce struct
281///
282/// One-time consumer implementation based on `Box<dyn FnOnce(&T)>` for single ownership scenarios.
283/// This is the simplest consumer type for truly one-time use.
284///
285/// # Features
286///
287/// - **Single Ownership**: Not cloneable, transfers ownership on use
288/// - **Zero Overhead**: No reference counting or lock overhead
289/// - **One-time Use**: Consumes self on first call
290/// - **Builder Pattern**: Method chaining naturally consumes `self`
291///
292/// # Use Cases
293///
294/// Choose `BoxConsumerOnce` when:
295/// - Consumer is truly used only once
296/// - Building pipelines where ownership flows naturally
297/// - Consumer captures values that should be consumed
298/// - Performance critical and cannot accept shared overhead
299///
300/// # Performance
301///
302/// `BoxConsumerOnce` has the best performance:
303/// - No reference counting overhead
304/// - No lock acquisition or runtime borrow checking
305/// - Direct function call through vtable
306/// - Minimal memory footprint (single pointer)
307///
308/// # Examples
309///
310/// ```rust
311/// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
312///
313/// let consumer = BoxConsumerOnce::new(|x: &i32| {
314///     println!("Value: {}", x);
315/// });
316/// consumer.accept(&5);
317/// ```
318///
319/// # Author
320///
321/// Haixing Hu
322pub struct BoxConsumerOnce<T> {
323    function: Box<dyn FnOnce(&T)>,
324    name: Option<String>,
325}
326
327// All methods require T: 'static because Box<dyn FnOnce(&T)> requires it
328impl<T> BoxConsumerOnce<T>
329where
330    T: 'static,
331{
332    // Generates: new(), new_with_name(), name(), set_name(), noop()
333    impl_consumer_common_methods!(BoxConsumerOnce<T>, (FnOnce(&T) + 'static), |f| Box::new(f));
334
335    // Generates: when() and and_then() methods that consume self
336    impl_box_consumer_methods!(BoxConsumerOnce<T>, BoxConditionalConsumerOnce, ConsumerOnce);
337}
338
339impl<T> ConsumerOnce<T> for BoxConsumerOnce<T> {
340    fn accept(self, value: &T) {
341        (self.function)(value)
342    }
343
344    impl_box_once_conversions!(BoxConsumerOnce<T>, ConsumerOnce, FnOnce(&T));
345}
346
347// Use macro to generate Debug and Display implementations
348impl_consumer_debug_display!(BoxConsumerOnce<T>);
349
350// ============================================================================
351// 3. Implement ConsumerOnce trait for closures
352// ============================================================================
353
354// Implement ConsumerOnce for all FnOnce(&T) using macro
355impl_closure_once_trait!(
356    ConsumerOnce<T>,
357    accept,
358    BoxConsumerOnce,
359    FnOnce(value: &T)
360);
361
362// ============================================================================
363// 4. Extension methods for closures
364// ============================================================================
365
366/// Extension trait providing one-time consumer composition methods for closures
367///
368/// Provides `and_then` and other composition methods for all closures implementing `FnOnce(&T)`,
369/// allowing closures to chain methods directly without explicit wrapper types.
370///
371/// # Features
372///
373/// - **Natural Syntax**: Chain operations directly on closures
374/// - **Returns BoxConsumerOnce**: Composed results can continue chaining
375/// - **Zero Cost**: No overhead when composing closures
376/// - **Automatic Implementation**: All `FnOnce(&T)` closures automatically get these methods
377///
378/// # Examples
379///
380/// ```rust
381/// use prism3_function::{ConsumerOnce, FnConsumerOnceOps};
382/// use std::sync::{Arc, Mutex};
383///
384/// let log = Arc::new(Mutex::new(Vec::new()));
385/// let l1 = log.clone();
386/// let l2 = log.clone();
387/// let chained = (move |x: &i32| {
388///     l1.lock().unwrap().push(*x * 2);
389/// }).and_then(move |x: &i32| {
390///     l2.lock().unwrap().push(*x + 10);
391/// });
392/// chained.accept(&5);
393/// assert_eq!(*log.lock().unwrap(), vec![10, 15]);
394/// ```
395///
396/// # Author
397///
398/// Haixing Hu
399pub trait FnConsumerOnceOps<T>: FnOnce(&T) + Sized {
400    /// Sequentially chain another one-time consumer
401    ///
402    /// Returns a new consumer that executes the current operation first, then the next operation.
403    /// Consumes the current closure and returns `BoxConsumerOnce<T>`.
404    ///
405    /// # Type Parameters
406    ///
407    /// * `C` - Type of the next consumer
408    ///
409    /// # Parameters
410    ///
411    /// * `next` - Consumer to execute after the current operation. **Note: This
412    ///   parameter is passed by value and will transfer ownership.** Since
413    ///   `BoxConsumerOnce` cannot be cloned, the parameter will be consumed.
414    ///   Can be:
415    ///   - A closure: `|x: &T|`
416    ///   - A `BoxConsumerOnce<T>`
417    ///   - Any type implementing `ConsumerOnce<T>`
418    ///
419    /// # Returns
420    ///
421    /// Returns a combined `BoxConsumerOnce<T>`
422    ///
423    /// # Examples
424    ///
425    /// ```rust
426    /// use prism3_function::{ConsumerOnce, FnConsumerOnceOps};
427    /// use std::sync::{Arc, Mutex};
428    ///
429    /// let log = Arc::new(Mutex::new(Vec::new()));
430    /// let l1 = log.clone();
431    /// let l2 = log.clone();
432    /// let chained = (move |x: &i32| {
433    ///     l1.lock().unwrap().push(*x * 2);
434    /// }).and_then(move |x: &i32| {
435    ///     l2.lock().unwrap().push(*x + 10);
436    /// }).and_then(|x: &i32| println!("Result: {}", x));
437    ///
438    /// chained.accept(&5);
439    /// assert_eq!(*log.lock().unwrap(), vec![10, 15]);
440    /// ```
441    fn and_then<C>(self, next: C) -> BoxConsumerOnce<T>
442    where
443        Self: 'static,
444        C: ConsumerOnce<T> + 'static,
445        T: 'static,
446    {
447        let first = self;
448        let second = next;
449        BoxConsumerOnce::new(move |t| {
450            first(t);
451            second.accept(t);
452        })
453    }
454}
455
456/// Implement FnConsumerOnceOps for all closure types
457impl<T, F> FnConsumerOnceOps<T> for F where F: FnOnce(&T) {}
458
459// ============================================================================
460// 5. BoxConditionalConsumerOnce - Box-based Conditional Consumer
461// ============================================================================
462
463/// BoxConditionalConsumerOnce struct
464///
465/// A conditional one-time consumer that only executes when a predicate is satisfied.
466/// Uses `BoxConsumerOnce` and `BoxPredicate` for single ownership semantics.
467///
468/// This type is typically created by calling `BoxConsumerOnce::when()` and is
469/// designed to work with the `or_else()` method to create if-then-else logic.
470///
471/// # Features
472///
473/// - **Single Ownership**: Not cloneable, consumes `self` on use
474/// - **Conditional Execution**: Only consumes when predicate returns `true`
475/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
476/// - **Implements ConsumerOnce**: Can be used anywhere a `ConsumerOnce` is expected
477///
478/// # Examples
479///
480/// ## Basic Conditional Execution
481///
482/// ```rust
483/// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
484/// use std::sync::{Arc, Mutex};
485///
486/// let log = Arc::new(Mutex::new(Vec::new()));
487/// let l = log.clone();
488/// let consumer = BoxConsumerOnce::new(move |x: &i32| {
489///     l.lock().unwrap().push(*x);
490/// });
491/// let conditional = consumer.when(|x: &i32| *x > 0);
492///
493/// conditional.accept(&5);
494/// assert_eq!(*log.lock().unwrap(), vec![5]); // Executed
495/// ```
496///
497/// ## With or_else Branch
498///
499/// ```rust
500/// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
501/// use std::sync::{Arc, Mutex};
502///
503/// let log = Arc::new(Mutex::new(Vec::new()));
504/// let l1 = log.clone();
505/// let l2 = log.clone();
506/// let consumer = BoxConsumerOnce::new(move |x: &i32| {
507///     l1.lock().unwrap().push(*x);
508/// })
509/// .when(|x: &i32| *x > 0)
510/// .or_else(move |x: &i32| {
511///     l2.lock().unwrap().push(-*x);
512/// });
513///
514/// consumer.accept(&5);
515/// assert_eq!(*log.lock().unwrap(), vec![5]); // when branch executed
516/// ```
517///
518/// # Author
519///
520/// Haixing Hu
521pub struct BoxConditionalConsumerOnce<T> {
522    consumer: BoxConsumerOnce<T>,
523    predicate: BoxPredicate<T>,
524}
525
526// Generate and_then and or_else methods using macro
527impl_box_conditional_consumer!(BoxConditionalConsumerOnce<T>, BoxConsumerOnce, ConsumerOnce);
528
529impl<T> ConsumerOnce<T> for BoxConditionalConsumerOnce<T>
530where
531    T: 'static,
532{
533    fn accept(self, value: &T) {
534        if self.predicate.test(value) {
535            self.consumer.accept(value);
536        }
537    }
538
539    fn into_box(self) -> BoxConsumerOnce<T> {
540        let pred = self.predicate;
541        let consumer = self.consumer;
542        BoxConsumerOnce::new(move |t| {
543            if pred.test(t) {
544                consumer.accept(t);
545            }
546        })
547    }
548
549    fn into_fn(self) -> impl FnOnce(&T) {
550        let pred = self.predicate;
551        let consumer = self.consumer;
552        move |t: &T| {
553            if pred.test(t) {
554                consumer.accept(t);
555            }
556        }
557    }
558
559    // do NOT override ConsumerOnce::to_xxxx() because BoxConditionalConsumerOnce is not Clone
560    // and calling BoxConditionalConsumerOnce::to_xxxx() will cause a compile error
561}
562
563// Use macro to generate Debug and Display implementations
564impl_conditional_consumer_debug_display!(BoxConditionalConsumerOnce<T>);