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