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