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