Skip to main content

qubit_function/consumers/
consumer.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # Consumer Types
10//!
11//! Provides implementations of non-mutating consumer interfaces for executing
12//! operations that neither modify their own state nor modify input values.
13//!
14//! It is similar to the `Fn(&T)` trait in the standard library.
15//!
16//! This module provides a unified `Consumer` trait and three concrete
17//! implementations based on different ownership models:
18//!
19//! - **`BoxConsumer<T>`**: Box-based single ownership implementation
20//! - **`ArcConsumer<T>`**: Arc-based thread-safe shared ownership
21//!   implementation
22//! - **`RcConsumer<T>`**: Rc-based single-threaded shared ownership
23//!   implementation
24//!
25//! # Design Philosophy
26//!
27//! Consumer uses `Fn(&T)` semantics: it is invoked through `&self` and receives
28//! shared references to input values.
29//!
30//! Suitable for pure observation, logging, notification and other scenarios.
31//! Compared to `StatefulConsumer`, `Consumer` does not require wrapper-level
32//! interior mutability (`Mutex`/`RefCell`), making it more efficient and easier
33//! to share.
34//!
35//! # Author
36//!
37//! Haixing Hu
38
39use std::rc::Rc;
40use std::sync::Arc;
41
42use crate::consumers::consumer_once::BoxConsumerOnce;
43use crate::consumers::macros::{
44    impl_box_conditional_consumer,
45    impl_box_consumer_methods,
46    impl_conditional_consumer_clone,
47    impl_conditional_consumer_conversions,
48    impl_conditional_consumer_debug_display,
49    impl_consumer_clone,
50    impl_consumer_common_methods,
51    impl_consumer_debug_display,
52    impl_shared_conditional_consumer,
53    impl_shared_consumer_methods,
54};
55use crate::macros::{
56    impl_arc_conversions,
57    impl_box_conversions,
58    impl_closure_trait,
59    impl_rc_conversions,
60};
61use crate::predicates::predicate::{
62    ArcPredicate,
63    BoxPredicate,
64    Predicate,
65    RcPredicate,
66};
67
68// ============================================================================
69// 1. Consumer Trait - Unified Consumer Interface
70// ============================================================================
71
72/// Consumer trait - Unified non-mutating consumer interface
73///
74/// It is similar to the `Fn(&T)` trait in the standard library.
75///
76/// Defines the core behavior of all non-mutating consumer types. The API uses
77/// `&self` and shared input references, so callers can use a consumer without
78/// granting mutable access to the consumer wrapper or input value.
79///
80/// # Auto-implementation
81///
82/// - All closures implementing `Fn(&T)`
83/// - `BoxConsumer<T>`, `ArcConsumer<T>`,
84///   `RcConsumer<T>`
85///
86/// # Features
87///
88/// - **Unified Interface**: All non-mutating consumer types share the same `accept`
89///   method signature
90/// - **Auto-implementation**: Closures automatically implement this trait with
91///   zero overhead
92/// - **Type Conversion**: Easy conversion between different ownership models
93/// - **Generic Programming**: Write functions that work with any non-mutating
94///   consumer type
95/// - **No Wrapper Interior Mutability**: No need for Mutex or RefCell in the
96///   wrapper, making shared ownership more efficient
97///
98/// # Examples
99///
100/// ```rust
101/// use qubit_function::{Consumer, BoxConsumer};
102///
103/// fn apply_consumer<C: Consumer<i32>>(consumer: &C, value: &i32) {
104///     consumer.accept(value);
105/// }
106///
107/// let box_con = BoxConsumer::new(|x: &i32| {
108///     println!("Value: {}", x);
109/// });
110/// apply_consumer(&box_con, &5);
111/// ```
112///
113/// # Author
114///
115/// Haixing Hu
116pub trait Consumer<T> {
117    /// Execute non-mutating consumption operation
118    ///
119    /// Performs an operation on the given reference. The operation typically
120    /// reads input values or produces side effects, but neither modifies the
121    /// input value nor the consumer's own state.
122    ///
123    /// # Parameters
124    ///
125    /// * `value` - Reference to the value to consume
126    ///
127    /// # Examples
128    ///
129    /// ```rust
130    /// use qubit_function::{Consumer, BoxConsumer};
131    ///
132    /// let consumer = BoxConsumer::new(|x: &i32| println!("{}", x));
133    /// consumer.accept(&5);
134    /// ```
135    fn accept(&self, value: &T);
136
137    /// Convert to BoxConsumer
138    ///
139    /// **⚠️ Consumes `self`**: The original consumer will be unavailable after
140    /// calling this method.
141    ///
142    /// # Returns
143    ///
144    /// Returns the wrapped `BoxConsumer<T>`
145    fn into_box(self) -> BoxConsumer<T>
146    where
147        Self: Sized + 'static,
148    {
149        BoxConsumer::new(move |t| self.accept(t))
150    }
151
152    /// Convert to RcConsumer
153    ///
154    /// **⚠️ Consumes `self`**: The original consumer will be unavailable after
155    /// calling this method.
156    ///
157    /// # Returns
158    ///
159    /// Returns the wrapped `RcConsumer<T>`
160    fn into_rc(self) -> RcConsumer<T>
161    where
162        Self: Sized + 'static,
163    {
164        RcConsumer::new(move |t| self.accept(t))
165    }
166
167    /// Convert to ArcConsumer
168    ///
169    /// **⚠️ Consumes `self`**: The original consumer will be unavailable after
170    /// calling this method.
171    ///
172    /// # Returns
173    ///
174    /// Returns the wrapped `ArcConsumer<T>`
175    fn into_arc(self) -> ArcConsumer<T>
176    where
177        Self: Sized + Send + Sync + 'static,
178    {
179        ArcConsumer::new(move |t| self.accept(t))
180    }
181
182    /// Convert to closure
183    ///
184    /// **⚠️ Consumes `self`**: The original consumer will be unavailable after
185    /// calling this method.
186    ///
187    /// Converts a non-mutating consumer to a closure that can be used directly in
188    /// places where the standard library requires `Fn`.
189    ///
190    /// # Returns
191    ///
192    /// Returns a closure implementing `Fn(&T)`
193    ///
194    /// # Examples
195    ///
196    /// ```rust
197    /// use qubit_function::{Consumer, BoxConsumer};
198    ///
199    /// let consumer = BoxConsumer::new(|x: &i32| {
200    ///     println!("Value: {}", x);
201    /// });
202    /// let func = consumer.into_fn();
203    /// func(&5);
204    /// ```
205    fn into_fn(self) -> impl Fn(&T)
206    where
207        Self: Sized + 'static,
208    {
209        move |t| self.accept(t)
210    }
211
212    /// Convert to ConsumerOnce
213    ///
214    /// **⚠️ Consumes `self`**: The original consumer will be unavailable after calling this method.
215    ///
216    /// Converts a reusable non-mutating consumer to a one-time consumer that consumes itself on use.
217    /// This enables passing `Consumer` to functions that require `ConsumerOnce`.
218    ///
219    /// # Returns
220    ///
221    /// Returns a `BoxConsumerOnce<T>`
222    ///
223    /// # Examples
224    ///
225    /// ```rust
226    /// use qubit_function::{Consumer, ConsumerOnce, BoxConsumer};
227    ///
228    /// fn takes_once<C: ConsumerOnce<i32>>(consumer: C, value: &i32) {
229    ///     consumer.accept(value);
230    /// }
231    ///
232    /// let consumer = BoxConsumer::new(|x: &i32| println!("{}", x));
233    /// takes_once(consumer.into_once(), &5);
234    /// ```
235    fn into_once(self) -> BoxConsumerOnce<T>
236    where
237        Self: Sized + 'static,
238    {
239        BoxConsumerOnce::new(move |t| self.accept(t))
240    }
241
242    /// Non-consuming conversion to `BoxConsumer`
243    ///
244    /// **⚠️ Does NOT consume `self`**: This method clones `self` and returns a
245    /// boxed non-mutating consumer that calls the cloned consumer. Requires
246    /// `Self: Clone` so it can be called through an immutable reference.
247    ///
248    /// # Returns
249    ///
250    /// Returns the wrapped `BoxConsumer<T>`
251    fn to_box(&self) -> BoxConsumer<T>
252    where
253        Self: Clone + 'static,
254    {
255        self.clone().into_box()
256    }
257
258    /// Non-consuming conversion to `RcConsumer`
259    ///
260    /// **⚠️ Does NOT consume `self`**: Clones `self` and returns an
261    /// `RcConsumer` that forwards to the cloned consumer. Requires
262    /// `Self: Clone`.
263    ///
264    /// # Returns
265    ///
266    /// Returns the wrapped `RcConsumer<T>`
267    fn to_rc(&self) -> RcConsumer<T>
268    where
269        Self: Clone + 'static,
270    {
271        self.clone().into_rc()
272    }
273
274    /// Non-consuming conversion to `ArcConsumer`
275    ///
276    /// **⚠️ Does NOT consume `self`**: Clones `self` and returns an
277    /// `ArcConsumer`. Requires `Self: Clone + Send + Sync` so the result
278    /// is thread-safe.
279    ///
280    /// # Returns
281    ///
282    /// Returns the wrapped `ArcConsumer<T>`
283    fn to_arc(&self) -> ArcConsumer<T>
284    where
285        Self: Clone + Send + Sync + 'static,
286    {
287        self.clone().into_arc()
288    }
289
290    /// Non-consuming conversion to a boxed closure
291    ///
292    /// **⚠️ Does NOT consume `self`**: Returns a closure which calls a cloned
293    /// copy of the consumer. Requires `Self: Clone`.
294    ///
295    /// # Returns
296    ///
297    /// Returns a closure implementing `Fn(&T)` which forwards to the cloned
298    /// consumer.
299    fn to_fn(&self) -> impl Fn(&T)
300    where
301        Self: Clone + 'static,
302    {
303        self.clone().into_fn()
304    }
305
306    /// Convert to ConsumerOnce without consuming self
307    ///
308    /// **⚠️ Requires Clone**: This method requires `Self` to implement `Clone`.
309    /// Clones the current consumer and converts the clone to a one-time consumer.
310    ///
311    /// # Returns
312    ///
313    /// Returns a `BoxConsumerOnce<T>`
314    ///
315    /// # Examples
316    ///
317    /// ```rust
318    /// use qubit_function::{Consumer, ConsumerOnce, ArcConsumer};
319    ///
320    /// fn takes_once<C: ConsumerOnce<i32>>(consumer: C, value: &i32) {
321    ///     consumer.accept(value);
322    /// }
323    ///
324    /// let consumer = ArcConsumer::new(|x: &i32| println!("{}", x));
325    /// takes_once(consumer.to_once(), &5);
326    /// ```
327    fn to_once(&self) -> BoxConsumerOnce<T>
328    where
329        Self: Clone + 'static,
330    {
331        self.clone().into_once()
332    }
333}
334
335// ============================================================================
336// 2. BoxConsumer - Single Ownership Implementation
337// ============================================================================
338
339/// BoxConsumer struct
340///
341/// Non-mutating consumer implementation based on `Box<dyn Fn(&T)>` for single
342/// ownership scenarios.
343///
344/// # Features
345///
346/// - **Single Ownership**: Not cloneable, transfers ownership when used
347/// - **Zero Overhead**: No reference counting or lock overhead
348/// - **Shared-reference API**: Invoked through `&self` and shared input
349///   references
350/// - **No Wrapper Interior Mutability**: No need for Mutex or RefCell in the
351///   wrapper
352///
353/// # Use Cases
354///
355/// Choose `BoxConsumer` when:
356/// - Non-mutating consumer is used once or in a linear flow
357/// - No need to share consumer across contexts
358/// - Pure observation operations, such as logging
359///
360/// # Examples
361///
362/// ```rust
363/// use qubit_function::{Consumer, BoxConsumer};
364///
365/// let consumer = BoxConsumer::new(|x: &i32| {
366///     println!("Observed value: {}", x);
367/// });
368/// consumer.accept(&5);
369/// ```
370///
371/// # Author
372///
373/// Haixing Hu
374pub struct BoxConsumer<T> {
375    function: Box<dyn Fn(&T)>,
376    name: Option<String>,
377}
378
379impl<T> BoxConsumer<T> {
380    // Generates: new(), new_with_name(), name(), set_name(), noop()
381    impl_consumer_common_methods!(BoxConsumer<T>, (Fn(&T) + 'static), |f| Box::new(f));
382
383    // Generates: when() and and_then() methods that consume self
384    impl_box_consumer_methods!(BoxConsumer<T>, BoxConditionalConsumer, Consumer);
385}
386
387impl<T> Consumer<T> for BoxConsumer<T> {
388    fn accept(&self, value: &T) {
389        (self.function)(value)
390    }
391
392    // Generates: into_box(), into_rc(), into_fn(), into_once()
393    impl_box_conversions!(BoxConsumer<T>, RcConsumer, Fn(&T), BoxConsumerOnce);
394}
395
396// Use macro to generate Debug and Display implementations
397impl_consumer_debug_display!(BoxConsumer<T>);
398
399// ============================================================================
400// 3. RcConsumer - Single-threaded Shared Ownership Implementation
401// ============================================================================
402
403/// RcConsumer struct
404///
405/// Non-mutating consumer implementation based on `Rc<dyn Fn(&T)>` for
406/// single-threaded shared ownership scenarios. The wrapper does not need
407/// `RefCell` because it only invokes a shared `Fn`.
408///
409/// # Features
410///
411/// - **Shared Ownership**: Cloneable through `Rc`, allows multiple owners
412/// - **Single-threaded**: Not thread-safe, cannot be sent across threads
413/// - **No Wrapper Interior Mutability Overhead**: No RefCell needed by the
414///   wrapper
415/// - **Non-consuming API**: `and_then` borrows `&self`, original object remains
416///   usable
417///
418/// # Use Cases
419///
420/// Choose `RcConsumer` when:
421/// - Need to share non-mutating consumer within a single thread
422/// - Pure observation operations, performance critical
423/// - Event handling in single-threaded UI frameworks
424///
425/// # Performance Advantages
426///
427/// `RcConsumer` has neither Arc's atomic operation overhead nor
428/// RefCell's runtime borrow checking overhead, making it the most performant of
429/// the three non-mutating consumers.
430///
431/// # Examples
432///
433/// ```rust
434/// use qubit_function::{Consumer, RcConsumer};
435///
436/// let consumer = RcConsumer::new(|x: &i32| {
437///     println!("Observed: {}", x);
438/// });
439/// let clone = consumer.clone();
440///
441/// consumer.accept(&5);
442/// clone.accept(&10);
443/// ```
444///
445/// # Author
446///
447/// Haixing Hu
448pub struct RcConsumer<T> {
449    function: Rc<dyn Fn(&T)>,
450    name: Option<String>,
451}
452
453impl<T> RcConsumer<T> {
454    // Generates: new(), new_with_name(), name(), set_name(), noop()
455    impl_consumer_common_methods!(RcConsumer<T>, (Fn(&T) + 'static), |f| Rc::new(f));
456
457    // Generates: when() and and_then() methods that borrow &self (Rc can clone)
458    impl_shared_consumer_methods!(
459        RcConsumer<T>,
460        RcConditionalConsumer,
461        into_rc,
462        Consumer,
463        'static
464    );
465}
466
467impl<T> Consumer<T> for RcConsumer<T> {
468    fn accept(&self, value: &T) {
469        (self.function)(value)
470    }
471
472    // Use macro to implement conversion methods
473    impl_rc_conversions!(
474        RcConsumer<T>,
475        BoxConsumer,
476        BoxConsumerOnce,
477        Fn(t: &T)
478    );
479}
480
481// Use macro to generate Clone implementation
482impl_consumer_clone!(RcConsumer<T>);
483
484// Use macro to generate Debug and Display implementations
485impl_consumer_debug_display!(RcConsumer<T>);
486
487// ============================================================================
488// 4. ArcConsumer - Thread-safe Shared Ownership Implementation
489// ============================================================================
490
491/// ArcConsumer struct
492///
493/// Non-mutating consumer implementation based on `Arc<dyn Fn(&T) + Send + Sync>`,
494/// for thread-safe shared ownership scenarios. The wrapper does not need
495/// `Mutex` because it only invokes a shared `Fn`.
496///
497/// # Features
498///
499/// - **Shared Ownership**: Cloneable through `Arc`, allows multiple owners
500/// - **Thread Safe**: Implements `Send + Sync`, can be safely used concurrently
501/// - **Lock-free Wrapper**: No Mutex protection needed by the wrapper
502/// - **Non-consuming API**: `and_then` borrows `&self`, original object remains
503///   usable
504///
505/// # Use Cases
506///
507/// Choose `ArcConsumer` when:
508/// - Need to share non-mutating consumer across multiple threads
509/// - Pure observation operations, such as logging, monitoring, notifications
510/// - Need high-concurrency reads with no lock overhead
511///
512/// # Performance Advantages
513///
514/// Compared to `ArcStatefulConsumer`, `ArcConsumer` has no Mutex lock overhead,
515/// performing better in high-concurrency observation scenarios.
516///
517/// # Examples
518///
519/// ```rust
520/// use qubit_function::{Consumer, ArcConsumer};
521///
522/// let consumer = ArcConsumer::new(|x: &i32| {
523///     println!("Observed: {}", x);
524/// });
525/// let clone = consumer.clone();
526///
527/// consumer.accept(&5);
528/// clone.accept(&10);
529/// ```
530///
531/// # Author
532///
533/// Haixing Hu
534pub struct ArcConsumer<T> {
535    function: Arc<dyn Fn(&T) + Send + Sync>,
536    name: Option<String>,
537}
538
539impl<T> ArcConsumer<T> {
540    // Generates: new(), new_with_name(), name(), set_name(), noop()
541    impl_consumer_common_methods!(ArcConsumer<T>, (Fn(&T) + Send + Sync + 'static), |f| {
542        Arc::new(f)
543    });
544
545    // Generates: when() and and_then() methods that borrow &self (Arc can clone)
546    impl_shared_consumer_methods!(
547        ArcConsumer<T>,
548        ArcConditionalConsumer,
549        into_arc,
550        Consumer,
551        Send + Sync + 'static
552    );
553}
554
555impl<T> Consumer<T> for ArcConsumer<T> {
556    fn accept(&self, value: &T) {
557        (self.function)(value)
558    }
559
560    // Use macro to implement conversion methods
561    impl_arc_conversions!(
562        ArcConsumer<T>,
563        BoxConsumer,
564        RcConsumer,
565        BoxConsumerOnce,
566        Fn(t: &T)
567    );
568}
569
570// Use macro to generate Clone implementation
571impl_consumer_clone!(ArcConsumer<T>);
572
573// Use macro to generate Debug and Display implementations
574impl_consumer_debug_display!(ArcConsumer<T>);
575
576// ============================================================================
577// 5. Implement Consumer trait for closures
578// ============================================================================
579
580// Implement Consumer for all Fn(&T)
581impl_closure_trait!(
582    Consumer<T>,
583    accept,
584    BoxConsumerOnce,
585    Fn(value: &T)
586);
587
588// ============================================================================
589// 6. Provide extension methods for closures
590// ============================================================================
591
592/// Extension trait providing non-mutating consumer composition methods for closures
593///
594/// Provides `and_then` and other composition methods for all closures
595/// implementing `Fn(&T)`, allowing closures to directly chain methods without
596/// explicit wrapper types.
597///
598/// # Features
599///
600/// - **Natural Syntax**: Chain operations directly on closures
601/// - **Returns BoxConsumer**: Combined results can continue chaining
602/// - **Zero Cost**: No overhead when composing closures
603/// - **Auto-implementation**: All `Fn(&T)` closures automatically get these
604///   methods
605///
606/// # Examples
607///
608/// ```rust
609/// use qubit_function::{Consumer, FnConsumerOps};
610///
611/// let chained = (|x: &i32| {
612///     println!("First: {}", x);
613/// }).and_then(|x: &i32| {
614///     println!("Second: {}", x);
615/// });
616/// chained.accept(&5);
617/// ```
618///
619/// # Author
620///
621/// Haixing Hu
622pub trait FnConsumerOps<T>: Fn(&T) + Sized {
623    /// Sequentially chain another non-mutating consumer
624    ///
625    /// Returns a new consumer that executes the current operation first, then the
626    /// next operation. Consumes the current closure and returns
627    /// `BoxConsumer<T>`.
628    ///
629    /// # Type Parameters
630    ///
631    /// * `C` - Type of the next consumer
632    ///
633    /// # Parameters
634    ///
635    /// * `next` - Consumer to execute after the current operation
636    ///
637    /// # Returns
638    ///
639    /// Returns a combined `BoxConsumer<T>`
640    ///
641    /// # Examples
642    ///
643    /// ```rust
644    /// use qubit_function::{Consumer, FnConsumerOps};
645    ///
646    /// let chained = (|x: &i32| {
647    ///     println!("First: {}", x);
648    /// }).and_then(|x: &i32| {
649    ///     println!("Second: {}", x);
650    /// }).and_then(|x: &i32| println!("Third: {}", x));
651    ///
652    /// chained.accept(&5);
653    /// ```
654    fn and_then<C>(self, next: C) -> BoxConsumer<T>
655    where
656        Self: 'static,
657        C: Consumer<T> + 'static,
658        T: 'static,
659    {
660        let first = self;
661        let second = next;
662        BoxConsumer::new(move |t| {
663            first(t);
664            second.accept(t);
665        })
666    }
667}
668
669/// Implement FnConsumerOps for all closure types
670impl<T, F> FnConsumerOps<T> for F where F: Fn(&T) {}
671
672// ============================================================================
673// 7. BoxConditionalConsumer - Box-based Conditional Consumer
674// ============================================================================
675
676/// BoxConditionalConsumer struct
677///
678/// A conditional non-mutating consumer that only executes when a predicate is satisfied.
679/// Uses `BoxConsumer` and `BoxPredicate` for single ownership semantics.
680///
681/// This type is typically created by calling `BoxConsumer::when()` and is
682/// designed to work with the `or_else()` method to create if-then-else logic.
683///
684/// # Features
685///
686/// - **Single Ownership**: Not cloneable, consumes `self` on use
687/// - **Conditional Execution**: Only consumes when predicate returns `true`
688/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
689/// - **Implements Consumer**: Can be used anywhere a `Consumer` is expected
690/// - **Non-mutating**: Neither modifies itself nor input values
691///
692/// # Examples
693///
694/// ## Basic Conditional Execution
695///
696/// ```rust
697/// use qubit_function::{Consumer, BoxConsumer};
698///
699/// let consumer = BoxConsumer::new(|x: &i32| {
700///     println!("Positive: {}", x);
701/// });
702/// let conditional = consumer.when(|x: &i32| *x > 0);
703///
704/// conditional.accept(&5);  // Prints: Positive: 5
705/// conditional.accept(&-5); // Does nothing
706/// ```
707///
708/// ## With or_else Branch
709///
710/// ```rust
711/// use qubit_function::{Consumer, BoxConsumer};
712///
713/// let consumer = BoxConsumer::new(|x: &i32| {
714///     println!("Positive: {}", x);
715/// })
716/// .when(|x: &i32| *x > 0)
717/// .or_else(|x: &i32| {
718///     println!("Non-positive: {}", x);
719/// });
720///
721/// consumer.accept(&5);  // Prints: Positive: 5
722/// consumer.accept(&-5); // Prints: Non-positive: -5
723/// ```
724///
725/// # Author
726///
727/// Haixing Hu
728pub struct BoxConditionalConsumer<T> {
729    consumer: BoxConsumer<T>,
730    predicate: BoxPredicate<T>,
731}
732
733// Use macro to generate conditional consumer implementations
734impl_box_conditional_consumer!(BoxConditionalConsumer<T>, BoxConsumer, Consumer);
735
736// Consumer trait implementation
737impl<T> Consumer<T> for BoxConditionalConsumer<T> {
738    fn accept(&self, value: &T) {
739        if self.predicate.test(value) {
740            self.consumer.accept(value);
741        }
742    }
743
744    // Generates: into_box(), into_rc(), into_fn()
745    impl_conditional_consumer_conversions!(BoxConsumer<T>, RcConsumer, Fn);
746}
747
748// Use macro to generate Debug and Display implementations
749impl_conditional_consumer_debug_display!(BoxConditionalConsumer<T>);
750
751// ============================================================================
752// 8. RcConditionalConsumer - Rc-based Conditional Consumer
753// ============================================================================
754
755/// RcConditionalConsumer struct
756///
757/// A conditional non-mutating consumer that only executes when a predicate is satisfied.
758/// Uses `RcConsumer` and `RcPredicate` for single-threaded shared ownership semantics.
759///
760/// This type is typically created by calling `RcConsumer::when()` and is
761/// designed to work with the `or_else()` method to create if-then-else logic.
762///
763/// # Features
764///
765/// - **Shared Ownership**: Cloneable through `Rc`, allows multiple owners
766/// - **Single-threaded**: Not thread-safe, cannot be sent across threads
767/// - **Conditional Execution**: Only consumes when predicate returns `true`
768/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
769/// - **Implements Consumer**: Can be used anywhere a `Consumer` is expected
770/// - **Non-mutating**: Neither modifies itself nor input values
771///
772/// # Examples
773///
774/// ## Basic Conditional Execution
775///
776/// ```rust
777/// use qubit_function::{Consumer, RcConsumer};
778///
779/// let consumer = RcConsumer::new(|x: &i32| {
780///     println!("Positive: {}", x);
781/// });
782/// let conditional = consumer.when(|x: &i32| *x > 0);
783///
784/// conditional.accept(&5);  // Prints: Positive: 5
785/// conditional.accept(&-5); // Does nothing
786/// ```
787///
788/// ## With or_else Branch
789///
790/// ```rust
791/// use qubit_function::{Consumer, RcConsumer};
792///
793/// let consumer = RcConsumer::new(|x: &i32| {
794///     println!("Positive: {}", x);
795/// })
796/// .when(|x: &i32| *x > 0)
797/// .or_else(|x: &i32| {
798///     println!("Non-positive: {}", x);
799/// });
800///
801/// consumer.accept(&5);  // Prints: Positive: 5
802/// consumer.accept(&-5); // Prints: Non-positive: -5
803/// ```
804///
805/// # Author
806///
807/// Haixing Hu
808pub struct RcConditionalConsumer<T> {
809    consumer: RcConsumer<T>,
810    predicate: RcPredicate<T>,
811}
812
813// Use macro to generate conditional consumer implementations
814impl_shared_conditional_consumer!(
815    RcConditionalConsumer<T>,
816    RcConsumer,
817    Consumer,
818    into_rc,
819    'static
820);
821
822// Hand-written Consumer trait implementation
823impl<T> Consumer<T> for RcConditionalConsumer<T> {
824    fn accept(&self, value: &T) {
825        if self.predicate.test(value) {
826            self.consumer.accept(value);
827        }
828    }
829
830    // Generates: into_box(), into_rc(), into_fn()
831    impl_conditional_consumer_conversions!(BoxConsumer<T>, RcConsumer, Fn);
832}
833
834// Use macro to generate Clone implementation
835impl_conditional_consumer_clone!(RcConditionalConsumer<T>);
836
837// Use macro to generate Debug and Display implementations
838impl_conditional_consumer_debug_display!(RcConditionalConsumer<T>);
839
840// ============================================================================
841// 9. ArcConditionalConsumer - Arc-based Conditional Consumer
842// ============================================================================
843
844/// ArcConditionalConsumer struct
845///
846/// A conditional non-mutating consumer that only executes when a predicate is satisfied.
847/// Uses `ArcConsumer` and `ArcPredicate` for thread-safe shared ownership semantics.
848///
849/// This type is typically created by calling `ArcConsumer::when()` and is
850/// designed to work with the `or_else()` method to create if-then-else logic.
851///
852/// # Features
853///
854/// - **Shared Ownership**: Cloneable through `Arc`, allows multiple owners
855/// - **Thread Safe**: Implements `Send + Sync`, can be safely used concurrently
856/// - **Conditional Execution**: Only consumes when predicate returns `true`
857/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
858/// - **Implements Consumer**: Can be used anywhere a `Consumer` is expected
859/// - **Non-mutating**: Neither modifies itself nor input values
860///
861/// # Examples
862///
863/// ## Basic Conditional Execution
864///
865/// ```rust
866/// use qubit_function::{Consumer, ArcConsumer};
867///
868/// let consumer = ArcConsumer::new(|x: &i32| {
869///     println!("Positive: {}", x);
870/// });
871/// let conditional = consumer.when(|x: &i32| *x > 0);
872///
873/// conditional.accept(&5);  // Prints: Positive: 5
874/// conditional.accept(&-5); // Does nothing
875/// ```
876///
877/// ## With or_else Branch
878///
879/// ```rust
880/// use qubit_function::{Consumer, ArcConsumer};
881///
882/// let consumer = ArcConsumer::new(|x: &i32| {
883///     println!("Positive: {}", x);
884/// })
885/// .when(|x: &i32| *x > 0)
886/// .or_else(|x: &i32| {
887///     println!("Non-positive: {}", x);
888/// });
889///
890/// consumer.accept(&5);  // Prints: Positive: 5
891/// consumer.accept(&-5); // Prints: Non-positive: -5
892/// ```
893///
894/// # Author
895///
896/// Haixing Hu
897pub struct ArcConditionalConsumer<T> {
898    consumer: ArcConsumer<T>,
899    predicate: ArcPredicate<T>,
900}
901
902// Use macro to generate conditional consumer implementations
903impl_shared_conditional_consumer!(
904    ArcConditionalConsumer<T>,
905    ArcConsumer,
906    Consumer,
907    into_arc,
908    Send + Sync + 'static
909);
910
911// Hand-written Consumer trait implementation
912impl<T> Consumer<T> for ArcConditionalConsumer<T> {
913    fn accept(&self, value: &T) {
914        if self.predicate.test(value) {
915            self.consumer.accept(value);
916        }
917    }
918
919    // Generates: into_box(), into_rc(), into_fn()
920    impl_conditional_consumer_conversions!(BoxConsumer<T>, RcConsumer, Fn);
921}
922
923// Use macro to generate Clone implementation
924impl_conditional_consumer_clone!(ArcConditionalConsumer<T>);
925
926// Use macro to generate Debug and Display implementations
927impl_conditional_consumer_debug_display!(ArcConditionalConsumer<T>);