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