prism3_function/
readonly_bi_consumer.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025.
4 *    3-Prism Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # ReadonlyBiConsumer Types
10//!
11//! Provides readonly bi-consumer interface implementations for operations
12//! that accept two input parameters without modifying their own state or
13//! the input values.
14//!
15//! This module provides a unified `ReadonlyBiConsumer` trait and three
16//! concrete implementations based on different ownership models:
17//!
18//! - **`BoxReadonlyBiConsumer<T, U>`**: Box-based single ownership
19//! - **`ArcReadonlyBiConsumer<T, U>`**: Arc-based thread-safe shared
20//!   ownership
21//! - **`RcReadonlyBiConsumer<T, U>`**: Rc-based single-threaded shared
22//!   ownership
23//!
24//! # Design Philosophy
25//!
26//! ReadonlyBiConsumer uses `Fn(&T, &U)` semantics: neither modifies its
27//! own state nor the input values. Suitable for pure observation, logging,
28//! and notification scenarios with two parameters. Compared to BiConsumer,
29//! ReadonlyBiConsumer does not require interior mutability
30//! (Mutex/RefCell), thus more efficient and easier to share.
31//!
32//! # Author
33//!
34//! Haixing Hu
35
36use std::fmt;
37use std::rc::Rc;
38use std::sync::Arc;
39
40// ==========================================================================
41// Type Aliases
42// ==========================================================================
43
44/// Type alias for readonly bi-consumer function signature.
45type ReadonlyBiConsumerFn<T, U> = dyn Fn(&T, &U);
46
47/// Type alias for thread-safe readonly bi-consumer function signature.
48type ThreadSafeReadonlyBiConsumerFn<T, U> = dyn Fn(&T, &U) + Send + Sync;
49
50// =======================================================================
51// 1. ReadonlyBiConsumer Trait - Unified Interface
52// =======================================================================
53
54/// ReadonlyBiConsumer trait - Unified readonly bi-consumer interface
55///
56/// Defines core behavior for all readonly bi-consumer types. Unlike
57/// `BiConsumer`, `ReadonlyBiConsumer` neither modifies its own state nor
58/// the input values, making it a fully immutable operation.
59///
60/// # Automatic Implementations
61///
62/// - All closures implementing `Fn(&T, &U)`
63/// - `BoxReadonlyBiConsumer<T, U>`, `ArcReadonlyBiConsumer<T, U>`,
64///   `RcReadonlyBiConsumer<T, U>`
65///
66/// # Features
67///
68/// - **Unified Interface**: All readonly bi-consumer types share the same
69///   `accept` method signature
70/// - **Automatic Implementation**: Closures automatically implement this
71///   trait with zero overhead
72/// - **Type Conversions**: Easy conversion between ownership models
73/// - **Generic Programming**: Write functions accepting any readonly
74///   bi-consumer type
75/// - **No Interior Mutability**: No need for Mutex or RefCell, more
76///   efficient
77///
78/// # Examples
79///
80/// ```rust
81/// use prism3_function::{ReadonlyBiConsumer, BoxReadonlyBiConsumer};
82///
83/// fn apply_consumer<C: ReadonlyBiConsumer<i32, i32>>(
84///     consumer: &C,
85///     a: &i32,
86///     b: &i32
87/// ) {
88///     consumer.accept(a, b);
89/// }
90///
91/// let box_con = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
92///     println!("Sum: {}", x + y);
93/// });
94/// apply_consumer(&box_con, &5, &3);
95/// ```
96///
97/// # Author
98///
99/// Haixing Hu
100pub trait ReadonlyBiConsumer<T, U> {
101    /// Performs the readonly consumption operation
102    ///
103    /// Executes an operation on the given two references. The operation
104    /// typically reads input values or produces side effects, but neither
105    /// modifies the input values nor the consumer's own state.
106    ///
107    /// # Parameters
108    ///
109    /// * `first` - Reference to the first value to consume
110    /// * `second` - Reference to the second value to consume
111    ///
112    /// # Examples
113    ///
114    /// ```rust
115    /// use prism3_function::{ReadonlyBiConsumer, BoxReadonlyBiConsumer};
116    ///
117    /// let consumer = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
118    ///     println!("Values: {}, {}", x, y);
119    /// });
120    /// consumer.accept(&5, &3);
121    /// ```
122    fn accept(&self, first: &T, second: &U);
123
124    /// Converts to BoxReadonlyBiConsumer
125    ///
126    /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
127    /// calling this method.
128    ///
129    /// # Returns
130    ///
131    /// Returns the wrapped `BoxReadonlyBiConsumer<T, U>`
132    fn into_box(self) -> BoxReadonlyBiConsumer<T, U>
133    where
134        Self: Sized + 'static,
135        T: 'static,
136        U: 'static,
137    {
138        BoxReadonlyBiConsumer::new(move |t, u| self.accept(t, u))
139    }
140
141    /// Converts to RcReadonlyBiConsumer
142    ///
143    /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
144    /// calling this method.
145    ///
146    /// # Returns
147    ///
148    /// Returns the wrapped `RcReadonlyBiConsumer<T, U>`
149    fn into_rc(self) -> RcReadonlyBiConsumer<T, U>
150    where
151        Self: Sized + 'static,
152        T: 'static,
153        U: 'static,
154    {
155        RcReadonlyBiConsumer::new(move |t, u| self.accept(t, u))
156    }
157
158    /// Converts to ArcReadonlyBiConsumer
159    ///
160    /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
161    /// calling this method.
162    ///
163    /// # Returns
164    ///
165    /// Returns the wrapped `ArcReadonlyBiConsumer<T, U>`
166    fn into_arc(self) -> ArcReadonlyBiConsumer<T, U>
167    where
168        Self: Sized + Send + Sync + 'static,
169        T: Send + Sync + 'static,
170        U: Send + Sync + 'static,
171    {
172        ArcReadonlyBiConsumer::new(move |t, u| self.accept(t, u))
173    }
174
175    /// Converts readonly bi-consumer to a closure
176    ///
177    /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
178    /// calling this method.
179    ///
180    /// Converts the readonly bi-consumer to a closure usable with standard
181    /// library methods requiring `Fn`.
182    ///
183    /// # Returns
184    ///
185    /// Returns a closure implementing `Fn(&T, &U)`
186    ///
187    /// # Examples
188    ///
189    /// ```rust
190    /// use prism3_function::{ReadonlyBiConsumer, BoxReadonlyBiConsumer};
191    ///
192    /// let consumer = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
193    ///     println!("Sum: {}", x + y);
194    /// });
195    /// let func = consumer.into_fn();
196    /// func(&5, &3);
197    /// ```
198    fn into_fn(self) -> impl Fn(&T, &U)
199    where
200        Self: Sized + 'static,
201        T: 'static,
202        U: 'static,
203    {
204        move |t, u| self.accept(t, u)
205    }
206
207    /// Converts to BoxReadonlyBiConsumer (without consuming self)
208    ///
209    /// Creates a new `BoxReadonlyBiConsumer` by cloning the current consumer.
210    /// The original consumer remains usable after this call.
211    ///
212    /// # Returns
213    ///
214    /// Returns a new `BoxReadonlyBiConsumer<T, U>`
215    ///
216    /// # Examples
217    ///
218    /// ```rust
219    /// use prism3_function::{ReadonlyBiConsumer, RcReadonlyBiConsumer};
220    ///
221    /// let consumer = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
222    ///     println!("Sum: {}", x + y);
223    /// });
224    /// let box_consumer = consumer.to_box();
225    /// box_consumer.accept(&5, &3);
226    /// // Original consumer still usable
227    /// consumer.accept(&10, &20);
228    /// ```
229    fn to_box(&self) -> BoxReadonlyBiConsumer<T, U>
230    where
231        Self: Clone + 'static,
232        T: 'static,
233        U: 'static,
234    {
235        self.clone().into_box()
236    }
237
238    /// Converts to RcReadonlyBiConsumer (without consuming self)
239    ///
240    /// Creates a new `RcReadonlyBiConsumer` by cloning the current consumer.
241    /// The original consumer remains usable after this call.
242    ///
243    /// # Returns
244    ///
245    /// Returns a new `RcReadonlyBiConsumer<T, U>`
246    ///
247    /// # Examples
248    ///
249    /// ```rust
250    /// use prism3_function::{ReadonlyBiConsumer, ArcReadonlyBiConsumer};
251    ///
252    /// let consumer = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
253    ///     println!("Sum: {}", x + y);
254    /// });
255    /// let rc_consumer = consumer.to_rc();
256    /// rc_consumer.accept(&5, &3);
257    /// // Original consumer still usable
258    /// consumer.accept(&10, &20);
259    /// ```
260    fn to_rc(&self) -> RcReadonlyBiConsumer<T, U>
261    where
262        Self: Clone + 'static,
263        T: 'static,
264        U: 'static,
265    {
266        self.clone().into_rc()
267    }
268
269    /// Converts to ArcReadonlyBiConsumer (without consuming self)
270    ///
271    /// Creates a new `ArcReadonlyBiConsumer` by cloning the current consumer.
272    /// The original consumer remains usable after this call.
273    ///
274    /// # Returns
275    ///
276    /// Returns a new `ArcReadonlyBiConsumer<T, U>`
277    ///
278    /// # Examples
279    ///
280    /// ```rust
281    /// use prism3_function::{ReadonlyBiConsumer, RcReadonlyBiConsumer};
282    ///
283    /// let consumer = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
284    ///     println!("Sum: {}", x + y);
285    /// });
286    /// // Note: This will only compile if the closure is Send + Sync
287    /// // For demonstration, we use a simple closure
288    /// let arc_consumer = consumer.to_arc();
289    /// arc_consumer.accept(&5, &3);
290    /// ```
291    fn to_arc(&self) -> ArcReadonlyBiConsumer<T, U>
292    where
293        Self: Clone + Send + Sync + 'static,
294        T: Send + Sync + 'static,
295        U: Send + Sync + 'static,
296    {
297        self.clone().into_arc()
298    }
299
300    /// Converts to a closure (without consuming self)
301    ///
302    /// Creates a new closure by cloning the current consumer.
303    /// The original consumer remains usable after this call.
304    ///
305    /// # Returns
306    ///
307    /// Returns a closure implementing `Fn(&T, &U)`
308    ///
309    /// # Examples
310    ///
311    /// ```rust
312    /// use prism3_function::{ReadonlyBiConsumer, RcReadonlyBiConsumer};
313    ///
314    /// let consumer = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
315    ///     println!("Sum: {}", x + y);
316    /// });
317    /// let func = consumer.to_fn();
318    /// func(&5, &3);
319    /// // Original consumer still usable
320    /// consumer.accept(&10, &20);
321    /// ```
322    fn to_fn(&self) -> impl Fn(&T, &U)
323    where
324        Self: Clone + 'static,
325        T: 'static,
326        U: 'static,
327    {
328        self.clone().into_fn()
329    }
330}
331
332// =======================================================================
333// 2. BoxReadonlyBiConsumer - Single Ownership Implementation
334// =======================================================================
335
336/// BoxReadonlyBiConsumer struct
337///
338/// A readonly bi-consumer implementation based on `Box<dyn Fn(&T, &U)>`
339/// for single ownership scenarios.
340///
341/// # Features
342///
343/// - **Single Ownership**: Not cloneable, ownership moves on use
344/// - **Zero Overhead**: No reference counting or locking
345/// - **Fully Immutable**: Neither modifies itself nor input values
346/// - **No Interior Mutability**: No need for Mutex or RefCell
347///
348/// # Use Cases
349///
350/// Choose `BoxReadonlyBiConsumer` when:
351/// - The readonly bi-consumer is used only once or in a linear flow
352/// - No need to share the consumer across contexts
353/// - Pure observation operations like logging
354///
355/// # Examples
356///
357/// ```rust
358/// use prism3_function::{ReadonlyBiConsumer, BoxReadonlyBiConsumer};
359///
360/// let consumer = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
361///     println!("Sum: {}", x + y);
362/// });
363/// consumer.accept(&5, &3);
364/// ```
365///
366/// # Author
367///
368/// Haixing Hu
369pub struct BoxReadonlyBiConsumer<T, U> {
370    function: Box<ReadonlyBiConsumerFn<T, U>>,
371    name: Option<String>,
372}
373
374impl<T, U> BoxReadonlyBiConsumer<T, U>
375where
376    T: 'static,
377    U: 'static,
378{
379    /// Creates a new BoxReadonlyBiConsumer
380    ///
381    /// # Type Parameters
382    ///
383    /// * `F` - The closure type
384    ///
385    /// # Parameters
386    ///
387    /// * `f` - The closure to wrap
388    ///
389    /// # Returns
390    ///
391    /// Returns a new `BoxReadonlyBiConsumer<T, U>` instance
392    ///
393    /// # Examples
394    ///
395    /// ```rust
396    /// use prism3_function::{ReadonlyBiConsumer, BoxReadonlyBiConsumer};
397    ///
398    /// let consumer = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
399    ///     println!("Product: {}", x * y);
400    /// });
401    /// consumer.accept(&5, &3);
402    /// ```
403    pub fn new<F>(f: F) -> Self
404    where
405        F: Fn(&T, &U) + 'static,
406    {
407        BoxReadonlyBiConsumer {
408            function: Box::new(f),
409            name: None,
410        }
411    }
412
413    /// Creates a no-op readonly bi-consumer
414    ///
415    /// # Returns
416    ///
417    /// Returns a no-op readonly bi-consumer
418    pub fn noop() -> Self {
419        BoxReadonlyBiConsumer::new(|_, _| {})
420    }
421
422    /// Gets the name of the consumer
423    pub fn name(&self) -> Option<&str> {
424        self.name.as_deref()
425    }
426
427    /// Sets the name of the consumer
428    pub fn set_name(&mut self, name: impl Into<String>) {
429        self.name = Some(name.into());
430    }
431
432    /// Chains another readonly bi-consumer in sequence
433    ///
434    /// Returns a new consumer executing the current operation first, then
435    /// the next operation. Consumes self.
436    ///
437    /// # Type Parameters
438    ///
439    /// * `C` - The type of the next consumer
440    ///
441    /// # Parameters
442    ///
443    /// * `next` - The consumer to execute after the current operation. **Note:
444    ///   This parameter is passed by value and will transfer ownership.** If you
445    ///   need to preserve the original consumer, clone it first (if it implements
446    ///   `Clone`). Can be:
447    ///   - A closure: `|x: &T, y: &U|`
448    ///   - A `BoxReadonlyBiConsumer<T, U>`
449    ///   - An `RcReadonlyBiConsumer<T, U>`
450    ///   - An `ArcReadonlyBiConsumer<T, U>`
451    ///   - Any type implementing `ReadonlyBiConsumer<T, U>`
452    ///
453    /// # Returns
454    ///
455    /// Returns a new composed `BoxReadonlyBiConsumer<T, U>`
456    ///
457    /// # Examples
458    ///
459    /// ## Direct value passing (ownership transfer)
460    ///
461    /// ```rust
462    /// use prism3_function::{ReadonlyBiConsumer, BoxReadonlyBiConsumer};
463    ///
464    /// let first = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
465    ///     println!("First: {}, {}", x, y);
466    /// });
467    /// let second = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
468    ///     println!("Second: sum = {}", x + y);
469    /// });
470    ///
471    /// // second is moved here
472    /// let chained = first.and_then(second);
473    /// chained.accept(&5, &3);
474    /// // second.accept(&2, &3); // Would not compile - moved
475    /// ```
476    ///
477    /// ## Preserving original with clone
478    ///
479    /// ```rust
480    /// use prism3_function::{ReadonlyBiConsumer, BoxReadonlyBiConsumer, RcReadonlyBiConsumer};
481    ///
482    /// let first = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
483    ///     println!("First: {}, {}", x, y);
484    /// });
485    /// let second = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
486    ///     println!("Second: sum = {}", x + y);
487    /// });
488    ///
489    /// // Clone to preserve original
490    /// let chained = first.and_then(second.clone());
491    /// chained.accept(&5, &3);
492    ///
493    /// // Original still usable
494    /// second.accept(&2, &3);
495    /// ```
496    pub fn and_then<C>(self, next: C) -> Self
497    where
498        C: ReadonlyBiConsumer<T, U> + 'static,
499    {
500        let first = self.function;
501        let second = next;
502        BoxReadonlyBiConsumer::new(move |t, u| {
503            first(t, u);
504            second.accept(t, u);
505        })
506    }
507}
508
509impl<T, U> ReadonlyBiConsumer<T, U> for BoxReadonlyBiConsumer<T, U> {
510    fn accept(&self, first: &T, second: &U) {
511        (self.function)(first, second)
512    }
513
514    fn into_box(self) -> BoxReadonlyBiConsumer<T, U>
515    where
516        T: 'static,
517        U: 'static,
518    {
519        self
520    }
521
522    fn into_rc(self) -> RcReadonlyBiConsumer<T, U>
523    where
524        T: 'static,
525        U: 'static,
526    {
527        RcReadonlyBiConsumer::new(move |t, u| (self.function)(t, u))
528    }
529
530    // do NOT override ReadonlyConsumer::into_arc() because ArcReadonlyBiConsumer is not Send + Sync
531    // and calling ArcReadonlyBiConsumer::into_arc() will cause a compile error
532
533    fn into_fn(self) -> impl Fn(&T, &U)
534    where
535        T: 'static,
536        U: 'static,
537    {
538        self.function
539    }
540}
541
542impl<T, U> fmt::Debug for BoxReadonlyBiConsumer<T, U> {
543    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
544        f.debug_struct("BoxReadonlyBiConsumer")
545            .field("name", &self.name)
546            .field("function", &"<function>")
547            .finish()
548    }
549}
550
551impl<T, U> fmt::Display for BoxReadonlyBiConsumer<T, U> {
552    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
553        match &self.name {
554            Some(name) => write!(f, "BoxReadonlyBiConsumer({})", name),
555            None => write!(f, "BoxReadonlyBiConsumer"),
556        }
557    }
558}
559
560// =======================================================================
561// 3. ArcReadonlyBiConsumer - Thread-Safe Shared Ownership
562// =======================================================================
563
564/// ArcReadonlyBiConsumer struct
565///
566/// A readonly bi-consumer implementation based on
567/// `Arc<dyn Fn(&T, &U) + Send + Sync>` for thread-safe shared ownership
568/// scenarios. No need for Mutex because operations are readonly.
569///
570/// # Features
571///
572/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
573/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
574/// - **No Locks**: Because readonly, no need for Mutex protection
575/// - **Non-Consuming API**: `and_then` borrows `&self`, original remains
576///   usable
577///
578/// # Use Cases
579///
580/// Choose `ArcReadonlyBiConsumer` when:
581/// - Need to share readonly bi-consumer across multiple threads
582/// - Pure observation operations like logging, monitoring, notifications
583/// - Need high-concurrency reads without lock overhead
584///
585/// # Performance Advantages
586///
587/// Compared to `ArcBiConsumer`, `ArcReadonlyBiConsumer` has no Mutex
588/// locking overhead, resulting in better performance in high-concurrency
589/// scenarios.
590///
591/// # Examples
592///
593/// ```rust
594/// use prism3_function::{ReadonlyBiConsumer, ArcReadonlyBiConsumer};
595///
596/// let consumer = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
597///     println!("Sum: {}", x + y);
598/// });
599/// let clone = consumer.clone();
600///
601/// consumer.accept(&5, &3);
602/// clone.accept(&10, &20);
603/// ```
604///
605/// # Author
606///
607/// Haixing Hu
608pub struct ArcReadonlyBiConsumer<T, U> {
609    function: Arc<ThreadSafeReadonlyBiConsumerFn<T, U>>,
610    name: Option<String>,
611}
612
613impl<T, U> ArcReadonlyBiConsumer<T, U>
614where
615    T: Send + Sync + 'static,
616    U: Send + Sync + 'static,
617{
618    /// Creates a new ArcReadonlyBiConsumer
619    ///
620    /// # Type Parameters
621    ///
622    /// * `F` - The closure type
623    ///
624    /// # Parameters
625    ///
626    /// * `f` - The closure to wrap
627    ///
628    /// # Returns
629    ///
630    /// Returns a new `ArcReadonlyBiConsumer<T, U>` instance
631    ///
632    /// # Examples
633    ///
634    /// ```rust
635    /// use prism3_function::{ReadonlyBiConsumer, ArcReadonlyBiConsumer};
636    ///
637    /// let consumer = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
638    ///     println!("Product: {}", x * y);
639    /// });
640    /// consumer.accept(&5, &3);
641    /// ```
642    pub fn new<F>(f: F) -> Self
643    where
644        F: Fn(&T, &U) + Send + Sync + 'static,
645    {
646        ArcReadonlyBiConsumer {
647            function: Arc::new(f),
648            name: None,
649        }
650    }
651
652    /// Creates a no-op readonly bi-consumer
653    ///
654    /// # Returns
655    ///
656    /// Returns a no-op readonly bi-consumer
657    pub fn noop() -> Self {
658        ArcReadonlyBiConsumer::new(|_, _| {})
659    }
660
661    /// Gets the name of the consumer
662    pub fn name(&self) -> Option<&str> {
663        self.name.as_deref()
664    }
665
666    /// Sets the name of the consumer
667    pub fn set_name(&mut self, name: impl Into<String>) {
668        self.name = Some(name.into());
669    }
670
671    /// Chains another ArcReadonlyBiConsumer in sequence
672    ///
673    /// Returns a new consumer executing the current operation first, then
674    /// the next operation. Borrows &self, does not consume the original
675    /// consumer.
676    ///
677    /// # Parameters
678    ///
679    /// * `next` - The consumer to execute after the current operation. **Note:
680    ///   This parameter is passed by reference, so the original consumer remains
681    ///   usable.** Can be:
682    ///   - An `ArcReadonlyBiConsumer<T, U>` (passed by reference)
683    ///   - Any type implementing `ReadonlyBiConsumer<T, U> + Send + Sync`
684    ///
685    /// # Returns
686    ///
687    /// Returns a new composed `ArcReadonlyBiConsumer<T, U>`
688    ///
689    /// # Examples
690    ///
691    /// ```rust
692    /// use prism3_function::{ReadonlyBiConsumer, ArcReadonlyBiConsumer};
693    ///
694    /// let first = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
695    ///     println!("First: {}, {}", x, y);
696    /// });
697    /// let second = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
698    ///     println!("Second: sum = {}", x + y);
699    /// });
700    ///
701    /// // second is passed by reference, so it remains usable
702    /// let chained = first.and_then(&second);
703    ///
704    /// // first and second still usable after chaining
705    /// chained.accept(&5, &3);
706    /// first.accept(&2, &3); // Still usable
707    /// second.accept(&7, &8); // Still usable
708    /// ```
709    pub fn and_then(&self, next: &ArcReadonlyBiConsumer<T, U>) -> ArcReadonlyBiConsumer<T, U> {
710        let first = Arc::clone(&self.function);
711        let second = Arc::clone(&next.function);
712        ArcReadonlyBiConsumer {
713            function: Arc::new(move |t: &T, u: &U| {
714                first(t, u);
715                second(t, u);
716            }),
717            name: None,
718        }
719    }
720}
721
722impl<T, U> ReadonlyBiConsumer<T, U> for ArcReadonlyBiConsumer<T, U> {
723    fn accept(&self, first: &T, second: &U) {
724        (self.function)(first, second)
725    }
726
727    fn into_box(self) -> BoxReadonlyBiConsumer<T, U>
728    where
729        T: 'static,
730        U: 'static,
731    {
732        BoxReadonlyBiConsumer::new(move |t, u| (self.function)(t, u))
733    }
734
735    fn into_rc(self) -> RcReadonlyBiConsumer<T, U>
736    where
737        T: 'static,
738        U: 'static,
739    {
740        RcReadonlyBiConsumer::new(move |t, u| (self.function)(t, u))
741    }
742
743    fn into_arc(self) -> ArcReadonlyBiConsumer<T, U>
744    where
745        T: Send + Sync + 'static,
746        U: Send + Sync + 'static,
747    {
748        self
749    }
750
751    fn into_fn(self) -> impl Fn(&T, &U)
752    where
753        T: 'static,
754        U: 'static,
755    {
756        move |t, u| (self.function)(t, u)
757    }
758
759    fn to_box(&self) -> BoxReadonlyBiConsumer<T, U>
760    where
761        T: 'static,
762        U: 'static,
763    {
764        let self_fn = self.function.clone();
765        BoxReadonlyBiConsumer::new(move |t, u| self_fn(t, u))
766    }
767
768    fn to_rc(&self) -> RcReadonlyBiConsumer<T, U>
769    where
770        T: 'static,
771        U: 'static,
772    {
773        let self_fn = self.function.clone();
774        RcReadonlyBiConsumer::new(move |t, u| self_fn(t, u))
775    }
776
777    fn to_arc(&self) -> ArcReadonlyBiConsumer<T, U>
778    where
779        T: Send + Sync + 'static,
780        U: Send + Sync + 'static,
781    {
782        self.clone()
783    }
784
785    fn to_fn(&self) -> impl Fn(&T, &U)
786    where
787        T: 'static,
788        U: 'static,
789    {
790        let self_fn = self.function.clone();
791        move |t, u| self_fn(t, u)
792    }
793}
794
795impl<T, U> Clone for ArcReadonlyBiConsumer<T, U> {
796    /// Clones the ArcReadonlyBiConsumer
797    ///
798    /// Creates a new ArcReadonlyBiConsumer sharing the underlying function
799    /// with the original instance.
800    fn clone(&self) -> Self {
801        Self {
802            function: Arc::clone(&self.function),
803            name: self.name.clone(),
804        }
805    }
806}
807
808impl<T, U> fmt::Debug for ArcReadonlyBiConsumer<T, U> {
809    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
810        f.debug_struct("ArcReadonlyBiConsumer")
811            .field("name", &self.name)
812            .field("function", &"<function>")
813            .finish()
814    }
815}
816
817impl<T, U> fmt::Display for ArcReadonlyBiConsumer<T, U> {
818    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
819        match &self.name {
820            Some(name) => write!(f, "ArcReadonlyBiConsumer({})", name),
821            None => write!(f, "ArcReadonlyBiConsumer"),
822        }
823    }
824}
825
826// =======================================================================
827// 4. RcReadonlyBiConsumer - Single-Threaded Shared Ownership
828// =======================================================================
829
830/// RcReadonlyBiConsumer struct
831///
832/// A readonly bi-consumer implementation based on `Rc<dyn Fn(&T, &U)>`
833/// for single-threaded shared ownership scenarios. No need for RefCell
834/// because operations are readonly.
835///
836/// # Features
837///
838/// - **Shared Ownership**: Cloneable via `Rc`, multiple owners allowed
839/// - **Single-Threaded**: Not thread-safe, cannot send across threads
840/// - **No Interior Mutability Overhead**: No need for RefCell because
841///   readonly
842/// - **Non-Consuming API**: `and_then` borrows `&self`, original remains
843///   usable
844///
845/// # Use Cases
846///
847/// Choose `RcReadonlyBiConsumer` when:
848/// - Need to share readonly bi-consumer within a single thread
849/// - Pure observation operations, performance critical
850/// - Single-threaded UI framework event handling
851///
852/// # Performance Advantages
853///
854/// `RcReadonlyBiConsumer` has neither Arc's atomic operation overhead nor
855/// RefCell's runtime borrow checking overhead, making it the best
856/// performing among the three readonly bi-consumer types.
857///
858/// # Examples
859///
860/// ```rust
861/// use prism3_function::{ReadonlyBiConsumer, RcReadonlyBiConsumer};
862///
863/// let consumer = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
864///     println!("Sum: {}", x + y);
865/// });
866/// let clone = consumer.clone();
867///
868/// consumer.accept(&5, &3);
869/// clone.accept(&10, &20);
870/// ```
871///
872/// # Author
873///
874/// Haixing Hu
875pub struct RcReadonlyBiConsumer<T, U> {
876    function: Rc<ReadonlyBiConsumerFn<T, U>>,
877    name: Option<String>,
878}
879
880impl<T, U> RcReadonlyBiConsumer<T, U>
881where
882    T: 'static,
883    U: 'static,
884{
885    /// Creates a new RcReadonlyBiConsumer
886    ///
887    /// # Type Parameters
888    ///
889    /// * `F` - The closure type
890    ///
891    /// # Parameters
892    ///
893    /// * `f` - The closure to wrap
894    ///
895    /// # Returns
896    ///
897    /// Returns a new `RcReadonlyBiConsumer<T, U>` instance
898    ///
899    /// # Examples
900    ///
901    /// ```rust
902    /// use prism3_function::{ReadonlyBiConsumer, RcReadonlyBiConsumer};
903    ///
904    /// let consumer = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
905    ///     println!("Product: {}", x * y);
906    /// });
907    /// consumer.accept(&5, &3);
908    /// ```
909    pub fn new<F>(f: F) -> Self
910    where
911        F: Fn(&T, &U) + 'static,
912    {
913        RcReadonlyBiConsumer {
914            function: Rc::new(f),
915            name: None,
916        }
917    }
918
919    /// Creates a no-op readonly bi-consumer
920    ///
921    /// # Returns
922    ///
923    /// Returns a no-op readonly bi-consumer
924    pub fn noop() -> Self {
925        RcReadonlyBiConsumer::new(|_, _| {})
926    }
927
928    /// Gets the name of the consumer
929    pub fn name(&self) -> Option<&str> {
930        self.name.as_deref()
931    }
932
933    /// Sets the name of the consumer
934    pub fn set_name(&mut self, name: impl Into<String>) {
935        self.name = Some(name.into());
936    }
937
938    /// Chains another RcReadonlyBiConsumer in sequence
939    ///
940    /// Returns a new consumer executing the current operation first, then
941    /// the next operation. Borrows &self, does not consume the original
942    /// consumer.
943    ///
944    /// # Parameters
945    ///
946    /// * `next` - The consumer to execute after the current operation. **Note:
947    ///   This parameter is passed by reference, so the original consumer remains
948    ///   usable.** Can be:
949    ///   - An `RcReadonlyBiConsumer<T, U>` (passed by reference)
950    ///   - Any type implementing `ReadonlyBiConsumer<T, U>`
951    ///
952    /// # Returns
953    ///
954    /// Returns a new composed `RcReadonlyBiConsumer<T, U>`
955    ///
956    /// # Examples
957    ///
958    /// ```rust
959    /// use prism3_function::{ReadonlyBiConsumer, RcReadonlyBiConsumer};
960    ///
961    /// let first = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
962    ///     println!("First: {}, {}", x, y);
963    /// });
964    /// let second = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
965    ///     println!("Second: sum = {}", x + y);
966    /// });
967    ///
968    /// // second is passed by reference, so it remains usable
969    /// let chained = first.and_then(&second);
970    ///
971    /// // first and second still usable after chaining
972    /// chained.accept(&5, &3);
973    /// first.accept(&2, &3); // Still usable
974    /// second.accept(&7, &8); // Still usable
975    /// ```
976    pub fn and_then(&self, next: &RcReadonlyBiConsumer<T, U>) -> RcReadonlyBiConsumer<T, U> {
977        let first = Rc::clone(&self.function);
978        let second = Rc::clone(&next.function);
979        RcReadonlyBiConsumer {
980            function: Rc::new(move |t: &T, u: &U| {
981                first(t, u);
982                second(t, u);
983            }),
984            name: None,
985        }
986    }
987}
988
989impl<T, U> ReadonlyBiConsumer<T, U> for RcReadonlyBiConsumer<T, U> {
990    fn accept(&self, first: &T, second: &U) {
991        (self.function)(first, second)
992    }
993
994    fn into_box(self) -> BoxReadonlyBiConsumer<T, U>
995    where
996        T: 'static,
997        U: 'static,
998    {
999        BoxReadonlyBiConsumer::new(move |t, u| (self.function)(t, u))
1000    }
1001
1002    fn into_rc(self) -> RcReadonlyBiConsumer<T, U>
1003    where
1004        T: 'static,
1005        U: 'static,
1006    {
1007        self
1008    }
1009
1010    // do NOT override ReadonlyBiConsumer::into_arc() because RcReadonlyBiConsumer is not Send + Sync
1011    // and calling RcReadonlyBiConsumer::into_arc() will cause a compile error
1012
1013    fn into_fn(self) -> impl Fn(&T, &U)
1014    where
1015        T: 'static,
1016        U: 'static,
1017    {
1018        move |t, u| (self.function)(t, u)
1019    }
1020
1021    fn to_box(&self) -> BoxReadonlyBiConsumer<T, U>
1022    where
1023        T: 'static,
1024        U: 'static,
1025    {
1026        let self_fn = self.function.clone();
1027        BoxReadonlyBiConsumer::new(move |t, u| self_fn(t, u))
1028    }
1029
1030    fn to_rc(&self) -> RcReadonlyBiConsumer<T, U>
1031    where
1032        T: 'static,
1033        U: 'static,
1034    {
1035        self.clone()
1036    }
1037
1038    // do NOT override ReadonlyBiConsumer::to_arc() because RcReadonlyBiConsumer is not Send + Sync
1039    // and calling RcReadonlyBiConsumer::to_arc() will cause a compile error
1040
1041    fn to_fn(&self) -> impl Fn(&T, &U)
1042    where
1043        T: 'static,
1044        U: 'static,
1045    {
1046        let self_fn = self.function.clone();
1047        move |t, u| self_fn(t, u)
1048    }
1049}
1050
1051impl<T, U> Clone for RcReadonlyBiConsumer<T, U> {
1052    /// Clones the RcReadonlyBiConsumer
1053    ///
1054    /// Creates a new RcReadonlyBiConsumer sharing the underlying function
1055    /// with the original instance.
1056    fn clone(&self) -> Self {
1057        Self {
1058            function: Rc::clone(&self.function),
1059            name: self.name.clone(),
1060        }
1061    }
1062}
1063
1064impl<T, U> fmt::Debug for RcReadonlyBiConsumer<T, U> {
1065    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1066        f.debug_struct("RcReadonlyBiConsumer")
1067            .field("name", &self.name)
1068            .field("function", &"<function>")
1069            .finish()
1070    }
1071}
1072
1073impl<T, U> fmt::Display for RcReadonlyBiConsumer<T, U> {
1074    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1075        match &self.name {
1076            Some(name) => write!(f, "RcReadonlyBiConsumer({})", name),
1077            None => write!(f, "RcReadonlyBiConsumer"),
1078        }
1079    }
1080}
1081
1082// =======================================================================
1083// 5. Implement ReadonlyBiConsumer trait for closures
1084// =======================================================================
1085
1086/// Implements ReadonlyBiConsumer for all Fn(&T, &U)
1087impl<T, U, F> ReadonlyBiConsumer<T, U> for F
1088where
1089    F: Fn(&T, &U),
1090{
1091    fn accept(&self, first: &T, second: &U) {
1092        self(first, second)
1093    }
1094
1095    fn into_box(self) -> BoxReadonlyBiConsumer<T, U>
1096    where
1097        Self: Sized + 'static,
1098        T: 'static,
1099        U: 'static,
1100    {
1101        BoxReadonlyBiConsumer::new(self)
1102    }
1103
1104    fn into_rc(self) -> RcReadonlyBiConsumer<T, U>
1105    where
1106        Self: Sized + 'static,
1107        T: 'static,
1108        U: 'static,
1109    {
1110        RcReadonlyBiConsumer::new(self)
1111    }
1112
1113    fn into_arc(self) -> ArcReadonlyBiConsumer<T, U>
1114    where
1115        Self: Sized + Send + Sync + 'static,
1116        T: Send + Sync + 'static,
1117        U: Send + Sync + 'static,
1118    {
1119        ArcReadonlyBiConsumer::new(self)
1120    }
1121
1122    fn into_fn(self) -> impl Fn(&T, &U)
1123    where
1124        Self: Sized + 'static,
1125        T: 'static,
1126        U: 'static,
1127    {
1128        self
1129    }
1130
1131    fn to_box(&self) -> BoxReadonlyBiConsumer<T, U>
1132    where
1133        Self: Clone + 'static,
1134        T: 'static,
1135        U: 'static,
1136    {
1137        let self_fn = self.clone();
1138        BoxReadonlyBiConsumer::new(move |t, u| self_fn(t, u))
1139    }
1140
1141    fn to_rc(&self) -> RcReadonlyBiConsumer<T, U>
1142    where
1143        Self: Clone + 'static,
1144        T: 'static,
1145        U: 'static,
1146    {
1147        let self_fn = self.clone();
1148        RcReadonlyBiConsumer::new(move |t, u| self_fn(t, u))
1149    }
1150
1151    fn to_arc(&self) -> ArcReadonlyBiConsumer<T, U>
1152    where
1153        Self: Clone + Send + Sync + 'static,
1154        T: Send + Sync + 'static,
1155        U: Send + Sync + 'static,
1156    {
1157        let self_fn = self.clone();
1158        ArcReadonlyBiConsumer::new(move |t, u| self_fn(t, u))
1159    }
1160
1161    fn to_fn(&self) -> impl Fn(&T, &U)
1162    where
1163        Self: Clone + 'static,
1164        T: 'static,
1165        U: 'static,
1166    {
1167        self.clone()
1168    }
1169}
1170
1171// =======================================================================
1172// 6. Provide extension methods for closures
1173// =======================================================================
1174
1175/// Extension trait providing readonly bi-consumer composition methods for
1176/// closures
1177///
1178/// Provides `and_then` and other composition methods for all closures
1179/// implementing `Fn(&T, &U)`, enabling direct method chaining on closures
1180/// without explicit wrapper types.
1181///
1182/// # Features
1183///
1184/// - **Natural Syntax**: Chain operations directly on closures
1185/// - **Returns BoxReadonlyBiConsumer**: Composition results can be
1186///   further chained
1187/// - **Zero Cost**: No overhead when composing closures
1188/// - **Automatic Implementation**: All `Fn(&T, &U)` closures get these
1189///   methods automatically
1190///
1191/// # Examples
1192///
1193/// ```rust
1194/// use prism3_function::{ReadonlyBiConsumer, FnReadonlyBiConsumerOps};
1195///
1196/// let chained = (|x: &i32, y: &i32| {
1197///     println!("First: {}, {}", x, y);
1198/// }).and_then(|x: &i32, y: &i32| {
1199///     println!("Second: sum = {}", x + y);
1200/// });
1201/// chained.accept(&5, &3);
1202/// ```
1203///
1204/// # Author
1205///
1206/// Haixing Hu
1207pub trait FnReadonlyBiConsumerOps<T, U>: Fn(&T, &U) + Sized {
1208    /// Chains another readonly bi-consumer in sequence
1209    ///
1210    /// Returns a new consumer executing the current operation first, then
1211    /// the next operation. Consumes the current closure and returns
1212    /// `BoxReadonlyBiConsumer<T, U>`.
1213    ///
1214    /// # Type Parameters
1215    ///
1216    /// * `C` - The type of the next consumer
1217    ///
1218    /// # Parameters
1219    ///
1220    /// * `next` - The consumer to execute after the current operation
1221    ///
1222    /// # Returns
1223    ///
1224    /// Returns the composed `BoxReadonlyBiConsumer<T, U>`
1225    ///
1226    /// # Examples
1227    ///
1228    /// ```rust
1229    /// use prism3_function::{ReadonlyBiConsumer, FnReadonlyBiConsumerOps};
1230    ///
1231    /// let chained = (|x: &i32, y: &i32| {
1232    ///     println!("First: {}, {}", x, y);
1233    /// }).and_then(|x: &i32, y: &i32| {
1234    ///     println!("Second: sum = {}", x + y);
1235    /// }).and_then(|x: &i32, y: &i32| {
1236    ///     println!("Third: product = {}", x * y);
1237    /// });
1238    ///
1239    /// chained.accept(&5, &3);
1240    /// ```
1241    fn and_then<C>(self, next: C) -> BoxReadonlyBiConsumer<T, U>
1242    where
1243        Self: 'static,
1244        C: ReadonlyBiConsumer<T, U> + 'static,
1245        T: 'static,
1246        U: 'static,
1247    {
1248        let first = self;
1249        let second = next;
1250        BoxReadonlyBiConsumer::new(move |t, u| {
1251            first(t, u);
1252            second.accept(t, u);
1253        })
1254    }
1255}
1256
1257/// Implements FnReadonlyBiConsumerOps for all closure types
1258impl<T, U, F> FnReadonlyBiConsumerOps<T, U> for F where F: Fn(&T, &U) {}