prism3_function/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//! This module provides a unified `BiConsumer` trait and three concrete
15//! implementations based on different ownership models:
16//!
17//! - **`BoxBiConsumer<T, U>`**: Box-based single ownership for one-time use
18//! - **`ArcBiConsumer<T, U>`**: Arc<Mutex<>>-based thread-safe shared
19//! ownership
20//! - **`RcBiConsumer<T, U>`**: Rc<RefCell<>>-based single-threaded shared
21//! ownership
22//!
23//! # Design Philosophy
24//!
25//! BiConsumer uses `FnMut(&T, &U)` semantics: can modify its own state but
26//! does NOT modify input values. Suitable for statistics, accumulation, and
27//! event processing scenarios involving two parameters.
28//!
29//! # Author
30//!
31//! Haixing Hu
32
33use std::cell::RefCell;
34use std::fmt;
35use std::rc::Rc;
36use std::sync::{Arc, Mutex};
37
38use crate::bi_predicate::{ArcBiPredicate, BiPredicate, BoxBiPredicate, RcBiPredicate};
39
40/// Type alias for bi-consumer function to simplify complex types.
41///
42/// Represents a mutable function taking two references and returning
43/// nothing. Used to reduce type complexity in struct definitions.
44type BiConsumerFn<T, U> = dyn FnMut(&T, &U);
45
46/// Type alias for thread-safe bi-consumer function.
47///
48/// Represents a mutable function with Send bound for thread-safe usage.
49type SendBiConsumerFn<T, U> = dyn FnMut(&T, &U) + Send;
50
51// =======================================================================
52// 1. BiConsumer Trait - Unified BiConsumer Interface
53// =======================================================================
54
55/// BiConsumer trait - Unified bi-consumer interface
56///
57/// Defines core behavior for all bi-consumer types. Similar to Java's
58/// `BiConsumer<T, U>` interface, performs operations accepting two values
59/// but returning no result (side effects only).
60///
61/// BiConsumer can modify its own state (e.g., accumulate, count) but
62/// should NOT modify the consumed values themselves.
63///
64/// # Automatic Implementations
65///
66/// - All closures implementing `FnMut(&T, &U)`
67/// - `BoxBiConsumer<T, U>`, `ArcBiConsumer<T, U>`, `RcBiConsumer<T, U>`
68///
69/// # Features
70///
71/// - **Unified Interface**: All bi-consumer types share the same `accept`
72/// method signature
73/// - **Automatic Implementation**: Closures automatically implement this
74/// trait with zero overhead
75/// - **Type Conversions**: Easy conversion between ownership models
76/// - **Generic Programming**: Write functions accepting any bi-consumer
77/// type
78///
79/// # Examples
80///
81/// ```rust
82/// use prism3_function::{BiConsumer, BoxBiConsumer, ArcBiConsumer};
83/// use std::sync::{Arc, Mutex};
84///
85/// fn apply_bi_consumer<C: BiConsumer<i32, i32>>(
86/// consumer: &mut C,
87/// a: &i32,
88/// b: &i32
89/// ) {
90/// consumer.accept(a, b);
91/// }
92///
93/// // Works with any bi-consumer type
94/// let log = Arc::new(Mutex::new(Vec::new()));
95/// let l = log.clone();
96/// let mut box_con = BoxBiConsumer::new(move |x: &i32, y: &i32| {
97/// l.lock().unwrap().push(*x + *y);
98/// });
99/// apply_bi_consumer(&mut box_con, &5, &3);
100/// assert_eq!(*log.lock().unwrap(), vec![8]);
101/// ```
102///
103/// # Author
104///
105/// Haixing Hu
106pub trait BiConsumer<T, U> {
107 /// Performs the consumption operation
108 ///
109 /// Executes an operation on the given two references. The operation
110 /// typically reads input values or produces side effects, but does not
111 /// modify the input values themselves. Can modify the consumer's own
112 /// state.
113 ///
114 /// # Parameters
115 ///
116 /// * `first` - Reference to the first value to consume
117 /// * `second` - Reference to the second value to consume
118 ///
119 /// # Examples
120 ///
121 /// ```rust
122 /// use prism3_function::{BiConsumer, BoxBiConsumer};
123 /// use std::sync::{Arc, Mutex};
124 ///
125 /// let log = Arc::new(Mutex::new(Vec::new()));
126 /// let l = log.clone();
127 /// let mut consumer = BoxBiConsumer::new(move |x: &i32, y: &i32| {
128 /// l.lock().unwrap().push(*x + *y);
129 /// });
130 /// consumer.accept(&5, &3);
131 /// assert_eq!(*log.lock().unwrap(), vec![8]);
132 /// ```
133 fn accept(&mut self, first: &T, second: &U);
134
135 /// Converts to BoxBiConsumer
136 ///
137 /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
138 /// calling this method.
139 ///
140 /// Converts the current bi-consumer to `BoxBiConsumer<T, U>`.
141 ///
142 /// # Ownership
143 ///
144 /// This method **consumes** the consumer (takes ownership of `self`).
145 /// After calling, the original consumer is no longer available.
146 ///
147 /// **Tip**: For cloneable consumers ([`ArcBiConsumer`],
148 /// [`RcBiConsumer`]), call `.clone()` first if you need to keep the
149 /// original.
150 ///
151 /// # Returns
152 ///
153 /// Returns the wrapped `BoxBiConsumer<T, U>`
154 ///
155 /// # Examples
156 ///
157 /// ```rust
158 /// use prism3_function::BiConsumer;
159 /// use std::sync::{Arc, Mutex};
160 ///
161 /// let log = Arc::new(Mutex::new(Vec::new()));
162 /// let l = log.clone();
163 /// let closure = move |x: &i32, y: &i32| {
164 /// l.lock().unwrap().push(*x + *y);
165 /// };
166 /// let mut box_consumer = closure.into_box();
167 /// box_consumer.accept(&5, &3);
168 /// assert_eq!(*log.lock().unwrap(), vec![8]);
169 /// ```
170 fn into_box(self) -> BoxBiConsumer<T, U>
171 where
172 Self: Sized + 'static,
173 T: 'static,
174 U: 'static,
175 {
176 let mut consumer = self;
177 BoxBiConsumer::new(move |t, u| consumer.accept(t, u))
178 }
179
180 /// Converts to RcBiConsumer
181 ///
182 /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
183 /// calling this method.
184 ///
185 /// # Returns
186 ///
187 /// Returns the wrapped `RcBiConsumer<T, U>`
188 fn into_rc(self) -> RcBiConsumer<T, U>
189 where
190 Self: Sized + 'static,
191 T: 'static,
192 U: 'static,
193 {
194 let mut consumer = self;
195 RcBiConsumer::new(move |t, u| consumer.accept(t, u))
196 }
197
198 /// Converts to ArcBiConsumer
199 ///
200 /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
201 /// calling this method.
202 ///
203 /// # Returns
204 ///
205 /// Returns the wrapped `ArcBiConsumer<T, U>`
206 fn into_arc(self) -> ArcBiConsumer<T, U>
207 where
208 Self: Sized + Send + 'static,
209 T: Send + 'static,
210 U: Send + 'static,
211 {
212 let mut consumer = self;
213 ArcBiConsumer::new(move |t, u| consumer.accept(t, u))
214 }
215
216 /// Converts bi-consumer to a closure
217 ///
218 /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
219 /// calling this method.
220 ///
221 /// Converts the bi-consumer to a closure usable with standard library
222 /// methods requiring `FnMut`.
223 ///
224 /// # Returns
225 ///
226 /// Returns a closure implementing `FnMut(&T, &U)`
227 ///
228 /// # Examples
229 ///
230 /// ```rust
231 /// use prism3_function::{BiConsumer, BoxBiConsumer};
232 /// use std::sync::{Arc, Mutex};
233 ///
234 /// let log = Arc::new(Mutex::new(Vec::new()));
235 /// let l = log.clone();
236 /// let consumer = BoxBiConsumer::new(move |x: &i32, y: &i32| {
237 /// l.lock().unwrap().push(*x + *y);
238 /// });
239 /// let mut func = consumer.into_fn();
240 /// func(&5, &3);
241 /// assert_eq!(*log.lock().unwrap(), vec![8]);
242 /// ```
243 fn into_fn(self) -> impl FnMut(&T, &U)
244 where
245 Self: Sized + 'static,
246 T: 'static,
247 U: 'static,
248 {
249 let mut consumer = self;
250 move |t, u| consumer.accept(t, u)
251 }
252
253 /// Converts to BoxBiConsumer (non-consuming)
254 ///
255 /// **⚠️ Requires Clone**: Original consumer must implement Clone.
256 ///
257 /// Converts the current bi-consumer to `BoxBiConsumer<T, U>` by cloning
258 /// it first.
259 ///
260 /// # Ownership
261 ///
262 /// This method does **not consume** the consumer. It clones the consumer
263 /// and then converts the clone to `BoxBiConsumer<T, U>`. The original
264 /// consumer remains available after calling this method.
265 ///
266 /// # Returns
267 ///
268 /// Returns the wrapped `BoxBiConsumer<T, U>` from the clone
269 ///
270 /// # Examples
271 ///
272 /// ```rust
273 /// use prism3_function::{BiConsumer, ArcBiConsumer};
274 /// use std::sync::{Arc, Mutex};
275 ///
276 /// let log = Arc::new(Mutex::new(Vec::new()));
277 /// let l = log.clone();
278 /// let consumer = ArcBiConsumer::new(move |x: &i32, y: &i32| {
279 /// l.lock().unwrap().push(*x + *y);
280 /// });
281 /// let mut box_consumer = consumer.to_box();
282 /// box_consumer.accept(&5, &3);
283 /// assert_eq!(*log.lock().unwrap(), vec![8]);
284 /// // Original consumer still usable
285 /// consumer.accept(&2, &1);
286 /// assert_eq!(*log.lock().unwrap(), vec![8, 3]);
287 /// ```
288 fn to_box(&self) -> BoxBiConsumer<T, U>
289 where
290 Self: Sized + Clone + 'static,
291 T: 'static,
292 U: 'static,
293 {
294 self.clone().into_box()
295 }
296
297 /// Converts to RcBiConsumer (non-consuming)
298 ///
299 /// **⚠️ Requires Clone**: Original consumer must implement Clone.
300 ///
301 /// Converts the current bi-consumer to `RcBiConsumer<T, U>` by cloning
302 /// it first.
303 ///
304 /// # Ownership
305 ///
306 /// This method does **not consume** the consumer. It clones the consumer
307 /// and then converts the clone to `RcBiConsumer<T, U>`. The original
308 /// consumer remains available after calling this method.
309 ///
310 /// # Returns
311 ///
312 /// Returns the wrapped `RcBiConsumer<T, U>` from the clone
313 ///
314 /// # Examples
315 ///
316 /// ```rust
317 /// use prism3_function::{BiConsumer, ArcBiConsumer};
318 /// use std::sync::{Arc, Mutex};
319 ///
320 /// let log = Arc::new(Mutex::new(Vec::new()));
321 /// let l = log.clone();
322 /// let consumer = ArcBiConsumer::new(move |x: &i32, y: &i32| {
323 /// l.lock().unwrap().push(*x + *y);
324 /// });
325 /// let mut rc_consumer = consumer.to_rc();
326 /// rc_consumer.accept(&5, &3);
327 /// assert_eq!(*log.lock().unwrap(), vec![8]);
328 /// // Original consumer still usable
329 /// consumer.accept(&2, &1);
330 /// assert_eq!(*log.lock().unwrap(), vec![8, 3]);
331 /// ```
332 fn to_rc(&self) -> RcBiConsumer<T, U>
333 where
334 Self: Sized + Clone + 'static,
335 T: 'static,
336 U: 'static,
337 {
338 self.clone().into_rc()
339 }
340
341 /// Converts to ArcBiConsumer (non-consuming)
342 ///
343 /// **⚠️ Requires Clone + Send**: Original consumer must implement Clone +
344 /// Send.
345 ///
346 /// Converts the current bi-consumer to `ArcBiConsumer<T, U>` by cloning
347 /// it first.
348 ///
349 /// # Ownership
350 ///
351 /// This method does **not consume** the consumer. It clones the consumer
352 /// and then converts the clone to `ArcBiConsumer<T, U>`. The original
353 /// consumer remains available after calling this method.
354 ///
355 /// # Returns
356 ///
357 /// Returns the wrapped `ArcBiConsumer<T, U>` from the clone
358 ///
359 /// # Examples
360 ///
361 /// ```rust
362 /// use prism3_function::{BiConsumer, RcBiConsumer};
363 /// use std::rc::Rc;
364 /// use std::cell::RefCell;
365 ///
366 /// let log = Rc::new(RefCell::new(Vec::new()));
367 /// let l = log.clone();
368 /// let consumer = RcBiConsumer::new(move |x: &i32, y: &i32| {
369 /// l.borrow_mut().push(*x + *y);
370 /// });
371 /// let mut arc_consumer = consumer.to_arc();
372 /// arc_consumer.accept(&5, &3);
373 /// assert_eq!(*log.borrow(), vec![8]);
374 /// // Original consumer still usable
375 /// consumer.accept(&2, &1);
376 /// assert_eq!(*log.borrow(), vec![8, 3]);
377 /// ```
378 fn to_arc(&self) -> ArcBiConsumer<T, U>
379 where
380 Self: Sized + Clone + Send + 'static,
381 T: Send + 'static,
382 U: Send + 'static,
383 {
384 self.clone().into_arc()
385 }
386
387 /// Converts to closure (non-consuming)
388 ///
389 /// **⚠️ Requires Clone**: Original consumer must implement Clone.
390 ///
391 /// Converts the consumer to a closure that can be used directly in
392 /// standard library functions requiring `FnMut`.
393 ///
394 /// # Ownership
395 ///
396 /// This method does **not consume** the consumer. It clones the consumer
397 /// and then converts the clone to a closure. The original consumer
398 /// remains available after calling this method.
399 ///
400 /// # Returns
401 ///
402 /// Returns a closure implementing `FnMut(&T, &U)` from the clone
403 ///
404 /// # Examples
405 ///
406 /// ```rust
407 /// use prism3_function::{BiConsumer, BoxBiConsumer};
408 /// use std::sync::{Arc, Mutex};
409 ///
410 /// let log = Arc::new(Mutex::new(Vec::new()));
411 /// let l = log.clone();
412 /// let consumer = BoxBiConsumer::new(move |x: &i32, y: &i32| {
413 /// l.lock().unwrap().push(*x + *y);
414 /// });
415 /// let mut func = consumer.to_fn();
416 /// func(&5, &3);
417 /// assert_eq!(*log.lock().unwrap(), vec![8]);
418 /// // Original consumer still usable
419 /// consumer.accept(&2, &1);
420 /// assert_eq!(*log.lock().unwrap(), vec![8, 3]);
421 /// ```
422 fn to_fn(&self) -> impl FnMut(&T, &U)
423 where
424 Self: Sized + Clone + 'static,
425 T: 'static,
426 U: 'static,
427 {
428 self.clone().into_fn()
429 }
430}
431
432// =======================================================================
433// 2. BoxBiConsumer - Single Ownership Implementation
434// =======================================================================
435
436/// BoxBiConsumer struct
437///
438/// A bi-consumer implementation based on `Box<dyn FnMut(&T, &U)>` for
439/// single ownership scenarios. This is the simplest and most efficient
440/// bi-consumer type when sharing is not required.
441///
442/// # Features
443///
444/// - **Single Ownership**: Not cloneable, ownership moves on use
445/// - **Zero Overhead**: No reference counting or locking
446/// - **Mutable State**: Can modify captured environment via `FnMut`
447/// - **Builder Pattern**: Method chaining consumes `self` naturally
448///
449/// # Use Cases
450///
451/// Choose `BoxBiConsumer` when:
452/// - The bi-consumer is used only once or in a linear flow
453/// - Building pipelines where ownership naturally flows
454/// - No need to share the consumer across contexts
455/// - Performance is critical and sharing overhead is unacceptable
456///
457/// # Performance
458///
459/// `BoxBiConsumer` has the best performance among the three bi-consumer
460/// types:
461/// - No reference counting overhead
462/// - No lock acquisition or runtime borrow checking
463/// - Direct function call through vtable
464/// - Minimal memory footprint (single pointer)
465///
466/// # Examples
467///
468/// ```rust
469/// use prism3_function::{BiConsumer, BoxBiConsumer};
470/// use std::sync::{Arc, Mutex};
471///
472/// let log = Arc::new(Mutex::new(Vec::new()));
473/// let l = log.clone();
474/// let mut consumer = BoxBiConsumer::new(move |x: &i32, y: &i32| {
475/// l.lock().unwrap().push(*x + *y);
476/// });
477/// consumer.accept(&5, &3);
478/// assert_eq!(*log.lock().unwrap(), vec![8]);
479/// ```
480///
481/// # Author
482///
483/// Haixing Hu
484pub struct BoxBiConsumer<T, U> {
485 function: Box<BiConsumerFn<T, U>>,
486 name: Option<String>,
487}
488
489impl<T, U> BoxBiConsumer<T, U>
490where
491 T: 'static,
492 U: 'static,
493{
494 /// Creates a new BoxBiConsumer
495 ///
496 /// # Type Parameters
497 ///
498 /// * `F` - The closure type
499 ///
500 /// # Parameters
501 ///
502 /// * `f` - The closure to wrap
503 ///
504 /// # Returns
505 ///
506 /// Returns a new `BoxBiConsumer<T, U>` instance
507 ///
508 /// # Examples
509 ///
510 /// ```rust
511 /// use prism3_function::{BiConsumer, BoxBiConsumer};
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 = BoxBiConsumer::new(move |x: &i32, y: &i32| {
517 /// l.lock().unwrap().push(*x * 2 + *y);
518 /// });
519 /// consumer.accept(&5, &3);
520 /// assert_eq!(*log.lock().unwrap(), vec![13]);
521 /// ```
522 pub fn new<F>(f: F) -> Self
523 where
524 F: FnMut(&T, &U) + 'static,
525 {
526 BoxBiConsumer {
527 function: Box::new(f),
528 name: None,
529 }
530 }
531
532 /// Creates a new BoxBiConsumer with a name
533 ///
534 /// # Type Parameters
535 ///
536 /// * `F` - The closure type
537 ///
538 /// # Parameters
539 ///
540 /// * `name` - The name of the consumer
541 /// * `f` - The closure to wrap
542 ///
543 /// # Returns
544 ///
545 /// Returns a new `BoxBiConsumer<T, U>` instance with the specified name
546 ///
547 /// # Examples
548 ///
549 /// ```rust
550 /// use prism3_function::{BiConsumer, BoxBiConsumer};
551 /// use std::sync::{Arc, Mutex};
552 ///
553 /// let log = Arc::new(Mutex::new(Vec::new()));
554 /// let l = log.clone();
555 /// let mut consumer = BoxBiConsumer::new_with_name("sum_logger", move |x: &i32, y: &i32| {
556 /// l.lock().unwrap().push(*x + *y);
557 /// });
558 /// assert_eq!(consumer.name(), Some("sum_logger"));
559 /// consumer.accept(&5, &3);
560 /// assert_eq!(*log.lock().unwrap(), vec![8]);
561 /// ```
562 pub fn new_with_name<F>(name: &str, f: F) -> Self
563 where
564 F: FnMut(&T, &U) + 'static,
565 {
566 BoxBiConsumer {
567 function: Box::new(f),
568 name: Some(name.to_string()),
569 }
570 }
571
572 /// Creates a no-op bi-consumer
573 ///
574 /// Returns a bi-consumer that performs no operation.
575 ///
576 /// # Returns
577 ///
578 /// Returns a no-op bi-consumer
579 ///
580 /// # Examples
581 ///
582 /// ```rust
583 /// use prism3_function::{BiConsumer, BoxBiConsumer};
584 ///
585 /// let mut noop = BoxBiConsumer::<i32, i32>::noop();
586 /// noop.accept(&42, &10);
587 /// // Values unchanged
588 /// ```
589 pub fn noop() -> Self {
590 BoxBiConsumer::new(|_, _| {})
591 }
592
593 /// Gets the name of the consumer
594 ///
595 /// # Returns
596 ///
597 /// Returns the consumer's name, or `None` if not set
598 pub fn name(&self) -> Option<&str> {
599 self.name.as_deref()
600 }
601
602 /// Sets the name of the consumer
603 ///
604 /// # Parameters
605 ///
606 /// * `name` - The name to set
607 pub fn set_name(&mut self, name: impl Into<String>) {
608 self.name = Some(name.into());
609 }
610
611 /// Chains another consumer in sequence
612 ///
613 /// Returns a new consumer executing the current operation first, then
614 /// the next operation. Consumes self.
615 ///
616 /// # Type Parameters
617 ///
618 /// * `C` - The type of the next consumer
619 ///
620 /// # Parameters
621 ///
622 /// * `next` - The consumer to execute after the current operation. **Note:
623 /// This parameter is passed by value and will transfer ownership.** If you
624 /// need to preserve the original consumer, clone it first (if it implements
625 /// `Clone`). Can be:
626 /// - A closure: `|x: &T, y: &U|`
627 /// - A `BoxBiConsumer<T, U>`
628 /// - An `ArcBiConsumer<T, U>`
629 /// - An `RcBiConsumer<T, U>`
630 /// - Any type implementing `BiConsumer<T, U>`
631 ///
632 /// # Returns
633 ///
634 /// Returns a new composed `BoxBiConsumer<T, U>`
635 ///
636 /// # Examples
637 ///
638 /// ## Direct value passing (ownership transfer)
639 ///
640 /// ```rust
641 /// use prism3_function::{BiConsumer, BoxBiConsumer};
642 /// use std::sync::{Arc, Mutex};
643 ///
644 /// let log = Arc::new(Mutex::new(Vec::new()));
645 /// let l1 = log.clone();
646 /// let l2 = log.clone();
647 /// let first = BoxBiConsumer::new(move |x: &i32, y: &i32| {
648 /// l1.lock().unwrap().push(*x + *y);
649 /// });
650 /// let second = BoxBiConsumer::new(move |x: &i32, y: &i32| {
651 /// l2.lock().unwrap().push(*x * *y);
652 /// });
653 ///
654 /// // second is moved here
655 /// let mut chained = first.and_then(second);
656 /// chained.accept(&5, &3);
657 /// assert_eq!(*log.lock().unwrap(), vec![8, 15]);
658 /// // second.accept(&2, &3); // Would not compile - moved
659 /// ```
660 ///
661 /// ## Preserving original with clone
662 ///
663 /// ```rust
664 /// use prism3_function::{BiConsumer, BoxBiConsumer};
665 /// use std::sync::{Arc, Mutex};
666 ///
667 /// let log = Arc::new(Mutex::new(Vec::new()));
668 /// let l1 = log.clone();
669 /// let l2 = log.clone();
670 /// let first = BoxBiConsumer::new(move |x: &i32, y: &i32| {
671 /// l1.lock().unwrap().push(*x + *y);
672 /// });
673 /// let second = BoxBiConsumer::new(move |x: &i32, y: &i32| {
674 /// l2.lock().unwrap().push(*x * *y);
675 /// });
676 ///
677 /// // Clone to preserve original
678 /// let mut chained = first.and_then(second.clone());
679 /// chained.accept(&5, &3);
680 /// assert_eq!(*log.lock().unwrap(), vec![8, 15]);
681 ///
682 /// // Original still usable
683 /// second.accept(&2, &3);
684 /// assert_eq!(*log.lock().unwrap(), vec![8, 15, 6]);
685 /// ```
686 pub fn and_then<C>(self, next: C) -> Self
687 where
688 C: BiConsumer<T, U> + 'static,
689 {
690 let mut first = self.function;
691 let mut second = next;
692 BoxBiConsumer::new(move |t, u| {
693 first(t, u);
694 second.accept(t, u);
695 })
696 }
697
698 /// Creates a conditional bi-consumer
699 ///
700 /// Returns a bi-consumer that only executes when a predicate is satisfied.
701 ///
702 /// # Parameters
703 ///
704 /// * `predicate` - The condition to check. **Note: This parameter is passed
705 /// by value and will transfer ownership.** If you need to preserve the
706 /// original bi-predicate, clone it first (if it implements `Clone`). Can be:
707 /// - A closure: `|x: &T, y: &U| -> bool`
708 /// - A function pointer: `fn(&T, &U) -> bool`
709 /// - A `BoxBiPredicate<T, U>`
710 /// - An `RcBiPredicate<T, U>`
711 /// - An `ArcBiPredicate<T, U>`
712 /// - Any type implementing `BiPredicate<T, U>`
713 ///
714 /// # Returns
715 ///
716 /// Returns `BoxConditionalBiConsumer<T, U>`
717 pub fn when<P>(self, predicate: P) -> BoxConditionalBiConsumer<T, U>
718 where
719 P: BiPredicate<T, U> + 'static,
720 {
721 BoxConditionalBiConsumer {
722 consumer: self,
723 predicate: predicate.into_box(),
724 }
725 }
726}
727
728impl<T, U> BiConsumer<T, U> for BoxBiConsumer<T, U> {
729 fn accept(&mut self, first: &T, second: &U) {
730 (self.function)(first, second)
731 }
732
733 fn into_box(self) -> BoxBiConsumer<T, U>
734 where
735 T: 'static,
736 U: 'static,
737 {
738 self
739 }
740
741 fn into_rc(self) -> RcBiConsumer<T, U>
742 where
743 T: 'static,
744 U: 'static,
745 {
746 let mut func = self.function;
747 RcBiConsumer::new(move |t, u| func(t, u))
748 }
749
750 // do NOT override BiConsumer::into_arc() because BoxBiConsumer is not Send + Sync
751 // and calling BoxBiConsumer::into_arc() will cause a compile error
752
753 fn into_fn(self) -> impl FnMut(&T, &U)
754 where
755 T: 'static,
756 U: 'static,
757 {
758 self.function
759 }
760
761 // do NOT override BiConsumer::to_xxx() because BoxBiConsumer is not Clone
762 // and calling BoxBiConsumer::to_xxx() will cause a compile error
763}
764
765impl<T, U> fmt::Debug for BoxBiConsumer<T, U> {
766 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
767 f.debug_struct("BoxBiConsumer")
768 .field("name", &self.name)
769 .field("function", &"<function>")
770 .finish()
771 }
772}
773
774impl<T, U> fmt::Display for BoxBiConsumer<T, U> {
775 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
776 match &self.name {
777 Some(name) => write!(f, "BoxBiConsumer({})", name),
778 None => write!(f, "BoxBiConsumer"),
779 }
780 }
781}
782
783// =======================================================================
784// 3. BoxConditionalBiConsumer - Box-based Conditional BiConsumer
785// =======================================================================
786
787/// BoxConditionalBiConsumer struct
788///
789/// A conditional bi-consumer that only executes when a predicate is satisfied.
790/// Uses `BoxBiConsumer` and `BoxBiPredicate` for single ownership semantics.
791///
792/// This type is typically created by calling `BoxBiConsumer::when()` and is
793/// designed to work with the `or_else()` method to create if-then-else logic.
794///
795/// # Features
796///
797/// - **Single Ownership**: Not cloneable, consumes `self` on use
798/// - **Conditional Execution**: Only consumes when predicate returns `true`
799/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
800/// - **Implements BiConsumer**: Can be used anywhere a `BiConsumer` is expected
801///
802/// # Examples
803///
804/// ## Basic Conditional Execution
805///
806/// ```rust
807/// use prism3_function::{BiConsumer, BoxBiConsumer};
808/// use std::sync::{Arc, Mutex};
809///
810/// let log = Arc::new(Mutex::new(Vec::new()));
811/// let l = log.clone();
812/// let consumer = BoxBiConsumer::new(move |x: &i32, y: &i32| {
813/// l.lock().unwrap().push(*x + *y);
814/// });
815/// let mut conditional = consumer.when(|x: &i32, y: &i32| *x > 0 && *y > 0);
816///
817/// conditional.accept(&5, &3);
818/// assert_eq!(*log.lock().unwrap(), vec![8]); // Executed
819///
820/// conditional.accept(&-5, &3);
821/// assert_eq!(*log.lock().unwrap(), vec![8]); // Not executed
822/// ```
823///
824/// ## With or_else Branch
825///
826/// ```rust
827/// use prism3_function::{BiConsumer, BoxBiConsumer};
828/// use std::sync::{Arc, Mutex};
829///
830/// let log = Arc::new(Mutex::new(Vec::new()));
831/// let l1 = log.clone();
832/// let l2 = log.clone();
833/// let mut consumer = BoxBiConsumer::new(move |x: &i32, y: &i32| {
834/// l1.lock().unwrap().push(*x + *y);
835/// }).when(|x: &i32, y: &i32| *x > 0 && *y > 0)
836/// .or_else(move |x: &i32, y: &i32| {
837/// l2.lock().unwrap().push(*x * *y);
838/// });
839///
840/// consumer.accept(&5, &3);
841/// assert_eq!(*log.lock().unwrap(), vec![8]); // when branch executed
842///
843/// consumer.accept(&-5, &3);
844/// assert_eq!(*log.lock().unwrap(), vec![8, -15]); // or_else branch executed
845/// ```
846///
847/// # Author
848///
849/// Haixing Hu
850pub struct BoxConditionalBiConsumer<T, U> {
851 consumer: BoxBiConsumer<T, U>,
852 predicate: BoxBiPredicate<T, U>,
853}
854
855impl<T, U> BiConsumer<T, U> for BoxConditionalBiConsumer<T, U>
856where
857 T: 'static,
858 U: 'static,
859{
860 fn accept(&mut self, first: &T, second: &U) {
861 if self.predicate.test(first, second) {
862 self.consumer.accept(first, second);
863 }
864 }
865
866 fn into_box(self) -> BoxBiConsumer<T, U> {
867 let pred = self.predicate;
868 let mut consumer = self.consumer;
869 BoxBiConsumer::new(move |t, u| {
870 if pred.test(t, u) {
871 consumer.accept(t, u);
872 }
873 })
874 }
875
876 fn into_rc(self) -> RcBiConsumer<T, U> {
877 let pred = self.predicate.into_rc();
878 let consumer = self.consumer.into_rc();
879 let mut consumer_fn = consumer;
880 RcBiConsumer::new(move |t, u| {
881 if pred.test(t, u) {
882 consumer_fn.accept(t, u);
883 }
884 })
885 }
886
887 // do NOT override BiConsumer::into_arc() because BoxConditionalBiConsumer is not Send + Sync
888 // and calling BoxConditionalBiConsumer::into_arc() will cause a compile error
889
890 fn into_fn(self) -> impl FnMut(&T, &U) {
891 let pred = self.predicate;
892 let mut consumer = self.consumer;
893 move |t: &T, u: &U| {
894 if pred.test(t, u) {
895 consumer.accept(t, u);
896 }
897 }
898 }
899
900 // do NOT override BiConsumer::to_xxx() because BoxConditionalBiConsumer is not Clone
901 // and calling BoxConditionalBiConsumer::to_xxx() will cause a compile error
902}
903
904impl<T, U> BoxConditionalBiConsumer<T, U>
905where
906 T: 'static,
907 U: 'static,
908{
909 /// Chains another consumer in sequence
910 ///
911 /// Combines the current conditional consumer with another consumer into a new
912 /// consumer. The current conditional consumer executes first, followed by the
913 /// next consumer.
914 ///
915 /// # Parameters
916 ///
917 /// * `next` - The next consumer to execute. **Note: This parameter is passed
918 /// by value and will transfer ownership.** If you need to preserve the
919 /// original consumer, clone it first (if it implements `Clone`). Can be:
920 /// - A closure: `|x: &T, y: &U|`
921 /// - A `BoxBiConsumer<T, U>`
922 /// - An `ArcBiConsumer<T, U>`
923 /// - An `RcBiConsumer<T, U>`
924 /// - Any type implementing `BiConsumer<T, U>`
925 ///
926 /// # Returns
927 ///
928 /// Returns a new `BoxBiConsumer<T, U>`
929 ///
930 /// # Examples
931 ///
932 /// ## Direct value passing (ownership transfer)
933 ///
934 /// ```rust
935 /// use prism3_function::{BiConsumer, BoxBiConsumer};
936 /// use std::sync::{Arc, Mutex};
937 ///
938 /// let log = Arc::new(Mutex::new(Vec::new()));
939 /// let l1 = log.clone();
940 /// let l2 = log.clone();
941 /// let cond = BoxBiConsumer::new(move |x: &i32, y: &i32| {
942 /// l1.lock().unwrap().push(*x + *y);
943 /// }).when(|x: &i32, y: &i32| *x > 0 && *y > 0);
944 /// let second = BoxBiConsumer::new(move |x: &i32, y: &i32| {
945 /// l2.lock().unwrap().push(*x * *y);
946 /// });
947 ///
948 /// // second is moved here
949 /// let mut chained = cond.and_then(second);
950 /// chained.accept(&5, &3);
951 /// assert_eq!(*log.lock().unwrap(), vec![8, 15]);
952 /// // second.accept(&2, &3); // Would not compile - moved
953 /// ```
954 ///
955 /// ## Preserving original with clone
956 ///
957 /// ```rust
958 /// use prism3_function::{BiConsumer, BoxBiConsumer};
959 /// use std::sync::{Arc, Mutex};
960 ///
961 /// let log = Arc::new(Mutex::new(Vec::new()));
962 /// let l1 = log.clone();
963 /// let l2 = log.clone();
964 /// let cond = BoxBiConsumer::new(move |x: &i32, y: &i32| {
965 /// l1.lock().unwrap().push(*x + *y);
966 /// }).when(|x: &i32, y: &i32| *x > 0 && *y > 0);
967 /// let second = BoxBiConsumer::new(move |x: &i32, y: &i32| {
968 /// l2.lock().unwrap().push(*x * *y);
969 /// });
970 ///
971 /// // Clone to preserve original
972 /// let mut chained = cond.and_then(second.clone());
973 /// chained.accept(&5, &3);
974 /// assert_eq!(*log.lock().unwrap(), vec![8, 15]);
975 ///
976 /// // Original still usable
977 /// second.accept(&2, &3);
978 /// assert_eq!(*log.lock().unwrap(), vec![8, 15, 6]);
979 /// ```
980 pub fn and_then<C>(self, next: C) -> BoxBiConsumer<T, U>
981 where
982 C: BiConsumer<T, U> + 'static,
983 {
984 let mut first = self;
985 let mut second = next;
986 BoxBiConsumer::new(move |t, u| {
987 first.accept(t, u);
988 second.accept(t, u);
989 })
990 }
991
992 /// Adds an else branch
993 ///
994 /// Executes the original consumer when the condition is satisfied, otherwise
995 /// executes else_consumer.
996 ///
997 /// # Parameters
998 ///
999 /// * `else_consumer` - The consumer for the else branch. **Note: This parameter
1000 /// is passed by value and will transfer ownership.** If you need to preserve
1001 /// the original consumer, clone it first (if it implements `Clone`). Can be:
1002 /// - A closure: `|x: &T, y: &U|`
1003 /// - A `BoxBiConsumer<T, U>`
1004 /// - An `RcBiConsumer<T, U>`
1005 /// - An `ArcBiConsumer<T, U>`
1006 /// - Any type implementing `BiConsumer<T, U>`
1007 ///
1008 /// # Returns
1009 ///
1010 /// Returns the composed `BoxBiConsumer<T, U>`
1011 ///
1012 /// # Examples
1013 ///
1014 /// ## Using a closure (recommended)
1015 ///
1016 /// ```rust
1017 /// use prism3_function::{BiConsumer, BoxBiConsumer};
1018 /// use std::sync::{Arc, Mutex};
1019 ///
1020 /// let log = Arc::new(Mutex::new(Vec::new()));
1021 /// let l1 = log.clone();
1022 /// let l2 = log.clone();
1023 /// let mut consumer = BoxBiConsumer::new(move |x: &i32, y: &i32| {
1024 /// l1.lock().unwrap().push(*x + *y);
1025 /// }).when(|x: &i32, y: &i32| *x > 0 && *y > 0)
1026 /// .or_else(move |x: &i32, y: &i32| {
1027 /// l2.lock().unwrap().push(*x * *y);
1028 /// });
1029 ///
1030 /// consumer.accept(&5, &3);
1031 /// assert_eq!(*log.lock().unwrap(), vec![8]); // Condition satisfied
1032 ///
1033 /// consumer.accept(&-5, &3);
1034 /// assert_eq!(*log.lock().unwrap(), vec![8, -15]); // Condition not satisfied
1035 /// ```
1036 pub fn or_else<C>(self, else_consumer: C) -> BoxBiConsumer<T, U>
1037 where
1038 C: BiConsumer<T, U> + 'static,
1039 {
1040 let pred = self.predicate;
1041 let mut then_cons = self.consumer;
1042 let mut else_cons = else_consumer;
1043 BoxBiConsumer::new(move |t, u| {
1044 if pred.test(t, u) {
1045 then_cons.accept(t, u);
1046 } else {
1047 else_cons.accept(t, u);
1048 }
1049 })
1050 }
1051}
1052
1053// =======================================================================
1054// 4. ArcBiConsumer - Thread-Safe Shared Ownership Implementation
1055// =======================================================================
1056
1057/// ArcBiConsumer struct
1058///
1059/// A bi-consumer implementation based on
1060/// `Arc<Mutex<dyn FnMut(&T, &U) + Send>>` for thread-safe shared
1061/// ownership scenarios. This consumer can be safely cloned and shared
1062/// across multiple threads.
1063///
1064/// # Features
1065///
1066/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
1067/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
1068/// - **Interior Mutability**: Uses `Mutex` for safe mutable access
1069/// - **Non-Consuming API**: `and_then` borrows `&self`, original remains
1070/// usable
1071/// - **Cross-Thread Sharing**: Can be sent to and used by other threads
1072///
1073/// # Use Cases
1074///
1075/// Choose `ArcBiConsumer` when:
1076/// - Need to share bi-consumer across multiple threads
1077/// - Concurrent task processing (e.g., thread pools)
1078/// - Using the same consumer in multiple places simultaneously
1079/// - Thread safety (Send + Sync) is required
1080///
1081/// # Performance Considerations
1082///
1083/// `ArcBiConsumer` has some overhead compared to `BoxBiConsumer`:
1084/// - **Reference Counting**: Atomic operations on clone/drop
1085/// - **Mutex Locking**: Each `accept` call requires lock acquisition
1086/// - **Lock Contention**: High concurrency may cause contention
1087///
1088/// These overheads are necessary for safe concurrent access. If thread
1089/// safety is not needed, consider using `RcBiConsumer` for lower
1090/// overhead in single-threaded sharing.
1091///
1092/// # Examples
1093///
1094/// ```rust
1095/// use prism3_function::{BiConsumer, ArcBiConsumer};
1096/// use std::sync::{Arc, Mutex};
1097///
1098/// let log = Arc::new(Mutex::new(Vec::new()));
1099/// let l = log.clone();
1100/// let mut consumer = ArcBiConsumer::new(move |x: &i32, y: &i32| {
1101/// l.lock().unwrap().push(*x + *y);
1102/// });
1103/// let mut clone = consumer.clone();
1104///
1105/// consumer.accept(&5, &3);
1106/// assert_eq!(*log.lock().unwrap(), vec![8]);
1107/// ```
1108///
1109/// # Author
1110///
1111/// Haixing Hu
1112pub struct ArcBiConsumer<T, U> {
1113 function: Arc<Mutex<SendBiConsumerFn<T, U>>>,
1114 name: Option<String>,
1115}
1116
1117impl<T, U> ArcBiConsumer<T, U>
1118where
1119 T: Send + 'static,
1120 U: Send + 'static,
1121{
1122 /// Creates a new ArcBiConsumer
1123 ///
1124 /// # Type Parameters
1125 ///
1126 /// * `F` - The closure type
1127 ///
1128 /// # Parameters
1129 ///
1130 /// * `f` - The closure to wrap
1131 ///
1132 /// # Returns
1133 ///
1134 /// Returns a new `ArcBiConsumer<T, U>` instance
1135 ///
1136 /// # Examples
1137 ///
1138 /// ```rust
1139 /// use prism3_function::{BiConsumer, ArcBiConsumer};
1140 /// use std::sync::{Arc, Mutex};
1141 ///
1142 /// let log = Arc::new(Mutex::new(Vec::new()));
1143 /// let l = log.clone();
1144 /// let mut consumer = ArcBiConsumer::new(move |x: &i32, y: &i32| {
1145 /// l.lock().unwrap().push(*x * 2 + *y);
1146 /// });
1147 /// consumer.accept(&5, &3);
1148 /// assert_eq!(*log.lock().unwrap(), vec![13]);
1149 /// ```
1150 pub fn new<F>(f: F) -> Self
1151 where
1152 F: FnMut(&T, &U) + Send + 'static,
1153 {
1154 ArcBiConsumer {
1155 function: Arc::new(Mutex::new(f)),
1156 name: None,
1157 }
1158 }
1159
1160 /// Creates a new ArcBiConsumer with a name
1161 ///
1162 /// # Type Parameters
1163 ///
1164 /// * `F` - The closure type
1165 ///
1166 /// # Parameters
1167 ///
1168 /// * `name` - The name of the consumer
1169 /// * `f` - The closure to wrap
1170 ///
1171 /// # Returns
1172 ///
1173 /// Returns a new `ArcBiConsumer<T, U>` instance with the specified name
1174 ///
1175 /// # Examples
1176 ///
1177 /// ```rust
1178 /// use prism3_function::{BiConsumer, ArcBiConsumer};
1179 /// use std::sync::{Arc, Mutex};
1180 ///
1181 /// let log = Arc::new(Mutex::new(Vec::new()));
1182 /// let l = log.clone();
1183 /// let mut consumer = ArcBiConsumer::new_with_name("sum_logger", move |x: &i32, y: &i32| {
1184 /// l.lock().unwrap().push(*x + *y);
1185 /// });
1186 /// assert_eq!(consumer.name(), Some("sum_logger"));
1187 /// consumer.accept(&5, &3);
1188 /// assert_eq!(*log.lock().unwrap(), vec![8]);
1189 /// ```
1190 pub fn new_with_name<F>(name: &str, f: F) -> Self
1191 where
1192 F: FnMut(&T, &U) + Send + 'static,
1193 {
1194 ArcBiConsumer {
1195 function: Arc::new(Mutex::new(f)),
1196 name: Some(name.to_string()),
1197 }
1198 }
1199
1200 /// Gets the name of the consumer
1201 ///
1202 /// # Returns
1203 ///
1204 /// Returns the consumer's name, or `None` if not set
1205 pub fn name(&self) -> Option<&str> {
1206 self.name.as_deref()
1207 }
1208
1209 /// Sets the name of the consumer
1210 ///
1211 /// # Parameters
1212 ///
1213 /// * `name` - The name to set
1214 pub fn set_name(&mut self, name: impl Into<String>) {
1215 self.name = Some(name.into());
1216 }
1217
1218 /// Converts to a closure (without consuming self)
1219 ///
1220 /// Creates a new closure that calls the underlying function via Arc.
1221 ///
1222 /// # Returns
1223 ///
1224 /// Returns a closure implementing `FnMut(&T, &U)`
1225 ///
1226 /// # Examples
1227 ///
1228 /// ```rust
1229 /// use prism3_function::{BiConsumer, ArcBiConsumer};
1230 /// use std::sync::{Arc, Mutex};
1231 ///
1232 /// let log = Arc::new(Mutex::new(Vec::new()));
1233 /// let l = log.clone();
1234 /// let consumer = ArcBiConsumer::new(move |x: &i32, y: &i32| {
1235 /// l.lock().unwrap().push(*x + *y);
1236 /// });
1237 ///
1238 /// let mut func = consumer.to_fn();
1239 /// func(&5, &3);
1240 /// assert_eq!(*log.lock().unwrap(), vec![8]);
1241 /// ```
1242 pub fn to_fn(&self) -> impl FnMut(&T, &U)
1243 where
1244 T: 'static,
1245 U: 'static,
1246 {
1247 let func = Arc::clone(&self.function);
1248 move |t: &T, u: &U| {
1249 func.lock().unwrap()(t, u);
1250 }
1251 }
1252
1253 /// Chains another ArcBiConsumer in sequence
1254 ///
1255 /// Returns a new consumer executing the current operation first, then
1256 /// the next operation. Borrows &self, does not consume the original
1257 /// consumer.
1258 ///
1259 /// # Parameters
1260 ///
1261 /// * `next` - The consumer to execute after the current operation. **Note:
1262 /// This parameter is passed by reference, so the original consumer remains
1263 /// usable.** Can be:
1264 /// - An `ArcBiConsumer<T, U>` (passed by reference)
1265 /// - Any type implementing `BiConsumer<T, U> + Send + Sync`
1266 ///
1267 /// # Returns
1268 ///
1269 /// Returns a new composed `ArcBiConsumer<T, U>`
1270 ///
1271 /// # Examples
1272 ///
1273 /// ```rust
1274 /// use prism3_function::{BiConsumer, ArcBiConsumer};
1275 /// use std::sync::{Arc, Mutex};
1276 ///
1277 /// let log = Arc::new(Mutex::new(Vec::new()));
1278 /// let l1 = log.clone();
1279 /// let l2 = log.clone();
1280 /// let first = ArcBiConsumer::new(move |x: &i32, y: &i32| {
1281 /// l1.lock().unwrap().push(*x + *y);
1282 /// });
1283 /// let second = ArcBiConsumer::new(move |x: &i32, y: &i32| {
1284 /// l2.lock().unwrap().push(*x * *y);
1285 /// });
1286 ///
1287 /// // second is passed by reference, so it remains usable
1288 /// let mut chained = first.and_then(&second);
1289 ///
1290 /// // first and second still usable after chaining
1291 /// chained.accept(&5, &3);
1292 /// assert_eq!(*log.lock().unwrap(), vec![8, 15]);
1293 /// // second.accept(&2, &3); // Still usable
1294 /// ```
1295 pub fn and_then(&self, next: &ArcBiConsumer<T, U>) -> ArcBiConsumer<T, U> {
1296 let first = Arc::clone(&self.function);
1297 let second = Arc::clone(&next.function);
1298 ArcBiConsumer {
1299 function: Arc::new(Mutex::new(move |t: &T, u: &U| {
1300 first.lock().unwrap()(t, u);
1301 second.lock().unwrap()(t, u);
1302 })),
1303 name: None,
1304 }
1305 }
1306
1307 /// Creates a conditional bi-consumer (thread-safe version)
1308 ///
1309 /// Returns a bi-consumer that only executes when a predicate is satisfied.
1310 ///
1311 /// # Type Parameters
1312 ///
1313 /// * `P` - The predicate type
1314 ///
1315 /// # Parameters
1316 ///
1317 /// * `predicate` - The condition to check. **Note: This parameter is passed
1318 /// by value and will transfer ownership.** If you need to preserve the
1319 /// original bi-predicate, clone it first (if it implements `Clone`).
1320 /// Must be `Send + Sync`, can be:
1321 /// - A closure: `|x: &T, y: &U| -> bool` (requires `Send + Sync`)
1322 /// - A function pointer: `fn(&T, &U) -> bool`
1323 /// - An `ArcBiPredicate<T, U>`
1324 /// - Any type implementing `BiPredicate<T, U> + Send + Sync`
1325 ///
1326 /// # Returns
1327 ///
1328 /// Returns `ArcConditionalBiConsumer<T, U>`
1329 ///
1330 /// # Examples
1331 ///
1332 /// ```rust
1333 /// use prism3_function::{BiConsumer, ArcBiConsumer};
1334 /// use std::sync::{Arc, Mutex};
1335 ///
1336 /// let log = Arc::new(Mutex::new(Vec::new()));
1337 /// let l = log.clone();
1338 /// let consumer = ArcBiConsumer::new(move |x: &i32, y: &i32| {
1339 /// l.lock().unwrap().push(*x + *y);
1340 /// });
1341 /// let conditional = consumer.when(|x: &i32, y: &i32| *x > 0 && *y > 0);
1342 ///
1343 /// let conditional_clone = conditional.clone();
1344 ///
1345 /// let mut positive = 5;
1346 /// let mut m = conditional;
1347 /// m.accept(&positive, &3);
1348 /// assert_eq!(*log.lock().unwrap(), vec![8]);
1349 /// ```
1350 pub fn when<P>(&self, predicate: P) -> ArcConditionalBiConsumer<T, U>
1351 where
1352 P: BiPredicate<T, U> + Send + Sync + 'static,
1353 T: Send + Sync,
1354 U: Send + Sync,
1355 {
1356 ArcConditionalBiConsumer {
1357 consumer: self.clone(),
1358 predicate: predicate.into_arc(),
1359 }
1360 }
1361}
1362
1363impl<T, U> BiConsumer<T, U> for ArcBiConsumer<T, U> {
1364 fn accept(&mut self, first: &T, second: &U) {
1365 (self.function.lock().unwrap())(first, second)
1366 }
1367
1368 fn into_box(self) -> BoxBiConsumer<T, U>
1369 where
1370 T: 'static,
1371 U: 'static,
1372 {
1373 let self_fn = self.function;
1374 BoxBiConsumer::new(move |t, u| self_fn.lock().unwrap()(t, u))
1375 }
1376
1377 fn into_rc(self) -> RcBiConsumer<T, U>
1378 where
1379 T: 'static,
1380 U: 'static,
1381 {
1382 let self_fn = self.function;
1383 RcBiConsumer::new(move |t, u| self_fn.lock().unwrap()(t, u))
1384 }
1385
1386 fn into_arc(self) -> ArcBiConsumer<T, U>
1387 where
1388 T: Send + 'static,
1389 U: Send + 'static,
1390 {
1391 self
1392 }
1393
1394 fn into_fn(self) -> impl FnMut(&T, &U)
1395 where
1396 T: 'static,
1397 U: 'static,
1398 {
1399 let self_fn = self.function;
1400 move |t, u| self_fn.lock().unwrap()(t, u)
1401 }
1402
1403 fn to_box(&self) -> BoxBiConsumer<T, U>
1404 where
1405 T: 'static,
1406 U: 'static,
1407 {
1408 let self_fn = self.function.clone();
1409 BoxBiConsumer::new(move |t, u| self_fn.lock().unwrap()(t, u))
1410 }
1411
1412 fn to_rc(&self) -> RcBiConsumer<T, U>
1413 where
1414 T: 'static,
1415 U: 'static,
1416 {
1417 let self_fn = self.function.clone();
1418 RcBiConsumer::new(move |t, u| self_fn.lock().unwrap()(t, u))
1419 }
1420
1421 fn to_arc(&self) -> ArcBiConsumer<T, U>
1422 where
1423 T: Send + 'static,
1424 U: Send + 'static,
1425 {
1426 self.clone()
1427 }
1428
1429 fn to_fn(&self) -> impl FnMut(&T, &U)
1430 where
1431 T: 'static,
1432 U: 'static,
1433 {
1434 let self_fn = self.function.clone();
1435 move |t, u| self_fn.lock().unwrap()(t, u)
1436 }
1437}
1438
1439impl<T, U> Clone for ArcBiConsumer<T, U> {
1440 /// Clones the ArcBiConsumer
1441 ///
1442 /// Creates a new ArcBiConsumer sharing the underlying function with
1443 /// the original instance.
1444 fn clone(&self) -> Self {
1445 ArcBiConsumer {
1446 function: self.function.clone(),
1447 name: self.name.clone(),
1448 }
1449 }
1450}
1451
1452impl<T, U> fmt::Debug for ArcBiConsumer<T, U> {
1453 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1454 f.debug_struct("ArcBiConsumer")
1455 .field("name", &self.name)
1456 .field("function", &"<function>")
1457 .finish()
1458 }
1459}
1460
1461impl<T, U> fmt::Display for ArcBiConsumer<T, U> {
1462 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1463 match &self.name {
1464 Some(name) => write!(f, "ArcBiConsumer({})", name),
1465 None => write!(f, "ArcBiConsumer"),
1466 }
1467 }
1468}
1469
1470// =======================================================================
1471// 5. ArcConditionalBiConsumer - Arc-based Conditional BiConsumer
1472// =======================================================================
1473
1474/// ArcConditionalBiConsumer struct
1475///
1476/// A thread-safe conditional bi-consumer that only executes when a predicate is
1477/// satisfied. Uses `ArcBiConsumer` and `ArcBiPredicate` for shared ownership across
1478/// threads.
1479///
1480/// This type is typically created by calling `ArcBiConsumer::when()` and is
1481/// designed to work with the `or_else()` method to create if-then-else logic.
1482///
1483/// # Features
1484///
1485/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
1486/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
1487/// - **Conditional Execution**: Only consumes when predicate returns `true`
1488/// - **Chainable**: Can add `or_else` branch to create if-then-else logic
1489///
1490/// # Examples
1491///
1492/// ```rust
1493/// use prism3_function::{BiConsumer, ArcBiConsumer};
1494/// use std::sync::{Arc, Mutex};
1495///
1496/// let log = Arc::new(Mutex::new(Vec::new()));
1497/// let l = log.clone();
1498/// let conditional = ArcBiConsumer::new(move |x: &i32, y: &i32| {
1499/// l.lock().unwrap().push(*x + *y);
1500/// }).when(|x: &i32, y: &i32| *x > 0 && *y > 0);
1501///
1502/// let conditional_clone = conditional.clone();
1503///
1504/// let mut value = 5;
1505/// let mut m = conditional;
1506/// m.accept(&value, &3);
1507/// assert_eq!(*log.lock().unwrap(), vec![8]);
1508/// ```
1509///
1510/// # Author
1511///
1512/// Haixing Hu
1513pub struct ArcConditionalBiConsumer<T, U> {
1514 consumer: ArcBiConsumer<T, U>,
1515 predicate: ArcBiPredicate<T, U>,
1516}
1517
1518impl<T, U> BiConsumer<T, U> for ArcConditionalBiConsumer<T, U>
1519where
1520 T: Send + 'static,
1521 U: Send + 'static,
1522{
1523 fn accept(&mut self, first: &T, second: &U) {
1524 if self.predicate.test(first, second) {
1525 self.consumer.accept(first, second);
1526 }
1527 }
1528
1529 fn into_box(self) -> BoxBiConsumer<T, U>
1530 where
1531 T: 'static,
1532 U: 'static,
1533 {
1534 let pred = self.predicate;
1535 let mut consumer = self.consumer;
1536 BoxBiConsumer::new(move |t, u| {
1537 if pred.test(t, u) {
1538 consumer.accept(t, u);
1539 }
1540 })
1541 }
1542
1543 fn into_rc(self) -> RcBiConsumer<T, U>
1544 where
1545 T: 'static,
1546 U: 'static,
1547 {
1548 let pred = self.predicate.to_rc();
1549 let consumer = self.consumer.into_rc();
1550 let mut consumer_fn = consumer;
1551 RcBiConsumer::new(move |t, u| {
1552 if pred.test(t, u) {
1553 consumer_fn.accept(t, u);
1554 }
1555 })
1556 }
1557
1558 fn into_arc(self) -> ArcBiConsumer<T, U>
1559 where
1560 T: Send + 'static,
1561 U: Send + 'static,
1562 {
1563 let pred = self.predicate;
1564 let mut consumer = self.consumer;
1565 ArcBiConsumer::new(move |t, u| {
1566 if pred.test(t, u) {
1567 consumer.accept(t, u);
1568 }
1569 })
1570 }
1571
1572 fn into_fn(self) -> impl FnMut(&T, &U)
1573 where
1574 T: 'static,
1575 U: 'static,
1576 {
1577 let pred = self.predicate;
1578 let mut consumer = self.consumer;
1579 move |t: &T, u: &U| {
1580 if pred.test(t, u) {
1581 consumer.accept(t, u);
1582 }
1583 }
1584 }
1585
1586 // Use the default implementation of to_xxx() from BiConsumer
1587}
1588
1589impl<T, U> ArcConditionalBiConsumer<T, U>
1590where
1591 T: Send + 'static,
1592 U: Send + 'static,
1593{
1594 /// Adds an else branch (thread-safe version)
1595 ///
1596 /// Executes the original consumer when the condition is satisfied, otherwise
1597 /// executes else_consumer.
1598 ///
1599 /// # Parameters
1600 ///
1601 /// * `else_consumer` - The consumer for the else branch. **Note: This parameter
1602 /// is passed by value and will transfer ownership.** If you need to preserve
1603 /// the original consumer, clone it first (if it implements `Clone`).
1604 /// Must be `Send`, can be:
1605 /// - A closure: `|x: &T, y: &U|` (must be `Send`)
1606 /// - An `ArcBiConsumer<T, U>`
1607 /// - A `BoxBiConsumer<T, U>`
1608 /// - Any type implementing `BiConsumer<T, U> + Send`
1609 ///
1610 /// # Returns
1611 ///
1612 /// Returns the composed `ArcBiConsumer<T, U>`
1613 ///
1614 /// # Examples
1615 ///
1616 /// ## Using a closure (recommended)
1617 ///
1618 /// ```rust
1619 /// use prism3_function::{BiConsumer, ArcBiConsumer};
1620 /// use std::sync::{Arc, Mutex};
1621 ///
1622 /// let log = Arc::new(Mutex::new(Vec::new()));
1623 /// let l1 = log.clone();
1624 /// let l2 = log.clone();
1625 /// let mut consumer = ArcBiConsumer::new(move |x: &i32, y: &i32| {
1626 /// l1.lock().unwrap().push(*x + *y);
1627 /// }).when(|x: &i32, y: &i32| *x > 0 && *y > 0)
1628 /// .or_else(move |x: &i32, y: &i32| {
1629 /// l2.lock().unwrap().push(*x * *y);
1630 /// });
1631 ///
1632 /// consumer.accept(&5, &3);
1633 /// assert_eq!(*log.lock().unwrap(), vec![8]);
1634 ///
1635 /// consumer.accept(&-5, &3);
1636 /// assert_eq!(*log.lock().unwrap(), vec![8, -15]);
1637 /// ```
1638 pub fn or_else<C>(&self, else_consumer: C) -> ArcBiConsumer<T, U>
1639 where
1640 C: BiConsumer<T, U> + Send + 'static,
1641 T: Send + Sync,
1642 U: Send + Sync,
1643 {
1644 let pred = self.predicate.clone();
1645 let mut then_cons = self.consumer.clone();
1646 let mut else_cons = else_consumer;
1647
1648 ArcBiConsumer::new(move |t: &T, u: &U| {
1649 if pred.test(t, u) {
1650 then_cons.accept(t, u);
1651 } else {
1652 else_cons.accept(t, u);
1653 }
1654 })
1655 }
1656}
1657
1658impl<T, U> Clone for ArcConditionalBiConsumer<T, U> {
1659 /// Clones the conditional consumer
1660 ///
1661 /// Creates a new instance that shares the underlying consumer and predicate
1662 /// with the original instance.
1663 fn clone(&self) -> Self {
1664 ArcConditionalBiConsumer {
1665 consumer: self.consumer.clone(),
1666 predicate: self.predicate.clone(),
1667 }
1668 }
1669}
1670
1671// =======================================================================
1672// 6. RcBiConsumer - Single-Threaded Shared Ownership Implementation
1673// =======================================================================
1674
1675/// RcBiConsumer struct
1676///
1677/// A bi-consumer implementation based on `Rc<RefCell<dyn FnMut(&T, &U)>>`
1678/// for single-threaded shared ownership scenarios. This consumer provides
1679/// the benefits of shared ownership without the overhead of thread
1680/// safety.
1681///
1682/// # Features
1683///
1684/// - **Shared Ownership**: Cloneable via `Rc`, multiple owners allowed
1685/// - **Single-Threaded**: Not thread-safe, cannot send across threads
1686/// - **Interior Mutability**: Uses `RefCell` for runtime borrow checking
1687/// - **No Lock Overhead**: More efficient than `ArcBiConsumer` for
1688/// single-threaded use
1689/// - **Non-Consuming API**: `and_then` borrows `&self`, original remains
1690/// usable
1691///
1692/// # Use Cases
1693///
1694/// Choose `RcBiConsumer` when:
1695/// - Need to share bi-consumer within a single thread
1696/// - Thread safety is not needed
1697/// - Performance matters (avoiding lock overhead)
1698/// - Single-threaded UI framework event handling
1699/// - Building complex single-threaded state machines
1700///
1701/// # Performance Considerations
1702///
1703/// `RcBiConsumer` performs better than `ArcBiConsumer` in single-threaded
1704/// scenarios:
1705/// - **Non-Atomic Counting**: clone/drop cheaper than `Arc`
1706/// - **No Lock Overhead**: `RefCell` uses runtime checking, no locks
1707/// - **Better Cache Locality**: No atomic operations means better CPU
1708/// cache behavior
1709///
1710/// But still has slight overhead compared to `BoxBiConsumer`:
1711/// - **Reference Counting**: Though non-atomic, still exists
1712/// - **Runtime Borrow Checking**: `RefCell` checks at runtime
1713///
1714/// # Safety
1715///
1716/// `RcBiConsumer` is not thread-safe and does not implement `Send` or
1717/// `Sync`. Attempting to send it to another thread will result in a
1718/// compile error. For thread-safe sharing, use `ArcBiConsumer` instead.
1719///
1720/// # Examples
1721///
1722/// ```rust
1723/// use prism3_function::{BiConsumer, RcBiConsumer};
1724/// use std::rc::Rc;
1725/// use std::cell::RefCell;
1726///
1727/// let log = Rc::new(RefCell::new(Vec::new()));
1728/// let l = log.clone();
1729/// let mut consumer = RcBiConsumer::new(move |x: &i32, y: &i32| {
1730/// l.borrow_mut().push(*x + *y);
1731/// });
1732/// let mut clone = consumer.clone();
1733///
1734/// consumer.accept(&5, &3);
1735/// assert_eq!(*log.borrow(), vec![8]);
1736/// ```
1737///
1738/// # Author
1739///
1740/// Haixing Hu
1741pub struct RcBiConsumer<T, U> {
1742 function: Rc<RefCell<BiConsumerFn<T, U>>>,
1743 name: Option<String>,
1744}
1745
1746impl<T, U> RcBiConsumer<T, U>
1747where
1748 T: 'static,
1749 U: 'static,
1750{
1751 /// Creates a new RcBiConsumer
1752 ///
1753 /// # Type Parameters
1754 ///
1755 /// * `F` - The closure type
1756 ///
1757 /// # Parameters
1758 ///
1759 /// * `f` - The closure to wrap
1760 ///
1761 /// # Returns
1762 ///
1763 /// Returns a new `RcBiConsumer<T, U>` instance
1764 ///
1765 /// # Examples
1766 ///
1767 /// ```rust
1768 /// use prism3_function::{BiConsumer, RcBiConsumer};
1769 /// use std::rc::Rc;
1770 /// use std::cell::RefCell;
1771 ///
1772 /// let log = Rc::new(RefCell::new(Vec::new()));
1773 /// let l = log.clone();
1774 /// let mut consumer = RcBiConsumer::new(move |x: &i32, y: &i32| {
1775 /// l.borrow_mut().push(*x * 2 + *y);
1776 /// });
1777 /// consumer.accept(&5, &3);
1778 /// assert_eq!(*log.borrow(), vec![13]);
1779 /// ```
1780 pub fn new<F>(f: F) -> Self
1781 where
1782 F: FnMut(&T, &U) + 'static,
1783 {
1784 RcBiConsumer {
1785 function: Rc::new(RefCell::new(f)),
1786 name: None,
1787 }
1788 }
1789
1790 /// Creates a new RcBiConsumer with a name
1791 ///
1792 /// # Type Parameters
1793 ///
1794 /// * `F` - The closure type
1795 ///
1796 /// # Parameters
1797 ///
1798 /// * `name` - The name of the consumer
1799 /// * `f` - The closure to wrap
1800 ///
1801 /// # Returns
1802 ///
1803 /// Returns a new `RcBiConsumer<T, U>` instance with the specified name
1804 ///
1805 /// # Examples
1806 ///
1807 /// ```rust
1808 /// use prism3_function::{BiConsumer, RcBiConsumer};
1809 /// use std::rc::Rc;
1810 /// use std::cell::RefCell;
1811 ///
1812 /// let log = Rc::new(RefCell::new(Vec::new()));
1813 /// let l = log.clone();
1814 /// let mut consumer = RcBiConsumer::new_with_name("sum_logger", move |x: &i32, y: &i32| {
1815 /// l.borrow_mut().push(*x + *y);
1816 /// });
1817 /// assert_eq!(consumer.name(), Some("sum_logger"));
1818 /// consumer.accept(&5, &3);
1819 /// assert_eq!(*log.borrow(), vec![8]);
1820 /// ```
1821 pub fn new_with_name<F>(name: &str, f: F) -> Self
1822 where
1823 F: FnMut(&T, &U) + 'static,
1824 {
1825 RcBiConsumer {
1826 function: Rc::new(RefCell::new(f)),
1827 name: Some(name.to_string()),
1828 }
1829 }
1830
1831 /// Gets the name of the consumer
1832 ///
1833 /// # Returns
1834 ///
1835 /// Returns the consumer's name, or `None` if not set
1836 pub fn name(&self) -> Option<&str> {
1837 self.name.as_deref()
1838 }
1839
1840 /// Sets the name of the consumer
1841 ///
1842 /// # Parameters
1843 ///
1844 /// * `name` - The name to set
1845 pub fn set_name(&mut self, name: impl Into<String>) {
1846 self.name = Some(name.into());
1847 }
1848
1849 /// Converts to a closure (without consuming self)
1850 ///
1851 /// Creates a new closure that calls the underlying function via Rc.
1852 ///
1853 /// # Returns
1854 ///
1855 /// Returns a closure implementing `FnMut(&T, &U)`
1856 ///
1857 /// # Examples
1858 ///
1859 /// ```rust
1860 /// use prism3_function::{BiConsumer, RcBiConsumer};
1861 /// use std::rc::Rc;
1862 /// use std::cell::RefCell;
1863 ///
1864 /// let log = Rc::new(RefCell::new(Vec::new()));
1865 /// let l = log.clone();
1866 /// let consumer = RcBiConsumer::new(move |x: &i32, y: &i32| {
1867 /// l.borrow_mut().push(*x + *y);
1868 /// });
1869 ///
1870 /// let mut func = consumer.to_fn();
1871 /// func(&5, &3);
1872 /// assert_eq!(*log.borrow(), vec![8]);
1873 /// ```
1874 pub fn to_fn(&self) -> impl FnMut(&T, &U)
1875 where
1876 T: 'static,
1877 U: 'static,
1878 {
1879 let func = Rc::clone(&self.function);
1880 move |t: &T, u: &U| {
1881 func.borrow_mut()(t, u);
1882 }
1883 }
1884
1885 /// Chains another RcBiConsumer in sequence
1886 ///
1887 /// Returns a new consumer executing the current operation first, then
1888 /// the next operation. Borrows &self, does not consume the original
1889 /// consumer.
1890 ///
1891 /// # Parameters
1892 ///
1893 /// * `next` - The consumer to execute after the current operation
1894 ///
1895 /// # Returns
1896 ///
1897 /// Returns a new composed `RcBiConsumer<T, U>`
1898 ///
1899 /// # Examples
1900 ///
1901 /// ```rust
1902 /// use prism3_function::{BiConsumer, RcBiConsumer};
1903 /// use std::rc::Rc;
1904 /// use std::cell::RefCell;
1905 ///
1906 /// let log = Rc::new(RefCell::new(Vec::new()));
1907 /// let l1 = log.clone();
1908 /// let l2 = log.clone();
1909 /// let first = RcBiConsumer::new(move |x: &i32, y: &i32| {
1910 /// l1.borrow_mut().push(*x + *y);
1911 /// });
1912 /// let second = RcBiConsumer::new(move |x: &i32, y: &i32| {
1913 /// l2.borrow_mut().push(*x * *y);
1914 /// });
1915 ///
1916 /// let mut chained = first.and_then(&second);
1917 ///
1918 /// // first and second still usable after chaining
1919 /// chained.accept(&5, &3);
1920 /// assert_eq!(*log.borrow(), vec![8, 15]);
1921 /// ```
1922 pub fn and_then(&self, next: &RcBiConsumer<T, U>) -> RcBiConsumer<T, U> {
1923 let first = Rc::clone(&self.function);
1924 let second = Rc::clone(&next.function);
1925 RcBiConsumer {
1926 function: Rc::new(RefCell::new(move |t: &T, u: &U| {
1927 first.borrow_mut()(t, u);
1928 second.borrow_mut()(t, u);
1929 })),
1930 name: None,
1931 }
1932 }
1933
1934 /// Creates a conditional bi-consumer (single-threaded shared version)
1935 ///
1936 /// Returns a bi-consumer that only executes when a predicate is satisfied.
1937 ///
1938 /// # Type Parameters
1939 ///
1940 /// * `P` - The predicate type
1941 ///
1942 /// # Parameters
1943 ///
1944 /// * `predicate` - The condition to check. **Note: This parameter is passed
1945 /// by value and will transfer ownership.** If you need to preserve the
1946 /// original bi-predicate, clone it first (if it implements `Clone`). Can be:
1947 /// - A closure: `|x: &T, y: &U| -> bool`
1948 /// - A function pointer: `fn(&T, &U) -> bool`
1949 /// - An `RcBiPredicate<T, U>`
1950 /// - A `BoxBiPredicate<T, U>`
1951 /// - Any type implementing `BiPredicate<T, U>`
1952 ///
1953 /// # Returns
1954 ///
1955 /// Returns `RcConditionalBiConsumer<T, U>`
1956 ///
1957 /// # Examples
1958 ///
1959 /// ```rust
1960 /// use prism3_function::{BiConsumer, RcBiConsumer};
1961 /// use std::rc::Rc;
1962 /// use std::cell::RefCell;
1963 ///
1964 /// let log = Rc::new(RefCell::new(Vec::new()));
1965 /// let l = log.clone();
1966 /// let consumer = RcBiConsumer::new(move |x: &i32, y: &i32| {
1967 /// l.borrow_mut().push(*x + *y);
1968 /// });
1969 /// let conditional = consumer.when(|x: &i32, y: &i32| *x > 0 && *y > 0);
1970 ///
1971 /// let conditional_clone = conditional.clone();
1972 ///
1973 /// let mut positive = 5;
1974 /// let mut m = conditional;
1975 /// m.accept(&positive, &3);
1976 /// assert_eq!(*log.borrow(), vec![8]);
1977 /// ```
1978 pub fn when<P>(&self, predicate: P) -> RcConditionalBiConsumer<T, U>
1979 where
1980 P: BiPredicate<T, U> + 'static,
1981 {
1982 RcConditionalBiConsumer {
1983 consumer: self.clone(),
1984 predicate: predicate.into_rc(),
1985 }
1986 }
1987}
1988
1989impl<T, U> BiConsumer<T, U> for RcBiConsumer<T, U> {
1990 fn accept(&mut self, first: &T, second: &U) {
1991 (self.function.borrow_mut())(first, second)
1992 }
1993
1994 fn into_box(self) -> BoxBiConsumer<T, U>
1995 where
1996 T: 'static,
1997 U: 'static,
1998 {
1999 let self_fn = self.function;
2000 BoxBiConsumer::new(move |t, u| self_fn.borrow_mut()(t, u))
2001 }
2002
2003 fn into_rc(self) -> RcBiConsumer<T, U>
2004 where
2005 T: 'static,
2006 U: 'static,
2007 {
2008 self
2009 }
2010
2011 // do NOT override BiConsumer::into_arc() because RcBiConsumer is not Send + Sync
2012 // and calling RcBiConsumer::into_arc() will cause a compile error
2013
2014 fn into_fn(self) -> impl FnMut(&T, &U)
2015 where
2016 T: 'static,
2017 U: 'static,
2018 {
2019 let self_fn = self.function;
2020 move |t, u| self_fn.borrow_mut()(t, u)
2021 }
2022
2023 fn to_box(&self) -> BoxBiConsumer<T, U>
2024 where
2025 T: 'static,
2026 U: 'static,
2027 {
2028 let self_fn = self.function.clone();
2029 BoxBiConsumer::new(move |t, u| self_fn.borrow_mut()(t, u))
2030 }
2031
2032 fn to_rc(&self) -> RcBiConsumer<T, U>
2033 where
2034 T: 'static,
2035 U: 'static,
2036 {
2037 self.clone()
2038 }
2039
2040 // do NOT override BiConsumer::to_arc() because RcBiConsumer is not Send + Sync
2041 // and calling RcBiConsumer::to_arc() will cause a compile error
2042
2043 fn to_fn(&self) -> impl FnMut(&T, &U)
2044 where
2045 T: 'static,
2046 U: 'static,
2047 {
2048 let self_fn = self.function.clone();
2049 move |t, u| self_fn.borrow_mut()(t, u)
2050 }
2051}
2052
2053impl<T, U> Clone for RcBiConsumer<T, U> {
2054 /// Clones the RcBiConsumer
2055 ///
2056 /// Creates a new RcBiConsumer sharing the underlying function with the
2057 /// original instance.
2058 fn clone(&self) -> Self {
2059 RcBiConsumer {
2060 function: Rc::clone(&self.function),
2061 name: self.name.clone(),
2062 }
2063 }
2064}
2065
2066impl<T, U> fmt::Debug for RcBiConsumer<T, U> {
2067 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2068 f.debug_struct("RcBiConsumer")
2069 .field("name", &self.name)
2070 .field("function", &"<function>")
2071 .finish()
2072 }
2073}
2074
2075impl<T, U> fmt::Display for RcBiConsumer<T, U> {
2076 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2077 match &self.name {
2078 Some(name) => write!(f, "RcBiConsumer({})", name),
2079 None => write!(f, "RcBiConsumer"),
2080 }
2081 }
2082}
2083
2084// =======================================================================
2085// 7. RcConditionalBiConsumer - Rc-based Conditional BiConsumer
2086// =======================================================================
2087
2088/// RcConditionalBiConsumer struct
2089///
2090/// A single-threaded conditional bi-consumer that only executes when a predicate is
2091/// satisfied. Uses `RcBiConsumer` and `RcBiPredicate` for shared ownership within a
2092/// single thread.
2093///
2094/// This type is typically created by calling `RcBiConsumer::when()` and is
2095/// designed to work with the `or_else()` method to create if-then-else logic.
2096///
2097/// # Features
2098///
2099/// - **Shared Ownership**: Cloneable via `Rc`, multiple owners allowed
2100/// - **Single-Threaded**: Not thread-safe, cannot be sent across threads
2101/// - **Conditional Execution**: Only consumes when predicate returns `true`
2102/// - **No Lock Overhead**: More efficient than `ArcConditionalBiConsumer`
2103///
2104/// # Examples
2105///
2106/// ```rust
2107/// use prism3_function::{BiConsumer, RcBiConsumer};
2108/// use std::rc::Rc;
2109/// use std::cell::RefCell;
2110///
2111/// let log = Rc::new(RefCell::new(Vec::new()));
2112/// let l = log.clone();
2113/// let conditional = RcBiConsumer::new(move |x: &i32, y: &i32| {
2114/// l.borrow_mut().push(*x + *y);
2115/// }).when(|x: &i32, y: &i32| *x > 0 && *y > 0);
2116///
2117/// let conditional_clone = conditional.clone();
2118///
2119/// let mut value = 5;
2120/// let mut m = conditional;
2121/// m.accept(&value, &3);
2122/// assert_eq!(*log.borrow(), vec![8]);
2123/// ```
2124///
2125/// # Author
2126///
2127/// Haixing Hu
2128pub struct RcConditionalBiConsumer<T, U> {
2129 consumer: RcBiConsumer<T, U>,
2130 predicate: RcBiPredicate<T, U>,
2131}
2132
2133impl<T, U> BiConsumer<T, U> for RcConditionalBiConsumer<T, U>
2134where
2135 T: 'static,
2136 U: 'static,
2137{
2138 fn accept(&mut self, first: &T, second: &U) {
2139 if self.predicate.test(first, second) {
2140 self.consumer.accept(first, second);
2141 }
2142 }
2143
2144 fn into_box(self) -> BoxBiConsumer<T, U> {
2145 let pred = self.predicate;
2146 let mut consumer = self.consumer;
2147 BoxBiConsumer::new(move |t, u| {
2148 if pred.test(t, u) {
2149 consumer.accept(t, u);
2150 }
2151 })
2152 }
2153
2154 fn into_rc(self) -> RcBiConsumer<T, U> {
2155 let pred = self.predicate;
2156 let mut consumer = self.consumer;
2157 RcBiConsumer::new(move |t, u| {
2158 if pred.test(t, u) {
2159 consumer.accept(t, u);
2160 }
2161 })
2162 }
2163
2164 // do NOT override BiConsumer::into_arc() because RcConditionalBiConsumer is not Send + Sync
2165 // and calling RcConditionalBiConsumer::into_arc() will cause a compile error
2166
2167 fn into_fn(self) -> impl FnMut(&T, &U) {
2168 let pred = self.predicate;
2169 let mut consumer = self.consumer;
2170 move |t: &T, u: &U| {
2171 if pred.test(t, u) {
2172 consumer.accept(t, u);
2173 }
2174 }
2175 }
2176
2177 // Use the default implementation of to_xxx() from BiConsumer
2178}
2179
2180impl<T, U> RcConditionalBiConsumer<T, U>
2181where
2182 T: 'static,
2183 U: 'static,
2184{
2185 /// Adds an else branch (single-threaded shared version)
2186 ///
2187 /// Executes the original consumer when the condition is satisfied, otherwise
2188 /// executes else_consumer.
2189 ///
2190 /// # Parameters
2191 ///
2192 /// * `else_consumer` - The consumer for the else branch. **Note: This parameter
2193 /// is passed by value and will transfer ownership.** If you need to preserve
2194 /// the original consumer, clone it first (if it implements `Clone`). Can be:
2195 /// - A closure: `|x: &T, y: &U|`
2196 /// - An `RcBiConsumer<T, U>`
2197 /// - A `BoxBiConsumer<T, U>`
2198 /// - Any type implementing `BiConsumer<T, U>`
2199 ///
2200 /// # Returns
2201 ///
2202 /// Returns the composed `RcBiConsumer<T, U>`
2203 ///
2204 /// # Examples
2205 ///
2206 /// ## Using a closure (recommended)
2207 ///
2208 /// ```rust
2209 /// use prism3_function::{BiConsumer, RcBiConsumer};
2210 /// use std::rc::Rc;
2211 /// use std::cell::RefCell;
2212 ///
2213 /// let log = Rc::new(RefCell::new(Vec::new()));
2214 /// let l1 = log.clone();
2215 /// let l2 = log.clone();
2216 /// let mut consumer = RcBiConsumer::new(move |x: &i32, y: &i32| {
2217 /// l1.borrow_mut().push(*x + *y);
2218 /// }).when(|x: &i32, y: &i32| *x > 0 && *y > 0)
2219 /// .or_else(move |x: &i32, y: &i32| {
2220 /// l2.borrow_mut().push(*x * *y);
2221 /// });
2222 ///
2223 /// consumer.accept(&5, &3);
2224 /// assert_eq!(*log.borrow(), vec![8]);
2225 ///
2226 /// consumer.accept(&-5, &3);
2227 /// assert_eq!(*log.borrow(), vec![8, -15]);
2228 /// ```
2229 pub fn or_else<C>(&self, else_consumer: C) -> RcBiConsumer<T, U>
2230 where
2231 C: BiConsumer<T, U> + 'static,
2232 {
2233 let pred = self.predicate.clone();
2234 let mut then_cons = self.consumer.clone();
2235 let mut else_cons = else_consumer;
2236
2237 RcBiConsumer::new(move |t: &T, u: &U| {
2238 if pred.test(t, u) {
2239 then_cons.accept(t, u);
2240 } else {
2241 else_cons.accept(t, u);
2242 }
2243 })
2244 }
2245}
2246
2247impl<T, U> Clone for RcConditionalBiConsumer<T, U> {
2248 /// Clones the conditional consumer
2249 ///
2250 /// Creates a new instance that shares the underlying consumer and predicate
2251 /// with the original instance.
2252 fn clone(&self) -> Self {
2253 RcConditionalBiConsumer {
2254 consumer: self.consumer.clone(),
2255 predicate: self.predicate.clone(),
2256 }
2257 }
2258}
2259
2260// =======================================================================
2261// 9. Implement BiConsumer trait for closures
2262// =======================================================================
2263
2264/// Implements BiConsumer for all FnMut(&T, &U)
2265impl<T, U, F> BiConsumer<T, U> for F
2266where
2267 F: FnMut(&T, &U),
2268{
2269 fn accept(&mut self, first: &T, second: &U) {
2270 self(first, second)
2271 }
2272
2273 fn into_box(self) -> BoxBiConsumer<T, U>
2274 where
2275 Self: Sized + 'static,
2276 T: 'static,
2277 U: 'static,
2278 {
2279 BoxBiConsumer::new(self)
2280 }
2281
2282 fn into_rc(self) -> RcBiConsumer<T, U>
2283 where
2284 Self: Sized + 'static,
2285 T: 'static,
2286 U: 'static,
2287 {
2288 RcBiConsumer::new(self)
2289 }
2290
2291 fn into_arc(self) -> ArcBiConsumer<T, U>
2292 where
2293 Self: Sized + Send + 'static,
2294 T: Send + 'static,
2295 U: Send + 'static,
2296 {
2297 ArcBiConsumer::new(self)
2298 }
2299
2300 fn into_fn(self) -> impl FnMut(&T, &U)
2301 where
2302 Self: Sized + 'static,
2303 T: 'static,
2304 U: 'static,
2305 {
2306 self
2307 }
2308
2309 fn to_box(&self) -> BoxBiConsumer<T, U>
2310 where
2311 Self: Sized + Clone + 'static,
2312 T: 'static,
2313 U: 'static,
2314 {
2315 let cloned = self.clone();
2316 BoxBiConsumer::new(cloned)
2317 }
2318
2319 fn to_rc(&self) -> RcBiConsumer<T, U>
2320 where
2321 Self: Sized + Clone + 'static,
2322 T: 'static,
2323 U: 'static,
2324 {
2325 let cloned = self.clone();
2326 RcBiConsumer::new(cloned)
2327 }
2328
2329 fn to_arc(&self) -> ArcBiConsumer<T, U>
2330 where
2331 Self: Sized + Clone + Send + 'static,
2332 T: Send + 'static,
2333 U: Send + 'static,
2334 {
2335 let cloned = self.clone();
2336 ArcBiConsumer::new(cloned)
2337 }
2338
2339 fn to_fn(&self) -> impl FnMut(&T, &U)
2340 where
2341 Self: Sized + Clone + 'static,
2342 T: 'static,
2343 U: 'static,
2344 {
2345 self.clone()
2346 }
2347}
2348
2349// =======================================================================
2350// 10. Provide extension methods for closures
2351// =======================================================================
2352
2353/// Extension trait providing bi-consumer composition methods for closures
2354///
2355/// Provides `and_then` and other composition methods for all closures
2356/// implementing `FnMut(&T, &U)`, enabling direct method chaining on
2357/// closures without explicit wrapper types.
2358///
2359/// # Design Rationale
2360///
2361/// This trait allows closures to be composed naturally using method
2362/// syntax, similar to iterator combinators. Composition methods consume
2363/// the closure and return `BoxBiConsumer<T, U>`, which can be further
2364/// chained.
2365///
2366/// # Features
2367///
2368/// - **Natural Syntax**: Chain operations directly on closures
2369/// - **Returns BoxBiConsumer**: Composition results are
2370/// `BoxBiConsumer<T, U>` for continued chaining
2371/// - **Zero Cost**: No overhead when composing closures
2372/// - **Automatic Implementation**: All `FnMut(&T, &U)` closures get
2373/// these methods automatically
2374///
2375/// # Examples
2376///
2377/// ```rust
2378/// use prism3_function::{BiConsumer, FnBiConsumerOps};
2379/// use std::sync::{Arc, Mutex};
2380///
2381/// let log = Arc::new(Mutex::new(Vec::new()));
2382/// let l1 = log.clone();
2383/// let l2 = log.clone();
2384/// let mut chained = (move |x: &i32, y: &i32| {
2385/// l1.lock().unwrap().push(*x + *y);
2386/// }).and_then(move |x: &i32, y: &i32| {
2387/// l2.lock().unwrap().push(*x * *y);
2388/// });
2389/// chained.accept(&5, &3);
2390/// assert_eq!(*log.lock().unwrap(), vec![8, 15]);
2391/// ```
2392///
2393/// # Author
2394///
2395/// Haixing Hu
2396pub trait FnBiConsumerOps<T, U>: FnMut(&T, &U) + Sized {
2397 /// Chains another consumer in sequence
2398 ///
2399 /// Returns a new consumer executing the current operation first, then
2400 /// the next operation. Consumes the current closure and returns
2401 /// `BoxBiConsumer<T, U>`.
2402 ///
2403 /// # Type Parameters
2404 ///
2405 /// * `C` - The type of the next consumer
2406 ///
2407 /// # Parameters
2408 ///
2409 /// * `next` - The consumer to execute after the current operation. **Note:
2410 /// This parameter is passed by value and will transfer ownership.** If you
2411 /// need to preserve the original consumer, clone it first (if it implements
2412 /// `Clone`). Can be:
2413 /// - A closure: `|x: &T, y: &U|`
2414 /// - A `BoxBiConsumer<T, U>`
2415 /// - An `ArcBiConsumer<T, U>`
2416 /// - An `RcBiConsumer<T, U>`
2417 /// - Any type implementing `BiConsumer<T, U>`
2418 ///
2419 /// # Returns
2420 ///
2421 /// Returns the composed `BoxBiConsumer<T, U>`
2422 ///
2423 /// # Examples
2424 ///
2425 /// ```rust
2426 /// use prism3_function::{BiConsumer, FnBiConsumerOps};
2427 /// use std::sync::{Arc, Mutex};
2428 ///
2429 /// let log = Arc::new(Mutex::new(Vec::new()));
2430 /// let l1 = log.clone();
2431 /// let l2 = log.clone();
2432 /// let mut chained = (move |x: &i32, y: &i32| {
2433 /// l1.lock().unwrap().push(*x + *y);
2434 /// }).and_then(move |x: &i32, y: &i32| {
2435 /// l2.lock().unwrap().push(*x * *y);
2436 /// }).and_then(|x: &i32, y: &i32| println!("Result: {}, {}", x, y));
2437 ///
2438 /// chained.accept(&5, &3); // Prints: Result: 5, 3
2439 /// assert_eq!(*log.lock().unwrap(), vec![8, 15]);
2440 /// ```
2441 fn and_then<C>(self, next: C) -> BoxBiConsumer<T, U>
2442 where
2443 Self: 'static,
2444 C: BiConsumer<T, U> + 'static,
2445 T: 'static,
2446 U: 'static,
2447 {
2448 let mut first = self;
2449 let mut second = next;
2450 BoxBiConsumer::new(move |t, u| {
2451 first(t, u);
2452 second.accept(t, u);
2453 })
2454 }
2455}
2456
2457/// Implements FnBiConsumerOps for all closure types
2458impl<T, U, F> FnBiConsumerOps<T, U> for F where F: FnMut(&T, &U) {}