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>);