Skip to main content

qubit_function/consumers/
bi_consumer.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit 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 qubit_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 qubit_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 qubit_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    {
233        move |t, u| self.accept(t, u)
234    }
235
236    /// Convert to BiConsumerOnce
237    ///
238    /// **⚠️ Consumes `self`**: The original consumer will be unavailable after calling this method.
239    ///
240    /// Converts a reusable readonly bi-consumer to a one-time consumer that consumes itself on use.
241    /// This enables passing `BiConsumer` to functions that require `BiConsumerOnce`.
242    ///
243    /// # Returns
244    ///
245    /// Returns a `BoxBiConsumerOnce<T, U>`
246    fn into_once(self) -> BoxBiConsumerOnce<T, U>
247    where
248        Self: Sized + 'static,
249        T: 'static,
250        U: 'static,
251    {
252        BoxBiConsumerOnce::new(move |t, u| self.accept(t, u))
253    }
254
255    /// Converts to BoxBiConsumer (without consuming self)
256    ///
257    /// Creates a new `BoxBiConsumer` by cloning the current consumer.
258    /// The original consumer remains usable after this call.
259    ///
260    /// # Returns
261    ///
262    /// Returns a new `BoxBiConsumer<T, U>`
263    ///
264    /// # Examples
265    ///
266    /// ```rust
267    /// use qubit_function::{BiConsumer, RcBiConsumer};
268    ///
269    /// let consumer = RcBiConsumer::new(|x: &i32, y: &i32| {
270    ///     println!("Sum: {}", x + y);
271    /// });
272    /// let box_consumer = consumer.to_box();
273    /// box_consumer.accept(&5, &3);
274    /// // Original consumer still usable
275    /// consumer.accept(&10, &20);
276    /// ```
277    fn to_box(&self) -> BoxBiConsumer<T, U>
278    where
279        Self: Clone + 'static,
280        T: 'static,
281        U: 'static,
282    {
283        self.clone().into_box()
284    }
285
286    /// Converts to RcBiConsumer (without consuming self)
287    ///
288    /// Creates a new `RcBiConsumer` by cloning the current consumer.
289    /// The original consumer remains usable after this call.
290    ///
291    /// # Returns
292    ///
293    /// Returns a new `RcBiConsumer<T, U>`
294    ///
295    /// # Examples
296    ///
297    /// ```rust
298    /// use qubit_function::{BiConsumer, ArcBiConsumer};
299    ///
300    /// let consumer = ArcBiConsumer::new(|x: &i32, y: &i32| {
301    ///     println!("Sum: {}", x + y);
302    /// });
303    /// let rc_consumer = consumer.to_rc();
304    /// rc_consumer.accept(&5, &3);
305    /// // Original consumer still usable
306    /// consumer.accept(&10, &20);
307    /// ```
308    fn to_rc(&self) -> RcBiConsumer<T, U>
309    where
310        Self: Clone + 'static,
311        T: 'static,
312        U: 'static,
313    {
314        self.clone().into_rc()
315    }
316
317    /// Converts to ArcBiConsumer (without consuming self)
318    ///
319    /// Creates a new `ArcBiConsumer` by cloning the current consumer.
320    /// The original consumer remains usable after this call.
321    ///
322    /// # Returns
323    ///
324    /// Returns a new `ArcBiConsumer<T, U>`
325    ///
326    /// # Examples
327    ///
328    /// ```rust
329    /// use qubit_function::{BiConsumer, RcBiConsumer};
330    ///
331    /// let consumer = RcBiConsumer::new(|x: &i32, y: &i32| {
332    ///     println!("Sum: {}", x + y);
333    /// });
334    /// // Note: This will only compile if the closure is Send + Sync
335    /// // For demonstration, we use a simple closure
336    /// let arc_consumer = consumer.to_arc();
337    /// arc_consumer.accept(&5, &3);
338    /// ```
339    fn to_arc(&self) -> ArcBiConsumer<T, U>
340    where
341        Self: Clone + Send + Sync + 'static,
342        T: 'static,
343        U: 'static,
344    {
345        self.clone().into_arc()
346    }
347
348    /// Converts to a closure (without consuming self)
349    ///
350    /// Creates a new closure by cloning the current consumer.
351    /// The original consumer remains usable after this call.
352    ///
353    /// # Returns
354    ///
355    /// Returns a closure implementing `Fn(&T, &U)`
356    ///
357    /// # Examples
358    ///
359    /// ```rust
360    /// use qubit_function::{BiConsumer, RcBiConsumer};
361    ///
362    /// let consumer = RcBiConsumer::new(|x: &i32, y: &i32| {
363    ///     println!("Sum: {}", x + y);
364    /// });
365    /// let func = consumer.to_fn();
366    /// func(&5, &3);
367    /// // Original consumer still usable
368    /// consumer.accept(&10, &20);
369    /// ```
370    fn to_fn(&self) -> impl Fn(&T, &U)
371    where
372        Self: Clone + 'static,
373    {
374        self.clone().into_fn()
375    }
376
377    /// Convert to BiConsumerOnce without consuming self
378    ///
379    /// **⚠️ Requires Clone**: This method requires `Self` to implement `Clone`.
380    /// Clones the current consumer and converts the clone to a one-time consumer.
381    ///
382    /// # Returns
383    ///
384    /// Returns a `BoxBiConsumerOnce<T, U>`
385    fn to_once(&self) -> BoxBiConsumerOnce<T, U>
386    where
387        Self: Clone + 'static,
388        T: 'static,
389        U: 'static,
390    {
391        self.clone().into_once()
392    }
393}
394
395// =======================================================================
396// 2. BoxBiConsumer - Single Ownership Implementation
397// =======================================================================
398
399/// BoxBiConsumer struct
400///
401/// A readonly bi-consumer implementation based on `Box<dyn Fn(&T, &U)>`
402/// for single ownership scenarios.
403///
404/// # Features
405///
406/// - **Single Ownership**: Not cloneable, ownership moves on use
407/// - **Zero Overhead**: No reference counting or locking
408/// - **Fully Immutable**: Neither modifies itself nor input values
409/// - **No Interior Mutability**: No need for Mutex or RefCell
410///
411/// # Use Cases
412///
413/// Choose `BoxBiConsumer` when:
414/// - The readonly bi-consumer is used only once or in a linear flow
415/// - No need to share the consumer across contexts
416/// - Pure observation operations like logging
417///
418/// # Examples
419///
420/// ```rust
421/// use qubit_function::{BiConsumer, BoxBiConsumer};
422///
423/// let consumer = BoxBiConsumer::new(|x: &i32, y: &i32| {
424///     println!("Sum: {}", x + y);
425/// });
426/// consumer.accept(&5, &3);
427/// ```
428///
429/// # Author
430///
431/// Haixing Hu
432pub struct BoxBiConsumer<T, U> {
433    function: Box<BiConsumerFn<T, U>>,
434    name: Option<String>,
435}
436
437impl<T, U> BoxBiConsumer<T, U> {
438    // Generates: new(), new_with_name(), name(), set_name(), noop()
439    impl_consumer_common_methods!(
440        BoxBiConsumer<T, U>,
441        (Fn(&T, &U) + 'static),
442        |f| Box::new(f)
443    );
444
445    // Generates: when() and and_then() methods that consume self
446    impl_box_consumer_methods!(
447        BoxBiConsumer<T, U>,
448        BoxConditionalBiConsumer,
449        BiConsumer
450    );
451}
452
453impl<T, U> BiConsumer<T, U> for BoxBiConsumer<T, U> {
454    fn accept(&self, first: &T, second: &U) {
455        (self.function)(first, second)
456    }
457
458    // Generates: into_box(), into_rc(), into_fn(), into_once()
459    impl_box_conversions!(
460        BoxBiConsumer<T, U>,
461        RcBiConsumer,
462        Fn(&T, &U),
463        BoxBiConsumerOnce
464    );
465}
466
467// Use macro to generate Debug and Display implementations
468impl_consumer_debug_display!(BoxBiConsumer<T, U>);
469
470// =======================================================================
471// 3. RcBiConsumer - Single-Threaded Shared Ownership
472// =======================================================================
473
474/// RcBiConsumer struct
475///
476/// A readonly bi-consumer implementation based on `Rc<dyn Fn(&T, &U)>`
477/// for single-threaded shared ownership scenarios. No need for RefCell
478/// because operations are readonly.
479///
480/// # Features
481///
482/// - **Shared Ownership**: Cloneable via `Rc`, multiple owners allowed
483/// - **Single-Threaded**: Not thread-safe, cannot send across threads
484/// - **No Interior Mutability Overhead**: No need for RefCell because
485///   readonly
486/// - **Non-Consuming API**: `and_then` borrows `&self`, original remains
487///   usable
488///
489/// # Use Cases
490///
491/// Choose `RcBiConsumer` when:
492/// - Need to share readonly bi-consumer within a single thread
493/// - Pure observation operations, performance critical
494/// - Single-threaded UI framework event handling
495///
496/// # Performance Advantages
497///
498/// `RcBiConsumer` has neither Arc's atomic operation overhead nor
499/// RefCell's runtime borrow checking overhead, making it the best
500/// performing among the three readonly bi-consumer types.
501///
502/// # Examples
503///
504/// ```rust
505/// use qubit_function::{BiConsumer, RcBiConsumer};
506///
507/// let consumer = RcBiConsumer::new(|x: &i32, y: &i32| {
508///     println!("Sum: {}", x + y);
509/// });
510/// let clone = consumer.clone();
511///
512/// consumer.accept(&5, &3);
513/// clone.accept(&10, &20);
514/// ```
515///
516/// # Author
517///
518/// Haixing Hu
519pub struct RcBiConsumer<T, U> {
520    function: Rc<BiConsumerFn<T, U>>,
521    name: Option<String>,
522}
523
524impl<T, U> RcBiConsumer<T, U> {
525    // Generates: new(), new_with_name(), name(), set_name(), noop()
526    impl_consumer_common_methods!(
527        RcBiConsumer<T, U>,
528        (Fn(&T, &U) + 'static),
529        |f| Rc::new(f)
530    );
531
532    // Generates: when() and and_then() methods that borrow &self (Rc can clone)
533    impl_shared_consumer_methods!(
534        RcBiConsumer<T, U>,
535        RcConditionalBiConsumer,
536        into_rc,
537        BiConsumer,
538        'static
539    );
540}
541
542impl<T, U> BiConsumer<T, U> for RcBiConsumer<T, U> {
543    fn accept(&self, first: &T, second: &U) {
544        (self.function)(first, second)
545    }
546
547    // Use macro to implement conversion methods
548    impl_rc_conversions!(
549        RcBiConsumer<T, U>,
550        BoxBiConsumer,
551        BoxBiConsumerOnce,
552        Fn(t: &T, u: &U)
553    );
554}
555
556// Use macro to generate Clone implementation
557impl_consumer_clone!(RcBiConsumer<T, U>);
558
559// Use macro to generate Debug and Display implementations
560impl_consumer_debug_display!(RcBiConsumer<T, U>);
561
562// =======================================================================
563// 4. ArcBiConsumer - Thread-Safe Shared Ownership
564// =======================================================================
565
566/// ArcBiConsumer struct
567///
568/// A readonly bi-consumer implementation based on
569/// `Arc<dyn Fn(&T, &U) + Send + Sync>` for thread-safe shared ownership
570/// scenarios. No need for Mutex because operations are readonly.
571///
572/// # Features
573///
574/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
575/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
576/// - **No Locks**: Because readonly, no need for Mutex protection
577/// - **Non-Consuming API**: `and_then` borrows `&self`, original remains
578///   usable
579///
580/// # Use Cases
581///
582/// Choose `ArcBiConsumer` when:
583/// - Need to share readonly bi-consumer across multiple threads
584/// - Pure observation operations like logging, monitoring, notifications
585/// - Need high-concurrency reads without lock overhead
586///
587/// # Performance Advantages
588///
589/// Compared to `ArcBiConsumer`, `ArcBiConsumer` has no Mutex
590/// locking overhead, resulting in better performance in high-concurrency
591/// scenarios.
592///
593/// # Examples
594///
595/// ```rust
596/// use qubit_function::{BiConsumer, ArcBiConsumer};
597///
598/// let consumer = ArcBiConsumer::new(|x: &i32, y: &i32| {
599///     println!("Sum: {}", x + y);
600/// });
601/// let clone = consumer.clone();
602///
603/// consumer.accept(&5, &3);
604/// clone.accept(&10, &20);
605/// ```
606///
607/// # Author
608///
609/// Haixing Hu
610pub struct ArcBiConsumer<T, U> {
611    function: Arc<ThreadSafeBiConsumerFn<T, U>>,
612    name: Option<String>,
613}
614
615impl<T, U> ArcBiConsumer<T, U> {
616    // Generates: new(), new_with_name(), name(), set_name(), noop()
617    impl_consumer_common_methods!(
618        ArcBiConsumer<T, U>,
619        (Fn(&T, &U) + Send + Sync + 'static),
620        |f| Arc::new(f)
621    );
622
623    // Generates: when() and and_then() methods that borrow &self (Arc can clone)
624    impl_shared_consumer_methods!(
625        ArcBiConsumer<T, U>,
626        ArcConditionalBiConsumer,
627        into_arc,
628        BiConsumer,
629        Send + Sync + 'static
630    );
631}
632
633impl<T, U> BiConsumer<T, U> for ArcBiConsumer<T, U> {
634    fn accept(&self, first: &T, second: &U) {
635        (self.function)(first, second)
636    }
637
638    // Use macro to implement conversion methods
639    impl_arc_conversions!(
640        ArcBiConsumer<T, U>,
641        BoxBiConsumer,
642        RcBiConsumer,
643        BoxBiConsumerOnce,
644        Fn(t: &T, u: &U)
645    );
646}
647
648// Use macro to generate Clone implementation
649impl_consumer_clone!(ArcBiConsumer<T, U>);
650
651// Use macro to generate Debug and Display implementations
652impl_consumer_debug_display!(ArcBiConsumer<T, U>);
653
654// =======================================================================
655// 5. Implement BiConsumer trait for closures
656// =======================================================================
657
658// Implements BiConsumer for all Fn(&T, &U)
659impl_closure_trait!(
660    BiConsumer<T, U>,
661    accept,
662    BoxBiConsumerOnce,
663    Fn(first: &T, second: &U)
664);
665
666// =======================================================================
667// 6. Provide extension methods for closures
668// =======================================================================
669
670/// Extension trait providing readonly bi-consumer composition methods for
671/// closures
672///
673/// Provides `and_then` and other composition methods for all closures
674/// implementing `Fn(&T, &U)`, enabling direct method chaining on closures
675/// without explicit wrapper types.
676///
677/// # Features
678///
679/// - **Natural Syntax**: Chain operations directly on closures
680/// - **Returns BoxBiConsumer**: Composition results can be
681///   further chained
682/// - **Zero Cost**: No overhead when composing closures
683/// - **Automatic Implementation**: All `Fn(&T, &U)` closures get these
684///   methods automatically
685///
686/// # Examples
687///
688/// ```rust
689/// use qubit_function::{BiConsumer, FnBiConsumerOps};
690///
691/// let chained = (|x: &i32, y: &i32| {
692///     println!("First: {}, {}", x, y);
693/// }).and_then(|x: &i32, y: &i32| {
694///     println!("Second: sum = {}", x + y);
695/// });
696/// chained.accept(&5, &3);
697/// ```
698///
699/// # Author
700///
701/// Haixing Hu
702pub trait FnBiConsumerOps<T, U>: Fn(&T, &U) + Sized {
703    /// Chains another readonly bi-consumer in sequence
704    ///
705    /// Returns a new consumer executing the current operation first, then
706    /// the next operation. Consumes the current closure and returns
707    /// `BoxBiConsumer<T, U>`.
708    ///
709    /// # Type Parameters
710    ///
711    /// * `C` - The type of the next consumer
712    ///
713    /// # Parameters
714    ///
715    /// * `next` - The consumer to execute after the current operation
716    ///
717    /// # Returns
718    ///
719    /// Returns the composed `BoxBiConsumer<T, U>`
720    ///
721    /// # Examples
722    ///
723    /// ```rust
724    /// use qubit_function::{BiConsumer, FnBiConsumerOps};
725    ///
726    /// let chained = (|x: &i32, y: &i32| {
727    ///     println!("First: {}, {}", x, y);
728    /// }).and_then(|x: &i32, y: &i32| {
729    ///     println!("Second: sum = {}", x + y);
730    /// }).and_then(|x: &i32, y: &i32| {
731    ///     println!("Third: product = {}", x * y);
732    /// });
733    ///
734    /// chained.accept(&5, &3);
735    /// ```
736    fn and_then<C>(self, next: C) -> BoxBiConsumer<T, U>
737    where
738        Self: 'static,
739        C: BiConsumer<T, U> + 'static,
740        T: 'static,
741        U: 'static,
742    {
743        let first = self;
744        let second = next;
745        BoxBiConsumer::new(move |t, u| {
746            first(t, u);
747            second.accept(t, u);
748        })
749    }
750}
751
752/// Implements FnBiConsumerOps for all closure types
753impl<T, U, F> FnBiConsumerOps<T, U> for F where F: Fn(&T, &U) {}
754
755// =======================================================================
756// 7. BoxConditionalBiConsumer - Box-based Conditional BiConsumer
757// =======================================================================
758
759/// BoxConditionalBiConsumer struct
760///
761/// A conditional readonly bi-consumer that only executes when a predicate is satisfied.
762/// Uses `BoxBiConsumer` and `BoxBiPredicate` for single ownership semantics.
763///
764/// This type is typically created by calling `BoxBiConsumer::when()` and is
765/// designed to work with the `or_else()` method to create if-then-else logic.
766///
767/// # Features
768///
769/// - **Single Ownership**: Not cloneable, consumes `self` on use
770/// - **Conditional Execution**: Only consumes when predicate returns `true`
771/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
772/// - **Implements BiConsumer**: Can be used anywhere a `BiConsumer` is expected
773/// - **Readonly**: Neither modifies itself nor input values
774///
775/// # Examples
776///
777/// ## Basic Conditional Execution
778///
779/// ```rust
780/// use qubit_function::{BiConsumer, BoxBiConsumer};
781///
782/// let consumer = BoxBiConsumer::new(|x: &i32, y: &i32| {
783///     println!("Both positive: {} + {} = {}", x, y, x + y);
784/// });
785/// let conditional = consumer.when(|x: &i32, y: &i32| *x > 0 && *y > 0);
786///
787/// conditional.accept(&5, &3);  // Prints: Both positive: 5 + 3 = 8
788/// conditional.accept(&-5, &3); // Does nothing
789/// ```
790///
791/// ## With or_else Branch
792///
793/// ```rust
794/// use qubit_function::{BiConsumer, BoxBiConsumer};
795///
796/// let consumer = BoxBiConsumer::new(|x: &i32, y: &i32| {
797///     println!("Both positive: {} + {} = {}", x, y, x + y);
798/// })
799/// .when(|x: &i32, y: &i32| *x > 0 && *y > 0)
800/// .or_else(|x: &i32, y: &i32| {
801///     println!("Not both positive: {} and {}", x, y);
802/// });
803///
804/// consumer.accept(&5, &3);  // Prints: Both positive: 5 + 3 = 8
805/// consumer.accept(&-5, &3); // Prints: Not both positive: -5 and 3
806/// ```
807///
808/// # Author
809///
810/// Haixing Hu
811pub struct BoxConditionalBiConsumer<T, U> {
812    consumer: BoxBiConsumer<T, U>,
813    predicate: BoxBiPredicate<T, U>,
814}
815
816// Use macro to generate conditional bi-consumer implementations
817impl_box_conditional_consumer!(
818    BoxConditionalBiConsumer<T, U>,
819    BoxBiConsumer,
820    BiConsumer
821);
822
823// Hand-written BiConsumer trait implementation
824impl<T, U> BiConsumer<T, U> for BoxConditionalBiConsumer<T, U> {
825    fn accept(&self, first: &T, second: &U) {
826        if self.predicate.test(first, second) {
827            self.consumer.accept(first, second);
828        }
829    }
830
831    // Generates: into_box(), into_rc(), into_fn()
832    impl_conditional_consumer_conversions!(
833        BoxBiConsumer<T, U>,
834        RcBiConsumer,
835        Fn
836    );
837}
838
839// Use macro to generate Debug and Display implementations
840impl_conditional_consumer_debug_display!(BoxConditionalBiConsumer<T, U>);
841
842// =======================================================================
843// 8. ArcConditionalBiConsumer - Arc-based Conditional BiConsumer
844// =======================================================================
845
846/// ArcConditionalBiConsumer struct
847///
848/// A conditional bi-consumer that wraps an `ArcBiConsumer` and only executes
849/// when a predicate is satisfied. Based on `Arc` for thread-safe shared ownership.
850///
851/// # Features
852///
853/// - **Shared Ownership**: Cloneable through `Arc`, allows multiple owners
854/// - **Thread Safe**: Implements `Send + Sync`, can be safely used concurrently
855/// - **Conditional Execution**: Only consumes when predicate returns `true`
856/// - **Implements BiConsumer**: Can be used anywhere a `BiConsumer` is expected
857/// - **Readonly**: Neither modifies itself nor input values
858///
859/// # Author
860///
861/// Haixing Hu
862pub struct ArcConditionalBiConsumer<T, U> {
863    consumer: ArcBiConsumer<T, U>,
864    predicate: ArcBiPredicate<T, U>,
865}
866
867// Use macro to generate conditional bi-consumer implementations
868impl_shared_conditional_consumer!(
869    ArcConditionalBiConsumer<T, U>,
870    ArcBiConsumer,
871    BiConsumer,
872    into_arc,
873    Send + Sync + 'static
874);
875
876// Hand-written BiConsumer trait implementation
877impl<T, U> BiConsumer<T, U> for ArcConditionalBiConsumer<T, U> {
878    fn accept(&self, first: &T, second: &U) {
879        if self.predicate.test(first, second) {
880            self.consumer.accept(first, second);
881        }
882    }
883
884    // Generates: into_box(), into_rc(), into_fn()
885    impl_conditional_consumer_conversions!(
886        BoxBiConsumer<T, U>,
887        RcBiConsumer,
888        Fn
889    );
890}
891
892// Use macro to generate Clone implementation
893impl_conditional_consumer_clone!(ArcConditionalBiConsumer<T, U>);
894
895// Use macro to generate Debug and Display implementations
896impl_conditional_consumer_debug_display!(ArcConditionalBiConsumer<T, U>);
897
898// =======================================================================
899// 9. RcConditionalBiConsumer - Rc-based Conditional BiConsumer
900// =======================================================================
901
902/// RcConditionalBiConsumer struct
903///
904/// A conditional bi-consumer that wraps an `RcBiConsumer` and only executes
905/// when a predicate is satisfied. Based on `Rc` for single-threaded shared ownership.
906///
907/// # Features
908///
909/// - **Shared Ownership**: Cloneable through `Rc`, allows multiple owners
910/// - **Single-Threaded**: Not thread-safe, more efficient than Arc in single-threaded contexts
911/// - **Conditional Execution**: Only consumes when predicate returns `true`
912/// - **Implements BiConsumer**: Can be used anywhere a `BiConsumer` is expected
913/// - **Readonly**: Neither modifies itself nor input values
914///
915/// # Author
916///
917/// Haixing Hu
918pub struct RcConditionalBiConsumer<T, U> {
919    consumer: RcBiConsumer<T, U>,
920    predicate: RcBiPredicate<T, U>,
921}
922
923// Use macro to generate conditional bi-consumer implementations
924impl_shared_conditional_consumer!(
925    RcConditionalBiConsumer<T, U>,
926    RcBiConsumer,
927    BiConsumer,
928    into_rc,
929    'static
930);
931
932// Hand-written BiConsumer trait implementation
933impl<T, U> BiConsumer<T, U> for RcConditionalBiConsumer<T, U> {
934    fn accept(&self, first: &T, second: &U) {
935        if self.predicate.test(first, second) {
936            self.consumer.accept(first, second);
937        }
938    }
939
940    // Generates: into_box(), into_rc(), into_fn()
941    impl_conditional_consumer_conversions!(
942        BoxBiConsumer<T, U>,
943        RcBiConsumer,
944        Fn
945    );
946}
947
948// Use macro to generate Clone implementation
949impl_conditional_consumer_clone!(RcConditionalBiConsumer<T, U>);
950
951// Use macro to generate Debug and Display implementations
952impl_conditional_consumer_debug_display!(RcConditionalBiConsumer<T, U>);