qubit_function/consumers/stateful_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 bi-consumer interface implementations for operations accepting
12//! two input parameters without returning a result.
13//!
14//! It is similar to the `FnMut(&T, &U)` trait in the standard library.
15//!
16//! This module provides a unified `BiConsumer` trait and three concrete
17//! implementations based on different ownership models:
18//!
19//! - **`BoxStatefulBiConsumer<T, U>`**: Box-based single ownership for one-time use
20//! - **`ArcStatefulBiConsumer<T, U>`**: Arc<Mutex<>>-based thread-safe shared
21//! ownership
22//! - **`RcStatefulBiConsumer<T, U>`**: Rc<RefCell<>>-based single-threaded shared
23//! ownership
24//!
25//! # Design Philosophy
26//!
27//! BiConsumer uses `FnMut(&T, &U)` semantics: can modify its own state but
28//! does NOT modify input values.
29//!
30//! Suitable for statistics, accumulation, and event processing scenarios
31//! involving two parameters.
32//!
33//! # Author
34//!
35//! Haixing Hu
36use std::cell::RefCell;
37use std::rc::Rc;
38use std::sync::Arc;
39
40use parking_lot::Mutex;
41
42use crate::consumers::{
43 bi_consumer_once::BoxBiConsumerOnce,
44 macros::{
45 impl_box_conditional_consumer,
46 impl_box_consumer_methods,
47 impl_conditional_consumer_clone,
48 impl_conditional_consumer_conversions,
49 impl_conditional_consumer_debug_display,
50 impl_consumer_clone,
51 impl_consumer_common_methods,
52 impl_consumer_debug_display,
53 impl_shared_conditional_consumer,
54 impl_shared_consumer_methods,
55 },
56};
57use crate::macros::{
58 impl_arc_conversions,
59 impl_box_conversions,
60 impl_closure_trait,
61 impl_rc_conversions,
62};
63use crate::predicates::bi_predicate::{
64 ArcBiPredicate,
65 BiPredicate,
66 BoxBiPredicate,
67 RcBiPredicate,
68};
69
70// =======================================================================
71// 1. BiConsumer Trait - Unified BiConsumer Interface
72// =======================================================================
73
74/// BiConsumer trait - Unified bi-consumer interface
75///
76/// Defines core behavior for all bi-consumer types. Similar to Java's
77/// `BiConsumer<T, U>` interface, performs operations accepting two values
78/// but returning no result (side effects only).
79///
80/// It is similar to the `FnMut(&T, &U)` trait in the standard library.
81///
82/// BiConsumer can modify its own state (e.g., accumulate, count) but
83/// should NOT modify the consumed values themselves.
84///
85/// # Automatic Implementations
86///
87/// - All closures implementing `FnMut(&T, &U)`
88/// - `BoxStatefulBiConsumer<T, U>`, `ArcStatefulBiConsumer<T, U>`, `RcStatefulBiConsumer<T, U>`
89///
90/// # Features
91///
92/// - **Unified Interface**: All bi-consumer types share the same `accept`
93/// method signature
94/// - **Automatic Implementation**: Closures automatically implement this
95/// trait with zero overhead
96/// - **Type Conversions**: Easy conversion between ownership models
97/// - **Generic Programming**: Write functions accepting any bi-consumer
98/// type
99///
100/// # Examples
101///
102/// ```rust
103/// use qubit_function::{BiConsumer, BoxStatefulBiConsumer, ArcStatefulBiConsumer};
104/// use std::sync::{Arc, Mutex};
105///
106/// fn apply_bi_consumer<C: StatefulBiConsumer<i32, i32>>(
107/// consumer: &mut C,
108/// a: &i32,
109/// b: &i32
110/// ) {
111/// consumer.accept(a, b);
112/// }
113///
114/// // Works with any bi-consumer type
115/// let log = Arc::new(Mutex::new(Vec::new()));
116/// let l = log.clone();
117/// let mut box_con = BoxStatefulBiConsumer::new(move |x: &i32, y: &i32| {
118/// l.lock().unwrap().push(*x + *y);
119/// });
120/// apply_bi_consumer(&mut box_con, &5, &3);
121/// assert_eq!(*log.lock().unwrap(), vec![8]);
122/// ```
123///
124/// # Author
125///
126/// Haixing Hu
127pub trait StatefulBiConsumer<T, U> {
128 /// Performs the consumption operation
129 ///
130 /// Executes an operation on the given two references. The operation
131 /// typically reads input values or produces side effects, but does not
132 /// modify the input values themselves. Can modify the consumer's own
133 /// state.
134 ///
135 /// # Parameters
136 ///
137 /// * `first` - Reference to the first value to consume
138 /// * `second` - Reference to the second value to consume
139 ///
140 /// # Examples
141 ///
142 /// ```rust
143 /// use qubit_function::{BiConsumer, BoxStatefulBiConsumer};
144 /// use std::sync::{Arc, Mutex};
145 ///
146 /// let log = Arc::new(Mutex::new(Vec::new()));
147 /// let l = log.clone();
148 /// let mut consumer = BoxStatefulBiConsumer::new(move |x: &i32, y: &i32| {
149 /// l.lock().unwrap().push(*x + *y);
150 /// });
151 /// consumer.accept(&5, &3);
152 /// assert_eq!(*log.lock().unwrap(), vec![8]);
153 /// ```
154 fn accept(&mut self, first: &T, second: &U);
155
156 /// Converts to BoxStatefulBiConsumer
157 ///
158 /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
159 /// calling this method.
160 ///
161 /// Converts the current bi-consumer to `BoxStatefulBiConsumer<T, U>`.
162 ///
163 /// # Ownership
164 ///
165 /// This method **consumes** the consumer (takes ownership of `self`).
166 /// After calling, the original consumer is no longer available.
167 ///
168 /// **Tip**: For cloneable consumers ([`ArcStatefulBiConsumer`],
169 /// [`RcStatefulBiConsumer`]), call `.clone()` first if you need to keep the
170 /// original.
171 ///
172 /// # Returns
173 ///
174 /// Returns the wrapped `BoxStatefulBiConsumer<T, U>`
175 ///
176 /// # Examples
177 ///
178 /// ```rust
179 /// use qubit_function::BiConsumer;
180 /// use std::sync::{Arc, Mutex};
181 ///
182 /// let log = Arc::new(Mutex::new(Vec::new()));
183 /// let l = log.clone();
184 /// let closure = move |x: &i32, y: &i32| {
185 /// l.lock().unwrap().push(*x + *y);
186 /// };
187 /// let mut box_consumer = closure.into_box();
188 /// box_consumer.accept(&5, &3);
189 /// assert_eq!(*log.lock().unwrap(), vec![8]);
190 /// ```
191 fn into_box(self) -> BoxStatefulBiConsumer<T, U>
192 where
193 Self: Sized + 'static,
194 {
195 let mut consumer = self;
196 BoxStatefulBiConsumer::new(move |t, u| consumer.accept(t, u))
197 }
198
199 /// Converts to RcStatefulBiConsumer
200 ///
201 /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
202 /// calling this method.
203 ///
204 /// # Returns
205 ///
206 /// Returns the wrapped `RcStatefulBiConsumer<T, U>`
207 fn into_rc(self) -> RcStatefulBiConsumer<T, U>
208 where
209 Self: Sized + 'static,
210 {
211 let mut consumer = self;
212 RcStatefulBiConsumer::new(move |t, u| consumer.accept(t, u))
213 }
214
215 /// Converts to ArcStatefulBiConsumer
216 ///
217 /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
218 /// calling this method.
219 ///
220 /// # Returns
221 ///
222 /// Returns the wrapped `ArcStatefulBiConsumer<T, U>`
223 fn into_arc(self) -> ArcStatefulBiConsumer<T, U>
224 where
225 Self: Sized + Send + 'static,
226 {
227 let mut consumer = self;
228 ArcStatefulBiConsumer::new(move |t, u| consumer.accept(t, u))
229 }
230
231 /// Converts bi-consumer to a closure
232 ///
233 /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
234 /// calling this method.
235 ///
236 /// Converts the bi-consumer to a closure usable with standard library
237 /// methods requiring `FnMut`.
238 ///
239 /// # Returns
240 ///
241 /// Returns a closure implementing `FnMut(&T, &U)`
242 ///
243 /// # Examples
244 ///
245 /// ```rust
246 /// use qubit_function::{BiConsumer, BoxStatefulBiConsumer};
247 /// use std::sync::{Arc, Mutex};
248 ///
249 /// let log = Arc::new(Mutex::new(Vec::new()));
250 /// let l = log.clone();
251 /// let consumer = BoxStatefulBiConsumer::new(move |x: &i32, y: &i32| {
252 /// l.lock().unwrap().push(*x + *y);
253 /// });
254 /// let mut func = consumer.into_fn();
255 /// func(&5, &3);
256 /// assert_eq!(*log.lock().unwrap(), vec![8]);
257 /// ```
258 fn into_fn(self) -> impl FnMut(&T, &U)
259 where
260 Self: Sized + 'static,
261 {
262 let mut consumer = self;
263 move |t, u| consumer.accept(t, u)
264 }
265
266 /// Convert to BiConsumerOnce
267 ///
268 /// **⚠️ Consumes `self`**: The original consumer will be unavailable after calling this method.
269 ///
270 /// Converts a reusable stateful bi-consumer to a one-time consumer that consumes itself on use.
271 /// This enables passing `StatefulBiConsumer` to functions that require `BiConsumerOnce`.
272 ///
273 /// # Returns
274 ///
275 /// Returns a `BoxBiConsumerOnce<T, U>`
276 fn into_once(self) -> BoxBiConsumerOnce<T, U>
277 where
278 Self: Sized + 'static,
279 {
280 BoxBiConsumerOnce::new(move |t, u| {
281 let mut consumer = self;
282 consumer.accept(t, u);
283 })
284 }
285
286 /// Converts to BoxStatefulBiConsumer (non-consuming)
287 ///
288 /// **⚠️ Requires Clone**: Original consumer must implement Clone.
289 ///
290 /// Converts the current bi-consumer to `BoxStatefulBiConsumer<T, U>` by cloning
291 /// it first.
292 ///
293 /// # Ownership
294 ///
295 /// This method does **not consume** the consumer. It clones the consumer
296 /// and then converts the clone to `BoxStatefulBiConsumer<T, U>`. The original
297 /// consumer remains available after calling this method.
298 ///
299 /// # Returns
300 ///
301 /// Returns the wrapped `BoxStatefulBiConsumer<T, U>` from the clone
302 ///
303 /// # Examples
304 ///
305 /// ```rust
306 /// use qubit_function::{BiConsumer, ArcStatefulBiConsumer};
307 /// use std::sync::{Arc, Mutex};
308 ///
309 /// let log = Arc::new(Mutex::new(Vec::new()));
310 /// let l = log.clone();
311 /// let consumer = ArcStatefulBiConsumer::new(move |x: &i32, y: &i32| {
312 /// l.lock().unwrap().push(*x + *y);
313 /// });
314 /// let mut box_consumer = consumer.to_box();
315 /// box_consumer.accept(&5, &3);
316 /// assert_eq!(*log.lock().unwrap(), vec![8]);
317 /// // Original consumer still usable
318 /// consumer.accept(&2, &1);
319 /// assert_eq!(*log.lock().unwrap(), vec![8, 3]);
320 /// ```
321 fn to_box(&self) -> BoxStatefulBiConsumer<T, U>
322 where
323 Self: Sized + Clone + 'static,
324 {
325 self.clone().into_box()
326 }
327
328 /// Converts to RcStatefulBiConsumer (non-consuming)
329 ///
330 /// **⚠️ Requires Clone**: Original consumer must implement Clone.
331 ///
332 /// Converts the current bi-consumer to `RcStatefulBiConsumer<T, U>` by cloning
333 /// it first.
334 ///
335 /// # Ownership
336 ///
337 /// This method does **not consume** the consumer. It clones the consumer
338 /// and then converts the clone to `RcStatefulBiConsumer<T, U>`. The original
339 /// consumer remains available after calling this method.
340 ///
341 /// # Returns
342 ///
343 /// Returns the wrapped `RcStatefulBiConsumer<T, U>` from the clone
344 ///
345 /// # Examples
346 ///
347 /// ```rust
348 /// use qubit_function::{BiConsumer, ArcStatefulBiConsumer};
349 /// use std::sync::{Arc, Mutex};
350 ///
351 /// let log = Arc::new(Mutex::new(Vec::new()));
352 /// let l = log.clone();
353 /// let consumer = ArcStatefulBiConsumer::new(move |x: &i32, y: &i32| {
354 /// l.lock().unwrap().push(*x + *y);
355 /// });
356 /// let mut rc_consumer = consumer.to_rc();
357 /// rc_consumer.accept(&5, &3);
358 /// assert_eq!(*log.lock().unwrap(), vec![8]);
359 /// // Original consumer still usable
360 /// consumer.accept(&2, &1);
361 /// assert_eq!(*log.lock().unwrap(), vec![8, 3]);
362 /// ```
363 fn to_rc(&self) -> RcStatefulBiConsumer<T, U>
364 where
365 Self: Sized + Clone + 'static,
366 {
367 self.clone().into_rc()
368 }
369
370 /// Converts to ArcStatefulBiConsumer (non-consuming)
371 ///
372 /// **⚠️ Requires Clone + Send**: Original consumer must implement Clone +
373 /// Send.
374 ///
375 /// Converts the current bi-consumer to `ArcStatefulBiConsumer<T, U>` by cloning
376 /// it first.
377 ///
378 /// # Ownership
379 ///
380 /// This method does **not consume** the consumer. It clones the consumer
381 /// and then converts the clone to `ArcStatefulBiConsumer<T, U>`. The original
382 /// consumer remains available after calling this method.
383 ///
384 /// # Returns
385 ///
386 /// Returns the wrapped `ArcStatefulBiConsumer<T, U>` from the clone
387 ///
388 /// # Examples
389 ///
390 /// ```rust
391 /// use qubit_function::{BiConsumer, RcStatefulBiConsumer};
392 /// use std::rc::Rc;
393 /// use std::cell::RefCell;
394 ///
395 /// let log = Rc::new(RefCell::new(Vec::new()));
396 /// let l = log.clone();
397 /// let consumer = RcStatefulBiConsumer::new(move |x: &i32, y: &i32| {
398 /// l.borrow_mut().push(*x + *y);
399 /// });
400 /// let mut arc_consumer = consumer.to_arc();
401 /// arc_consumer.accept(&5, &3);
402 /// assert_eq!(*log.borrow(), vec![8]);
403 /// // Original consumer still usable
404 /// consumer.accept(&2, &1);
405 /// assert_eq!(*log.borrow(), vec![8, 3]);
406 /// ```
407 fn to_arc(&self) -> ArcStatefulBiConsumer<T, U>
408 where
409 Self: Sized + Clone + Send + 'static,
410 {
411 self.clone().into_arc()
412 }
413
414 /// Converts to closure (non-consuming)
415 ///
416 /// **⚠️ Requires Clone**: Original consumer must implement Clone.
417 ///
418 /// Converts the consumer to a closure that can be used directly in
419 /// standard library functions requiring `FnMut`.
420 ///
421 /// # Ownership
422 ///
423 /// This method does **not consume** the consumer. It clones the consumer
424 /// and then converts the clone to a closure. The original consumer
425 /// remains available after calling this method.
426 ///
427 /// # Returns
428 ///
429 /// Returns a closure implementing `FnMut(&T, &U)` from the clone
430 ///
431 /// # Examples
432 ///
433 /// ```rust
434 /// use qubit_function::{BiConsumer, BoxStatefulBiConsumer};
435 /// use std::sync::{Arc, Mutex};
436 ///
437 /// let log = Arc::new(Mutex::new(Vec::new()));
438 /// let l = log.clone();
439 /// let consumer = BoxStatefulBiConsumer::new(move |x: &i32, y: &i32| {
440 /// l.lock().unwrap().push(*x + *y);
441 /// });
442 /// let mut func = consumer.to_fn();
443 /// func(&5, &3);
444 /// assert_eq!(*log.lock().unwrap(), vec![8]);
445 /// // Original consumer still usable
446 /// consumer.accept(&2, &1);
447 /// assert_eq!(*log.lock().unwrap(), vec![8, 3]);
448 /// ```
449 fn to_fn(&self) -> impl FnMut(&T, &U)
450 where
451 Self: Sized + Clone + 'static,
452 {
453 self.clone().into_fn()
454 }
455
456 /// Convert to BiConsumerOnce without consuming self
457 ///
458 /// **⚠️ Requires Clone**: This method requires `Self` to implement `Clone`.
459 /// Clones the current consumer and converts the clone to a one-time consumer.
460 ///
461 /// # Returns
462 ///
463 /// Returns a `BoxBiConsumerOnce<T, U>`
464 fn to_once(&self) -> BoxBiConsumerOnce<T, U>
465 where
466 Self: Clone + 'static,
467 {
468 self.clone().into_once()
469 }
470}
471
472// =======================================================================
473// 2. BoxStatefulBiConsumer - Single Ownership Implementation
474// =======================================================================
475
476/// BoxStatefulBiConsumer struct
477///
478/// A bi-consumer implementation based on `Box<dyn FnMut(&T, &U)>` for
479/// single ownership scenarios. This is the simplest and most efficient
480/// bi-consumer type when sharing is not required.
481///
482/// # Features
483///
484/// - **Single Ownership**: Not cloneable, ownership moves on use
485/// - **Zero Overhead**: No reference counting or locking
486/// - **Mutable State**: Can modify captured environment via `FnMut`
487/// - **Builder Pattern**: Method chaining consumes `self` naturally
488///
489/// # Use Cases
490///
491/// Choose `BoxStatefulBiConsumer` when:
492/// - The bi-consumer is used only once or in a linear flow
493/// - Building pipelines where ownership naturally flows
494/// - No need to share the consumer across contexts
495/// - Performance is critical and sharing overhead is unacceptable
496///
497/// # Performance
498///
499/// `BoxStatefulBiConsumer` has the best performance among the three bi-consumer
500/// types:
501/// - No reference counting overhead
502/// - No lock acquisition or runtime borrow checking
503/// - Direct function call through vtable
504/// - Minimal memory footprint (single pointer)
505///
506/// # Examples
507///
508/// ```rust
509/// use qubit_function::{BiConsumer, BoxStatefulBiConsumer};
510/// use std::sync::{Arc, Mutex};
511///
512/// let log = Arc::new(Mutex::new(Vec::new()));
513/// let l = log.clone();
514/// let mut consumer = BoxStatefulBiConsumer::new(move |x: &i32, y: &i32| {
515/// l.lock().unwrap().push(*x + *y);
516/// });
517/// consumer.accept(&5, &3);
518/// assert_eq!(*log.lock().unwrap(), vec![8]);
519/// ```
520///
521/// # Author
522///
523/// Haixing Hu
524pub struct BoxStatefulBiConsumer<T, U> {
525 function: Box<dyn FnMut(&T, &U)>,
526 name: Option<String>,
527}
528
529impl<T, U> BoxStatefulBiConsumer<T, U> {
530 // Generates: new(), new_with_name(), name(), set_name(), noop()
531 impl_consumer_common_methods!(
532 BoxStatefulBiConsumer<T, U>,
533 (FnMut(&T, &U) + 'static),
534 |f| Box::new(f)
535 );
536
537 // Generates: when() and and_then() methods that consume self
538 impl_box_consumer_methods!(
539 BoxStatefulBiConsumer<T, U>,
540 BoxConditionalStatefulBiConsumer,
541 StatefulBiConsumer
542 );
543}
544
545impl<T, U> StatefulBiConsumer<T, U> for BoxStatefulBiConsumer<T, U> {
546 fn accept(&mut self, first: &T, second: &U) {
547 (self.function)(first, second)
548 }
549
550 // Generates: into_box(), into_rc(), into_fn(), into_once()
551 impl_box_conversions!(
552 BoxStatefulBiConsumer<T, U>,
553 RcStatefulBiConsumer,
554 FnMut(&T, &U),
555 BoxBiConsumerOnce
556 );
557}
558
559// Use macro to generate Debug and Display implementations
560impl_consumer_debug_display!(BoxStatefulBiConsumer<T, U>);
561
562// =======================================================================
563// 3. RcStatefulBiConsumer - Single-Threaded Shared Ownership Implementation
564// =======================================================================
565
566/// RcStatefulBiConsumer struct
567///
568/// A bi-consumer implementation based on `Rc<RefCell<dyn FnMut(&T, &U)>>`
569/// for single-threaded shared ownership scenarios. This consumer provides
570/// the benefits of shared ownership without the overhead of thread
571/// safety.
572///
573/// # Features
574///
575/// - **Shared Ownership**: Cloneable via `Rc`, multiple owners allowed
576/// - **Single-Threaded**: Not thread-safe, cannot send across threads
577/// - **Interior Mutability**: Uses `RefCell` for runtime borrow checking
578/// - **No Lock Overhead**: More efficient than `ArcStatefulBiConsumer` for
579/// single-threaded use
580/// - **Non-Consuming API**: `and_then` borrows `&self`, original remains
581/// usable
582///
583/// # Use Cases
584///
585/// Choose `RcStatefulBiConsumer` when:
586/// - Need to share bi-consumer within a single thread
587/// - Thread safety is not needed
588/// - Performance matters (avoiding lock overhead)
589/// - Single-threaded UI framework event handling
590/// - Building complex single-threaded state machines
591///
592/// # Performance Considerations
593///
594/// `RcStatefulBiConsumer` performs better than `ArcStatefulBiConsumer` in single-threaded
595/// scenarios:
596/// - **Non-Atomic Counting**: clone/drop cheaper than `Arc`
597/// - **No Lock Overhead**: `RefCell` uses runtime checking, no locks
598/// - **Better Cache Locality**: No atomic operations means better CPU
599/// cache behavior
600///
601/// But still has slight overhead compared to `BoxStatefulBiConsumer`:
602/// - **Reference Counting**: Though non-atomic, still exists
603/// - **Runtime Borrow Checking**: `RefCell` checks at runtime
604///
605/// # Safety
606///
607/// `RcStatefulBiConsumer` is not thread-safe and does not implement `Send` or
608/// `Sync`. Attempting to send it to another thread will result in a
609/// compile error. For thread-safe sharing, use `ArcStatefulBiConsumer` instead.
610///
611/// # Examples
612///
613/// ```rust
614/// use qubit_function::{BiConsumer, RcStatefulBiConsumer};
615/// use std::rc::Rc;
616/// use std::cell::RefCell;
617///
618/// let log = Rc::new(RefCell::new(Vec::new()));
619/// let l = log.clone();
620/// let mut consumer = RcStatefulBiConsumer::new(move |x: &i32, y: &i32| {
621/// l.borrow_mut().push(*x + *y);
622/// });
623/// let mut clone = consumer.clone();
624///
625/// consumer.accept(&5, &3);
626/// assert_eq!(*log.borrow(), vec![8]);
627/// ```
628///
629/// # Author
630///
631/// Haixing Hu
632pub struct RcStatefulBiConsumer<T, U> {
633 function: Rc<RefCell<dyn FnMut(&T, &U)>>,
634 name: Option<String>,
635}
636
637impl<T, U> RcStatefulBiConsumer<T, U> {
638 // Generates: new(), new_with_name(), name(), set_name(), noop()
639 impl_consumer_common_methods!(
640 RcStatefulBiConsumer<T, U>,
641 (FnMut(&T, &U) + 'static),
642 |f| Rc::new(RefCell::new(f))
643 );
644
645 // Generates: when() and and_then() methods that borrow &self (Rc can clone)
646 impl_shared_consumer_methods!(
647 RcStatefulBiConsumer<T, U>,
648 RcConditionalStatefulBiConsumer,
649 into_rc,
650 StatefulBiConsumer,
651 'static
652 );
653}
654
655impl<T, U> StatefulBiConsumer<T, U> for RcStatefulBiConsumer<T, U> {
656 fn accept(&mut self, first: &T, second: &U) {
657 (self.function.borrow_mut())(first, second)
658 }
659
660 // Use macro to implement conversion methods
661 impl_rc_conversions!(
662 RcStatefulBiConsumer<T, U>,
663 BoxStatefulBiConsumer,
664 BoxBiConsumerOnce,
665 FnMut(t: &T, u: &U)
666 );
667}
668
669// Use macro to generate Clone implementation
670impl_consumer_clone!(RcStatefulBiConsumer<T, U>);
671
672// Use macro to generate Debug and Display implementations
673impl_consumer_debug_display!(RcStatefulBiConsumer<T, U>);
674
675// =======================================================================
676// 4. ArcStatefulBiConsumer - Thread-Safe Shared Ownership Implementation
677// =======================================================================
678
679/// ArcStatefulBiConsumer struct
680///
681/// A bi-consumer implementation based on
682/// `Arc<Mutex<dyn FnMut(&T, &U) + Send>>` for thread-safe shared
683/// ownership scenarios. This consumer can be safely cloned and shared
684/// across multiple threads.
685///
686/// # Features
687///
688/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
689/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
690/// - **Interior Mutability**: Uses `Mutex` for safe mutable access
691/// - **Non-Consuming API**: `and_then` borrows `&self`, original remains
692/// usable
693/// - **Cross-Thread Sharing**: Can be sent to and used by other threads
694///
695/// # Use Cases
696///
697/// Choose `ArcStatefulBiConsumer` when:
698/// - Need to share bi-consumer across multiple threads
699/// - Concurrent task processing (e.g., thread pools)
700/// - Using the same consumer in multiple places simultaneously
701/// - Thread safety (Send + Sync) is required
702///
703/// # Performance Considerations
704///
705/// `ArcStatefulBiConsumer` has some overhead compared to `BoxStatefulBiConsumer`:
706/// - **Reference Counting**: Atomic operations on clone/drop
707/// - **Mutex Locking**: Each `accept` call requires lock acquisition
708/// - **Lock Contention**: High concurrency may cause contention
709///
710/// These overheads are necessary for safe concurrent access. If thread
711/// safety is not needed, consider using `RcStatefulBiConsumer` for lower
712/// overhead in single-threaded sharing.
713///
714/// # Examples
715///
716/// ```rust
717/// use qubit_function::{BiConsumer, ArcStatefulBiConsumer};
718/// use std::sync::{Arc, Mutex};
719///
720/// let log = Arc::new(Mutex::new(Vec::new()));
721/// let l = log.clone();
722/// let mut consumer = ArcStatefulBiConsumer::new(move |x: &i32, y: &i32| {
723/// l.lock().unwrap().push(*x + *y);
724/// });
725/// let mut clone = consumer.clone();
726///
727/// consumer.accept(&5, &3);
728/// assert_eq!(*log.lock().unwrap(), vec![8]);
729/// ```
730///
731/// # Author
732///
733/// Haixing Hu
734pub struct ArcStatefulBiConsumer<T, U> {
735 function: Arc<Mutex<dyn FnMut(&T, &U) + Send>>,
736 name: Option<String>,
737}
738
739impl<T, U> ArcStatefulBiConsumer<T, U> {
740 // Generates: new(), new_with_name(), name(), set_name(), noop()
741 impl_consumer_common_methods!(
742 ArcStatefulBiConsumer<T, U>,
743 (FnMut(&T, &U) + Send + 'static),
744 |f| Arc::new(Mutex::new(f))
745 );
746
747 // Generates: when() and and_then() methods that borrow &self (Arc can clone)
748 impl_shared_consumer_methods!(
749 ArcStatefulBiConsumer<T, U>,
750 ArcConditionalStatefulBiConsumer,
751 into_arc,
752 StatefulBiConsumer,
753 Send + Sync + 'static
754 );
755}
756
757impl<T, U> StatefulBiConsumer<T, U> for ArcStatefulBiConsumer<T, U> {
758 fn accept(&mut self, first: &T, second: &U) {
759 (self.function.lock())(first, second)
760 }
761
762 // Use macro to implement conversion methods
763 impl_arc_conversions!(
764 ArcStatefulBiConsumer<T, U>,
765 BoxStatefulBiConsumer,
766 RcStatefulBiConsumer,
767 BoxBiConsumerOnce,
768 FnMut(t: &T, u: &U)
769 );
770}
771
772// Use macro to generate Clone implementation
773impl_consumer_clone!(ArcStatefulBiConsumer<T, U>);
774
775// Use macro to generate Debug and Display implementations
776impl_consumer_debug_display!(ArcStatefulBiConsumer<T, U>);
777
778// =======================================================================
779// 5. Implement BiConsumer trait for closures
780// =======================================================================
781
782// Implements BiConsumer for all FnMut(&T, &U)
783impl_closure_trait!(
784 StatefulBiConsumer<T, U>,
785 accept,
786 BoxBiConsumerOnce,
787 FnMut(first: &T, second: &U)
788);
789
790// =======================================================================
791// 6. Provide extension methods for closures
792// =======================================================================
793
794/// Extension trait providing bi-consumer composition methods for closures
795///
796/// Provides `and_then` and other composition methods for all closures
797/// implementing `FnMut(&T, &U)`, enabling direct method chaining on
798/// closures without explicit wrapper types.
799///
800/// # Design Rationale
801///
802/// This trait allows closures to be composed naturally using method
803/// syntax, similar to iterator combinators. Composition methods consume
804/// the closure and return `BoxStatefulBiConsumer<T, U>`, which can be further
805/// chained.
806///
807/// # Features
808///
809/// - **Natural Syntax**: Chain operations directly on closures
810/// - **Returns BoxStatefulBiConsumer**: Composition results are
811/// `BoxStatefulBiConsumer<T, U>` for continued chaining
812/// - **Zero Cost**: No overhead when composing closures
813/// - **Automatic Implementation**: All `FnMut(&T, &U)` closures get
814/// these methods automatically
815///
816/// # Examples
817///
818/// ```rust
819/// use qubit_function::{BiConsumer, FnStatefulBiConsumerOps};
820/// use std::sync::{Arc, Mutex};
821///
822/// let log = Arc::new(Mutex::new(Vec::new()));
823/// let l1 = log.clone();
824/// let l2 = log.clone();
825/// let mut chained = (move |x: &i32, y: &i32| {
826/// l1.lock().unwrap().push(*x + *y);
827/// }).and_then(move |x: &i32, y: &i32| {
828/// l2.lock().unwrap().push(*x * *y);
829/// });
830/// chained.accept(&5, &3);
831/// assert_eq!(*log.lock().unwrap(), vec![8, 15]);
832/// ```
833///
834/// # Author
835///
836/// Haixing Hu
837pub trait FnStatefulBiConsumerOps<T, U>: FnMut(&T, &U) + Sized {
838 /// Chains another consumer in sequence
839 ///
840 /// Returns a new consumer executing the current operation first, then
841 /// the next operation. Consumes the current closure and returns
842 /// `BoxStatefulBiConsumer<T, U>`.
843 ///
844 /// # Type Parameters
845 ///
846 /// * `C` - The type of the next consumer
847 ///
848 /// # Parameters
849 ///
850 /// * `next` - The consumer to execute after the current operation. **Note:
851 /// This parameter is passed by value and will transfer ownership.** If you
852 /// need to preserve the original consumer, clone it first (if it implements
853 /// `Clone`). Can be:
854 /// - A closure: `|x: &T, y: &U|`
855 /// - A `BoxStatefulBiConsumer<T, U>`
856 /// - An `ArcStatefulBiConsumer<T, U>`
857 /// - An `RcStatefulBiConsumer<T, U>`
858 /// - Any type implementing `BiConsumer<T, U>`
859 ///
860 /// # Returns
861 ///
862 /// Returns the composed `BoxStatefulBiConsumer<T, U>`
863 ///
864 /// # Examples
865 ///
866 /// ```rust
867 /// use qubit_function::{BiConsumer, FnStatefulBiConsumerOps};
868 /// use std::sync::{Arc, Mutex};
869 ///
870 /// let log = Arc::new(Mutex::new(Vec::new()));
871 /// let l1 = log.clone();
872 /// let l2 = log.clone();
873 /// let mut chained = (move |x: &i32, y: &i32| {
874 /// l1.lock().unwrap().push(*x + *y);
875 /// }).and_then(move |x: &i32, y: &i32| {
876 /// l2.lock().unwrap().push(*x * *y);
877 /// }).and_then(|x: &i32, y: &i32| println!("Result: {}, {}", x, y));
878 ///
879 /// chained.accept(&5, &3); // Prints: Result: 5, 3
880 /// assert_eq!(*log.lock().unwrap(), vec![8, 15]);
881 /// ```
882 fn and_then<C>(self, next: C) -> BoxStatefulBiConsumer<T, U>
883 where
884 Self: 'static,
885 C: StatefulBiConsumer<T, U> + 'static,
886 T: 'static,
887 U: 'static,
888 {
889 let mut first = self;
890 let mut second = next;
891 BoxStatefulBiConsumer::new(move |t, u| {
892 first(t, u);
893 second.accept(t, u);
894 })
895 }
896}
897
898/// Implements FnStatefulBiConsumerOps for all closure types
899impl<T, U, F> FnStatefulBiConsumerOps<T, U> for F where F: FnMut(&T, &U) {}
900
901// =======================================================================
902// 7. BoxConditionalBiConsumer - Box-based Conditional BiConsumer
903// =======================================================================
904
905/// BoxConditionalBiConsumer struct
906///
907/// A conditional bi-consumer that only executes when a predicate is satisfied.
908/// Uses `BoxStatefulBiConsumer` and `BoxBiPredicate` for single ownership semantics.
909///
910/// This type is typically created by calling `BoxStatefulBiConsumer::when()` and is
911/// designed to work with the `or_else()` method to create if-then-else logic.
912///
913/// # Features
914///
915/// - **Single Ownership**: Not cloneable, consumes `self` on use
916/// - **Conditional Execution**: Only consumes when predicate returns `true`
917/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
918/// - **Implements BiConsumer**: Can be used anywhere a `BiConsumer` is expected
919///
920/// # Examples
921///
922/// ## Basic Conditional Execution
923///
924/// ```rust
925/// use qubit_function::{BiConsumer, BoxStatefulBiConsumer};
926/// use std::sync::{Arc, Mutex};
927///
928/// let log = Arc::new(Mutex::new(Vec::new()));
929/// let l = log.clone();
930/// let consumer = BoxStatefulBiConsumer::new(move |x: &i32, y: &i32| {
931/// l.lock().unwrap().push(*x + *y);
932/// });
933/// let mut conditional = consumer.when(|x: &i32, y: &i32| *x > 0 && *y > 0);
934///
935/// conditional.accept(&5, &3);
936/// assert_eq!(*log.lock().unwrap(), vec![8]); // Executed
937///
938/// conditional.accept(&-5, &3);
939/// assert_eq!(*log.lock().unwrap(), vec![8]); // Not executed
940/// ```
941///
942/// ## With or_else Branch
943///
944/// ```rust
945/// use qubit_function::{BiConsumer, BoxStatefulBiConsumer};
946/// use std::sync::{Arc, Mutex};
947///
948/// let log = Arc::new(Mutex::new(Vec::new()));
949/// let l1 = log.clone();
950/// let l2 = log.clone();
951/// let mut consumer = BoxStatefulBiConsumer::new(move |x: &i32, y: &i32| {
952/// l1.lock().unwrap().push(*x + *y);
953/// }).when(|x: &i32, y: &i32| *x > 0 && *y > 0)
954/// .or_else(move |x: &i32, y: &i32| {
955/// l2.lock().unwrap().push(*x * *y);
956/// });
957///
958/// consumer.accept(&5, &3);
959/// assert_eq!(*log.lock().unwrap(), vec![8]); // when branch executed
960///
961/// consumer.accept(&-5, &3);
962/// assert_eq!(*log.lock().unwrap(), vec![8, -15]); // or_else branch executed
963/// ```
964///
965/// # Author
966///
967/// Haixing Hu
968pub struct BoxConditionalStatefulBiConsumer<T, U> {
969 consumer: BoxStatefulBiConsumer<T, U>,
970 predicate: BoxBiPredicate<T, U>,
971}
972
973// Use macro to generate conditional bi-consumer implementations
974impl_box_conditional_consumer!(
975 BoxConditionalStatefulBiConsumer<T, U>,
976 BoxStatefulBiConsumer,
977 StatefulBiConsumer
978);
979
980impl<T, U> StatefulBiConsumer<T, U> for BoxConditionalStatefulBiConsumer<T, U> {
981 fn accept(&mut self, first: &T, second: &U) {
982 if self.predicate.test(first, second) {
983 self.consumer.accept(first, second);
984 }
985 }
986
987 // Generates: into_box(), into_rc(), into_fn()
988 impl_conditional_consumer_conversions!(
989 BoxStatefulBiConsumer<T, U>,
990 RcStatefulBiConsumer,
991 FnMut
992 );
993}
994
995// Use macro to generate Debug and Display implementations
996impl_conditional_consumer_debug_display!(BoxConditionalStatefulBiConsumer<T, U>);
997
998// =======================================================================
999// 8. ArcConditionalStatefulBiConsumer - Arc-based Conditional BiConsumer
1000// =======================================================================
1001
1002/// ArcConditionalStatefulBiConsumer struct
1003///
1004/// A thread-safe conditional bi-consumer that only executes when a predicate is
1005/// satisfied. Uses `ArcStatefulBiConsumer` and `ArcBiPredicate` for shared ownership across
1006/// threads.
1007///
1008/// This type is typically created by calling `ArcStatefulBiConsumer::when()` and is
1009/// designed to work with the `or_else()` method to create if-then-else logic.
1010///
1011/// # Features
1012///
1013/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
1014/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
1015/// - **Conditional Execution**: Only consumes when predicate returns `true`
1016/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
1017///
1018/// # Examples
1019///
1020/// ```rust
1021/// use qubit_function::{BiConsumer, ArcStatefulBiConsumer};
1022/// use std::sync::{Arc, Mutex};
1023///
1024/// let log = Arc::new(Mutex::new(Vec::new()));
1025/// let l = log.clone();
1026/// let conditional = ArcStatefulBiConsumer::new(move |x: &i32, y: &i32| {
1027/// l.lock().unwrap().push(*x + *y);
1028/// }).when(|x: &i32, y: &i32| *x > 0 && *y > 0);
1029///
1030/// let conditional_clone = conditional.clone();
1031///
1032/// let mut value = 5;
1033/// let mut m = conditional;
1034/// m.accept(&value, &3);
1035/// assert_eq!(*log.lock().unwrap(), vec![8]);
1036/// ```
1037///
1038/// # Author
1039///
1040/// Haixing Hu
1041pub struct ArcConditionalStatefulBiConsumer<T, U> {
1042 consumer: ArcStatefulBiConsumer<T, U>,
1043 predicate: ArcBiPredicate<T, U>,
1044}
1045
1046// Use macro to generate and_then and or_else methods
1047impl_shared_conditional_consumer!(
1048 ArcConditionalStatefulBiConsumer<T, U>,
1049 ArcStatefulBiConsumer,
1050 StatefulBiConsumer,
1051 into_arc,
1052 Send + Sync + 'static
1053);
1054
1055impl<T, U> StatefulBiConsumer<T, U> for ArcConditionalStatefulBiConsumer<T, U> {
1056 fn accept(&mut self, first: &T, second: &U) {
1057 if self.predicate.test(first, second) {
1058 self.consumer.accept(first, second);
1059 }
1060 }
1061
1062 // Generates: into_box(), into_rc(), into_fn()
1063 impl_conditional_consumer_conversions!(
1064 BoxStatefulBiConsumer<T, U>,
1065 RcStatefulBiConsumer,
1066 FnMut
1067 );
1068}
1069
1070// Use macro to generate Clone implementation
1071impl_conditional_consumer_clone!(ArcConditionalStatefulBiConsumer<T, U>);
1072
1073// Use macro to generate Debug and Display implementations
1074impl_conditional_consumer_debug_display!(ArcConditionalStatefulBiConsumer<T, U>);
1075
1076// =======================================================================
1077// 9. RcConditionalStatefulBiConsumer - Rc-based Conditional BiConsumer
1078// =======================================================================
1079
1080/// RcConditionalStatefulBiConsumer struct
1081///
1082/// A single-threaded conditional bi-consumer that only executes when a predicate is
1083/// satisfied. Uses `RcStatefulBiConsumer` and `RcBiPredicate` for shared ownership within a
1084/// single thread.
1085///
1086/// This type is typically created by calling `RcStatefulBiConsumer::when()` and is
1087/// designed to work with the `or_else()` method to create if-then-else logic.
1088///
1089/// # Features
1090///
1091/// - **Shared Ownership**: Cloneable via `Rc`, multiple owners allowed
1092/// - **Single-Threaded**: Not thread-safe, cannot be sent across threads
1093/// - **Conditional Execution**: Only consumes when predicate returns `true`
1094/// - **No Lock Overhead**: More efficient than `ArcConditionalStatefulBiConsumer`
1095///
1096/// # Examples
1097///
1098/// ```rust
1099/// use qubit_function::{BiConsumer, RcStatefulBiConsumer};
1100/// use std::rc::Rc;
1101/// use std::cell::RefCell;
1102///
1103/// let log = Rc::new(RefCell::new(Vec::new()));
1104/// let l = log.clone();
1105/// let conditional = RcStatefulBiConsumer::new(move |x: &i32, y: &i32| {
1106/// l.borrow_mut().push(*x + *y);
1107/// }).when(|x: &i32, y: &i32| *x > 0 && *y > 0);
1108///
1109/// let conditional_clone = conditional.clone();
1110///
1111/// let mut value = 5;
1112/// let mut m = conditional;
1113/// m.accept(&value, &3);
1114/// assert_eq!(*log.borrow(), vec![8]);
1115/// ```
1116///
1117/// # Author
1118///
1119/// Haixing Hu
1120pub struct RcConditionalStatefulBiConsumer<T, U> {
1121 consumer: RcStatefulBiConsumer<T, U>,
1122 predicate: RcBiPredicate<T, U>,
1123}
1124
1125// Use macro to generate and_then and or_else methods
1126impl_shared_conditional_consumer!(
1127 RcConditionalStatefulBiConsumer<T, U>,
1128 RcStatefulBiConsumer,
1129 StatefulBiConsumer,
1130 into_rc,
1131 'static
1132);
1133
1134impl<T, U> StatefulBiConsumer<T, U> for RcConditionalStatefulBiConsumer<T, U> {
1135 fn accept(&mut self, first: &T, second: &U) {
1136 if self.predicate.test(first, second) {
1137 self.consumer.accept(first, second);
1138 }
1139 }
1140
1141 // Generates: into_box(), into_rc(), into_fn()
1142 impl_conditional_consumer_conversions!(
1143 BoxStatefulBiConsumer<T, U>,
1144 RcStatefulBiConsumer,
1145 FnMut
1146 );
1147}
1148
1149// Use macro to generate Clone implementation
1150impl_conditional_consumer_clone!(RcConditionalStatefulBiConsumer<T, U>);
1151
1152// Use macro to generate Debug and Display implementations
1153impl_conditional_consumer_debug_display!(RcConditionalStatefulBiConsumer<T, U>);