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