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