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