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