prism3_function/consumers/
bi_consumer.rs

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