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