prism3_function/
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//! This module provides a unified `ConsumerOnce` trait and one concrete implementation:
15//!
16//! - **`BoxConsumerOnce<T>`**: Box-based single ownership implementation
17//!
18//! # Why No Arc/Rc Variants?
19//!
20//! Unlike `Consumer` and `ReadonlyConsumer`, this module does **not** provide `ArcConsumerOnce`
21//! or `RcConsumerOnce` implementations. This is a design decision based on the fact that
22//! `FnOnce` semantics are fundamentally incompatible with shared ownership. See design docs for details.
23//!
24//! # Design Philosophy
25//!
26//! ConsumerOnce uses `FnOnce(&T)` semantics for truly one-time consumption operations.
27//! Unlike Consumer, ConsumerOnce consumes itself on first call. Suitable for initialization
28//! callbacks, cleanup callbacks, and similar scenarios.
29//!
30//! # Author
31//!
32//! Hu Haixing
33
34use std::fmt;
35
36use crate::predicate::{BoxPredicate, Predicate};
37
38// ============================================================================
39// 1. ConsumerOnce Trait - Unified ConsumerOnce Interface
40// ============================================================================
41
42/// ConsumerOnce trait - Unified one-time consumer interface
43///
44/// Defines the core behavior of all one-time consumer types. Similar to consumers
45/// implementing `FnOnce(&T)`, executes operations that accept a value reference but
46/// return no result (only side effects), consuming itself in the process.
47///
48/// # Automatic Implementation
49///
50/// - All closures implementing `FnOnce(&T)`
51/// - `BoxConsumerOnce<T>`
52///
53/// # Features
54///
55/// - **Unified Interface**: All consumer types share the same `accept` method signature
56/// - **Automatic Implementation**: Closures automatically implement this trait with zero overhead
57/// - **Type Conversion**: Can be converted to BoxConsumerOnce
58/// - **Generic Programming**: Write functions that work with any one-time consumer type
59///
60/// # Examples
61///
62/// ```rust
63/// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
64/// use std::sync::{Arc, Mutex};
65///
66/// fn apply_consumer<C: ConsumerOnce<i32>>(consumer: C, value: &i32) {
67///     consumer.accept(value);
68/// }
69///
70/// let log = Arc::new(Mutex::new(Vec::new()));
71/// let l = log.clone();
72/// let box_con = BoxConsumerOnce::new(move |x: &i32| {
73///     l.lock().unwrap().push(*x);
74/// });
75/// apply_consumer(box_con, &5);
76/// assert_eq!(*log.lock().unwrap(), vec![5]);
77/// ```
78///
79/// # Author
80///
81/// Hu Haixing
82pub trait ConsumerOnce<T> {
83    /// Execute one-time consumption operation
84    ///
85    /// Executes an operation on the given reference. The operation typically reads
86    /// the input value or produces side effects, but does not modify the input
87    /// value itself. Consumes self.
88    ///
89    /// # Parameters
90    ///
91    /// * `value` - Reference to the value to be consumed
92    ///
93    /// # Examples
94    ///
95    /// ```rust
96    /// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
97    ///
98    /// let consumer = BoxConsumerOnce::new(|x: &i32| println!("{}", x));
99    /// consumer.accept(&5);
100    /// ```
101    fn accept(self, value: &T);
102
103    /// Convert to BoxConsumerOnce
104    ///
105    /// **⚠️ Consumes `self`**: The original consumer will be unavailable after calling this method.
106    ///
107    /// # Returns
108    ///
109    /// Returns the wrapped `BoxConsumerOnce<T>`
110    ///
111    /// # Examples
112    ///
113    /// ```rust
114    /// use prism3_function::ConsumerOnce;
115    /// use std::sync::{Arc, Mutex};
116    ///
117    /// let log = Arc::new(Mutex::new(Vec::new()));
118    /// let l = log.clone();
119    /// let closure = move |x: &i32| {
120    ///     l.lock().unwrap().push(*x);
121    /// };
122    /// let box_consumer = closure.into_box();
123    /// box_consumer.accept(&5);
124    /// assert_eq!(*log.lock().unwrap(), vec![5]);
125    /// ```
126    fn into_box(self) -> BoxConsumerOnce<T>
127    where
128        Self: Sized + 'static,
129        T: 'static;
130
131    /// Convert to closure
132    ///
133    /// **⚠️ Consumes `self`**: The original consumer will be unavailable after calling this method.
134    ///
135    /// Converts a one-time consumer to a closure that can be used directly in places
136    /// where the standard library requires `FnOnce`.
137    ///
138    /// # Returns
139    ///
140    /// Returns a closure implementing `FnOnce(&T)`
141    fn into_fn(self) -> impl FnOnce(&T)
142    where
143        Self: Sized + 'static,
144        T: 'static;
145}
146
147// ============================================================================
148// 2. BoxConsumerOnce - Single Ownership Implementation
149// ============================================================================
150
151/// BoxConsumerOnce struct
152///
153/// One-time consumer implementation based on `Box<dyn FnOnce(&T)>` for single ownership scenarios.
154/// This is the simplest consumer type for truly one-time use.
155///
156/// # Features
157///
158/// - **Single Ownership**: Not cloneable, transfers ownership on use
159/// - **Zero Overhead**: No reference counting or lock overhead
160/// - **One-time Use**: Consumes self on first call
161/// - **Builder Pattern**: Method chaining naturally consumes `self`
162///
163/// # Use Cases
164///
165/// Choose `BoxConsumerOnce` when:
166/// - Consumer is truly used only once
167/// - Building pipelines where ownership flows naturally
168/// - Consumer captures values that should be consumed
169/// - Performance critical and cannot accept shared overhead
170///
171/// # Performance
172///
173/// `BoxConsumerOnce` has the best performance:
174/// - No reference counting overhead
175/// - No lock acquisition or runtime borrow checking
176/// - Direct function call through vtable
177/// - Minimal memory footprint (single pointer)
178///
179/// # Examples
180///
181/// ```rust
182/// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
183///
184/// let consumer = BoxConsumerOnce::new(|x: &i32| {
185///     println!("Value: {}", x);
186/// });
187/// consumer.accept(&5);
188/// ```
189///
190/// # Author
191///
192/// Hu Haixing
193pub struct BoxConsumerOnce<T> {
194    function: Box<dyn FnOnce(&T)>,
195    name: Option<String>,
196}
197
198impl<T> BoxConsumerOnce<T>
199where
200    T: 'static,
201{
202    /// Create a new BoxConsumerOnce
203    ///
204    /// # Type Parameters
205    ///
206    /// * `F` - Closure type
207    ///
208    /// # Parameters
209    ///
210    /// * `f` - Closure to be wrapped
211    ///
212    /// # Returns
213    ///
214    /// Returns a new `BoxConsumerOnce<T>` instance
215    ///
216    /// # Examples
217    ///
218    /// ```rust
219    /// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
220    /// use std::sync::{Arc, Mutex};
221    ///
222    /// let log = Arc::new(Mutex::new(Vec::new()));
223    /// let l = log.clone();
224    /// let consumer = BoxConsumerOnce::new(move |x: &i32| {
225    ///     l.lock().unwrap().push(*x + 1);
226    /// });
227    /// consumer.accept(&5);
228    /// assert_eq!(*log.lock().unwrap(), vec![6]);
229    /// ```
230    pub fn new<F>(f: F) -> Self
231    where
232        F: FnOnce(&T) + 'static,
233    {
234        BoxConsumerOnce {
235            function: Box::new(f),
236            name: None,
237        }
238    }
239
240    /// Get the consumer's name
241    pub fn name(&self) -> Option<&str> {
242        self.name.as_deref()
243    }
244
245    /// Set the consumer's name
246    pub fn set_name(&mut self, name: impl Into<String>) {
247        self.name = Some(name.into());
248    }
249
250    /// Sequentially chain another one-time consumer
251    ///
252    /// Returns a new consumer that executes the current operation first, then the next operation. Consumes self.
253    ///
254    /// # Type Parameters
255    ///
256    /// * `C` - Type of the next consumer
257    ///
258    /// # Parameters
259    ///
260    /// * `next` - Consumer to execute after the current operation. **Note: This
261    ///   parameter is passed by value and will transfer ownership.** Since
262    ///   `BoxConsumerOnce` cannot be cloned, the parameter will be consumed.
263    ///   Can be:
264    ///   - A closure: `|x: &T|`
265    ///   - A `BoxConsumerOnce<T>`
266    ///   - Any type implementing `ConsumerOnce<T>`
267    ///
268    /// # Returns
269    ///
270    /// Returns a new combined `BoxConsumerOnce<T>`
271    ///
272    /// # Examples
273    ///
274    /// ```rust
275    /// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
276    /// use std::sync::{Arc, Mutex};
277    ///
278    /// let log = Arc::new(Mutex::new(Vec::new()));
279    /// let l1 = log.clone();
280    /// let l2 = log.clone();
281    /// let first = BoxConsumerOnce::new(move |x: &i32| {
282    ///     l1.lock().unwrap().push(*x * 2);
283    /// });
284    /// let second = BoxConsumerOnce::new(move |x: &i32| {
285    ///     l2.lock().unwrap().push(*x + 10);
286    /// });
287    ///
288    /// // Both first and second are moved and consumed
289    /// let chained = first.and_then(second);
290    /// chained.accept(&5);
291    /// assert_eq!(*log.lock().unwrap(), vec![10, 15]);
292    /// // first.accept(&3); // Would not compile - moved
293    /// // second.accept(&3); // Would not compile - moved
294    /// ```
295    pub fn and_then<C>(self, next: C) -> Self
296    where
297        C: ConsumerOnce<T> + 'static,
298    {
299        let first = self.function;
300        let second = next;
301        BoxConsumerOnce::new(move |t| {
302            first(t);
303            second.accept(t);
304        })
305    }
306
307    /// Create a no-op consumer
308    ///
309    /// # Returns
310    ///
311    /// Returns a no-op consumer
312    ///
313    /// # Examples
314    ///
315    /// ```rust
316    /// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
317    ///
318    /// let noop = BoxConsumerOnce::<i32>::noop();
319    /// noop.accept(&42);
320    /// // Value unchanged
321    /// ```
322    pub fn noop() -> Self {
323        BoxConsumerOnce::new(|_| {})
324    }
325
326    /// Creates a conditional consumer
327    ///
328    /// Returns a consumer that only executes when a predicate is satisfied.
329    ///
330    /// # Parameters
331    ///
332    /// * `predicate` - The condition to check, can be:
333    ///   - Closure: `|x: &T| -> bool`
334    ///   - Function pointer: `fn(&T) -> bool`
335    ///   - `BoxPredicate<T>`
336    ///   - Any type implementing `Predicate<T>`
337    ///
338    /// # Returns
339    ///
340    /// Returns `BoxConditionalConsumerOnce<T>`
341    ///
342    /// # Examples
343    ///
344    /// ```rust
345    /// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
346    /// use std::sync::{Arc, Mutex};
347    ///
348    /// let log = Arc::new(Mutex::new(Vec::new()));
349    /// let l = log.clone();
350    /// let consumer = BoxConsumerOnce::new(move |x: &i32| {
351    ///     l.lock().unwrap().push(*x);
352    /// });
353    /// let conditional = consumer.when(|x: &i32| *x > 0);
354    ///
355    /// conditional.accept(&5);
356    /// assert_eq!(*log.lock().unwrap(), vec![5]);
357    /// ```
358    pub fn when<P>(self, predicate: P) -> BoxConditionalConsumerOnce<T>
359    where
360        P: Predicate<T> + 'static,
361    {
362        BoxConditionalConsumerOnce {
363            consumer: self,
364            predicate: predicate.into_box(),
365        }
366    }
367}
368
369impl<T> ConsumerOnce<T> for BoxConsumerOnce<T> {
370    fn accept(self, value: &T) {
371        (self.function)(value)
372    }
373
374    fn into_box(self) -> BoxConsumerOnce<T>
375    where
376        T: 'static,
377    {
378        self
379    }
380
381    fn into_fn(self) -> impl FnOnce(&T)
382    where
383        T: 'static,
384    {
385        self.function
386    }
387}
388
389impl<T> fmt::Debug for BoxConsumerOnce<T> {
390    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
391        f.debug_struct("BoxConsumerOnce")
392            .field("name", &self.name)
393            .field("function", &"<function>")
394            .finish()
395    }
396}
397
398impl<T> fmt::Display for BoxConsumerOnce<T> {
399    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
400        match &self.name {
401            Some(name) => write!(f, "BoxConsumerOnce({})", name),
402            None => write!(f, "BoxConsumerOnce"),
403        }
404    }
405}
406
407// ============================================================================
408// 3. BoxConditionalConsumerOnce - Box-based Conditional Consumer
409// ============================================================================
410
411/// BoxConditionalConsumerOnce struct
412///
413/// A conditional one-time consumer that only executes when a predicate is satisfied.
414/// Uses `BoxConsumerOnce` and `BoxPredicate` for single ownership semantics.
415///
416/// This type is typically created by calling `BoxConsumerOnce::when()` and is
417/// designed to work with the `or_else()` method to create if-then-else logic.
418///
419/// # Features
420///
421/// - **Single Ownership**: Not cloneable, consumes `self` on use
422/// - **Conditional Execution**: Only consumes when predicate returns `true`
423/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
424/// - **Implements ConsumerOnce**: Can be used anywhere a `ConsumerOnce` is expected
425///
426/// # Examples
427///
428/// ## Basic Conditional Execution
429///
430/// ```rust
431/// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
432/// use std::sync::{Arc, Mutex};
433///
434/// let log = Arc::new(Mutex::new(Vec::new()));
435/// let l = log.clone();
436/// let consumer = BoxConsumerOnce::new(move |x: &i32| {
437///     l.lock().unwrap().push(*x);
438/// });
439/// let conditional = consumer.when(|x: &i32| *x > 0);
440///
441/// conditional.accept(&5);
442/// assert_eq!(*log.lock().unwrap(), vec![5]); // Executed
443/// ```
444///
445/// ## With or_else Branch
446///
447/// ```rust
448/// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
449/// use std::sync::{Arc, Mutex};
450///
451/// let log = Arc::new(Mutex::new(Vec::new()));
452/// let l1 = log.clone();
453/// let l2 = log.clone();
454/// let consumer = BoxConsumerOnce::new(move |x: &i32| {
455///     l1.lock().unwrap().push(*x);
456/// })
457/// .when(|x: &i32| *x > 0)
458/// .or_else(move |x: &i32| {
459///     l2.lock().unwrap().push(-*x);
460/// });
461///
462/// consumer.accept(&5);
463/// assert_eq!(*log.lock().unwrap(), vec![5]); // when branch executed
464/// ```
465///
466/// # Author
467///
468/// Hu Haixing
469pub struct BoxConditionalConsumerOnce<T> {
470    consumer: BoxConsumerOnce<T>,
471    predicate: BoxPredicate<T>,
472}
473
474impl<T> ConsumerOnce<T> for BoxConditionalConsumerOnce<T>
475where
476    T: 'static,
477{
478    fn accept(self, value: &T) {
479        if self.predicate.test(value) {
480            self.consumer.accept(value);
481        }
482    }
483
484    fn into_box(self) -> BoxConsumerOnce<T> {
485        let pred = self.predicate;
486        let consumer = self.consumer;
487        BoxConsumerOnce::new(move |t| {
488            if pred.test(t) {
489                consumer.accept(t);
490            }
491        })
492    }
493
494    fn into_fn(self) -> impl FnOnce(&T) {
495        let pred = self.predicate;
496        let consumer = self.consumer;
497        move |t: &T| {
498            if pred.test(t) {
499                consumer.accept(t);
500            }
501        }
502    }
503}
504
505impl<T> BoxConditionalConsumerOnce<T>
506where
507    T: 'static,
508{
509    /// Chains another consumer in sequence
510    ///
511    /// Combines the current conditional consumer with another consumer into a new
512    /// consumer. The current conditional consumer executes first, followed by the
513    /// next consumer.
514    ///
515    /// # Parameters
516    ///
517    /// * `next` - The next consumer to execute. **Note: This parameter is passed
518    ///   by value and will transfer ownership.** Since `BoxConsumerOnce` cannot
519    ///   be cloned, the parameter will be consumed. Can be:
520    ///   - A closure: `|x: &T|`
521    ///   - A `BoxConsumerOnce<T>`
522    ///   - Any type implementing `ConsumerOnce<T>`
523    ///
524    /// # Returns
525    ///
526    /// Returns a new `BoxConsumerOnce<T>`
527    ///
528    /// # Examples
529    ///
530    /// ```rust
531    /// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
532    /// use std::sync::{Arc, Mutex};
533    ///
534    /// let log = Arc::new(Mutex::new(Vec::new()));
535    /// let l1 = log.clone();
536    /// let l2 = log.clone();
537    /// let cond1 = BoxConsumerOnce::new(move |x: &i32| {
538    ///     l1.lock().unwrap().push(*x * 2);
539    /// }).when(|x: &i32| *x > 0);
540    /// let cond2 = BoxConsumerOnce::new(move |x: &i32| {
541    ///     l2.lock().unwrap().push(*x + 100);
542    /// }).when(|x: &i32| *x > 10);
543    ///
544    /// // Both cond1 and cond2 are moved and consumed
545    /// let chained = cond1.and_then(cond2);
546    /// chained.accept(&6);
547    /// assert_eq!(*log.lock().unwrap(), vec![12, 106]); // First *2 = 12, then +100 = 106
548    /// // cond1.accept(&3); // Would not compile - moved
549    /// // cond2.accept(&3); // Would not compile - moved
550    /// ```
551    pub fn and_then<C>(self, next: C) -> BoxConsumerOnce<T>
552    where
553        C: ConsumerOnce<T> + 'static,
554    {
555        let first = self;
556        let second = next;
557        BoxConsumerOnce::new(move |t| {
558            first.accept(t);
559            second.accept(t);
560        })
561    }
562
563    /// Adds an else branch
564    ///
565    /// Executes the original consumer when the condition is satisfied, otherwise
566    /// executes else_consumer.
567    ///
568    /// # Parameters
569    ///
570    /// * `else_consumer` - The consumer for the else branch. **Note: This parameter
571    ///   is passed by value and will transfer ownership.** Since `BoxConsumerOnce`
572    ///   cannot be cloned, the parameter will be consumed. Can be:
573    ///   - A closure: `|x: &T|`
574    ///   - A `BoxConsumerOnce<T>`
575    ///   - Any type implementing `ConsumerOnce<T>`
576    ///
577    /// # Returns
578    ///
579    /// Returns the composed `BoxConsumerOnce<T>`
580    ///
581    /// # Examples
582    ///
583    /// ## Using a closure (recommended)
584    ///
585    /// ```rust
586    /// use prism3_function::{ConsumerOnce, BoxConsumerOnce};
587    /// use std::sync::{Arc, Mutex};
588    ///
589    /// let log = Arc::new(Mutex::new(Vec::new()));
590    /// let l1 = log.clone();
591    /// let l2 = log.clone();
592    /// let consumer = BoxConsumerOnce::new(move |x: &i32| {
593    ///     l1.lock().unwrap().push(*x);
594    /// })
595    /// .when(|x: &i32| *x > 0)
596    /// .or_else(move |x: &i32| {
597    ///     l2.lock().unwrap().push(-*x);
598    /// });
599    ///
600    /// consumer.accept(&5);
601    /// assert_eq!(*log.lock().unwrap(), vec![5]); // Condition satisfied, execute first
602    /// ```
603    pub fn or_else<C>(self, else_consumer: C) -> BoxConsumerOnce<T>
604    where
605        C: ConsumerOnce<T> + 'static,
606    {
607        let pred = self.predicate;
608        let then_cons = self.consumer;
609        let else_cons = else_consumer;
610        BoxConsumerOnce::new(move |t| {
611            if pred.test(t) {
612                then_cons.accept(t);
613            } else {
614                else_cons.accept(t);
615            }
616        })
617    }
618}
619
620// ============================================================================
621// 4. Implement ConsumerOnce trait for closures
622// ============================================================================
623
624/// Implement ConsumerOnce for all FnOnce(&T)
625impl<T, F> ConsumerOnce<T> for F
626where
627    F: FnOnce(&T),
628{
629    fn accept(self, value: &T) {
630        self(value)
631    }
632
633    fn into_box(self) -> BoxConsumerOnce<T>
634    where
635        Self: Sized + 'static,
636        T: 'static,
637    {
638        BoxConsumerOnce::new(self)
639    }
640
641    fn into_fn(self) -> impl FnOnce(&T)
642    where
643        Self: Sized + 'static,
644        T: 'static,
645    {
646        self
647    }
648}
649
650// ============================================================================
651// 5. Extension methods for closures
652// ============================================================================
653
654/// Extension trait providing one-time consumer composition methods for closures
655///
656/// Provides `and_then` and other composition methods for all closures implementing `FnOnce(&T)`,
657/// allowing closures to chain methods directly without explicit wrapper types.
658///
659/// # Features
660///
661/// - **Natural Syntax**: Chain operations directly on closures
662/// - **Returns BoxConsumerOnce**: Composed results can continue chaining
663/// - **Zero Cost**: No overhead when composing closures
664/// - **Automatic Implementation**: All `FnOnce(&T)` closures automatically get these methods
665///
666/// # Examples
667///
668/// ```rust
669/// use prism3_function::{ConsumerOnce, FnConsumerOnceOps};
670/// use std::sync::{Arc, Mutex};
671///
672/// let log = Arc::new(Mutex::new(Vec::new()));
673/// let l1 = log.clone();
674/// let l2 = log.clone();
675/// let chained = (move |x: &i32| {
676///     l1.lock().unwrap().push(*x * 2);
677/// }).and_then(move |x: &i32| {
678///     l2.lock().unwrap().push(*x + 10);
679/// });
680/// chained.accept(&5);
681/// assert_eq!(*log.lock().unwrap(), vec![10, 15]);
682/// ```
683///
684/// # Author
685///
686/// Hu Haixing
687pub trait FnConsumerOnceOps<T>: FnOnce(&T) + Sized {
688    /// Sequentially chain another one-time consumer
689    ///
690    /// Returns a new consumer that executes the current operation first, then the next operation.
691    /// Consumes the current closure and returns `BoxConsumerOnce<T>`.
692    ///
693    /// # Type Parameters
694    ///
695    /// * `C` - Type of the next consumer
696    ///
697    /// # Parameters
698    ///
699    /// * `next` - Consumer to execute after the current operation. **Note: This
700    ///   parameter is passed by value and will transfer ownership.** Since
701    ///   `BoxConsumerOnce` cannot be cloned, the parameter will be consumed.
702    ///   Can be:
703    ///   - A closure: `|x: &T|`
704    ///   - A `BoxConsumerOnce<T>`
705    ///   - Any type implementing `ConsumerOnce<T>`
706    ///
707    /// # Returns
708    ///
709    /// Returns a combined `BoxConsumerOnce<T>`
710    ///
711    /// # Examples
712    ///
713    /// ```rust
714    /// use prism3_function::{ConsumerOnce, FnConsumerOnceOps};
715    /// use std::sync::{Arc, Mutex};
716    ///
717    /// let log = Arc::new(Mutex::new(Vec::new()));
718    /// let l1 = log.clone();
719    /// let l2 = log.clone();
720    /// let chained = (move |x: &i32| {
721    ///     l1.lock().unwrap().push(*x * 2);
722    /// }).and_then(move |x: &i32| {
723    ///     l2.lock().unwrap().push(*x + 10);
724    /// }).and_then(|x: &i32| println!("Result: {}", x));
725    ///
726    /// chained.accept(&5);
727    /// assert_eq!(*log.lock().unwrap(), vec![10, 15]);
728    /// ```
729    fn and_then<C>(self, next: C) -> BoxConsumerOnce<T>
730    where
731        Self: 'static,
732        C: ConsumerOnce<T> + 'static,
733        T: 'static,
734    {
735        let first = self;
736        let second = next;
737        BoxConsumerOnce::new(move |t| {
738            first(t);
739            second.accept(t);
740        })
741    }
742}
743
744/// Implement FnConsumerOnceOps for all closure types
745impl<T, F> FnConsumerOnceOps<T> for F where F: FnOnce(&T) {}