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    /// Converts to RcReadonlyBiConsumer
139    ///
140    /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
141    /// calling this method.
142    ///
143    /// # Returns
144    ///
145    /// Returns the wrapped `RcReadonlyBiConsumer<T, U>`
146    fn into_rc(self) -> RcReadonlyBiConsumer<T, U>
147    where
148        Self: Sized + 'static,
149        T: 'static,
150        U: 'static;
151
152    /// Converts to ArcReadonlyBiConsumer
153    ///
154    /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
155    /// calling this method.
156    ///
157    /// # Returns
158    ///
159    /// Returns the wrapped `ArcReadonlyBiConsumer<T, U>`
160    fn into_arc(self) -> ArcReadonlyBiConsumer<T, U>
161    where
162        Self: Sized + Send + Sync + 'static,
163        T: Send + Sync + 'static,
164        U: Send + Sync + 'static;
165
166    /// Converts readonly bi-consumer to a closure
167    ///
168    /// **⚠️ Consumes `self`**: Original consumer becomes unavailable after
169    /// calling this method.
170    ///
171    /// Converts the readonly bi-consumer to a closure usable with standard
172    /// library methods requiring `Fn`.
173    ///
174    /// # Returns
175    ///
176    /// Returns a closure implementing `Fn(&T, &U)`
177    ///
178    /// # Examples
179    ///
180    /// ```rust
181    /// use prism3_function::{ReadonlyBiConsumer, BoxReadonlyBiConsumer};
182    ///
183    /// let consumer = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
184    ///     println!("Sum: {}", x + y);
185    /// });
186    /// let func = consumer.into_fn();
187    /// func(&5, &3);
188    /// ```
189    fn into_fn(self) -> impl Fn(&T, &U)
190    where
191        Self: Sized + 'static,
192        T: 'static,
193        U: 'static;
194}
195
196// =======================================================================
197// 2. BoxReadonlyBiConsumer - Single Ownership Implementation
198// =======================================================================
199
200/// BoxReadonlyBiConsumer struct
201///
202/// A readonly bi-consumer implementation based on `Box<dyn Fn(&T, &U)>`
203/// for single ownership scenarios.
204///
205/// # Features
206///
207/// - **Single Ownership**: Not cloneable, ownership moves on use
208/// - **Zero Overhead**: No reference counting or locking
209/// - **Fully Immutable**: Neither modifies itself nor input values
210/// - **No Interior Mutability**: No need for Mutex or RefCell
211///
212/// # Use Cases
213///
214/// Choose `BoxReadonlyBiConsumer` when:
215/// - The readonly bi-consumer is used only once or in a linear flow
216/// - No need to share the consumer across contexts
217/// - Pure observation operations like logging
218///
219/// # Examples
220///
221/// ```rust
222/// use prism3_function::{ReadonlyBiConsumer, BoxReadonlyBiConsumer};
223///
224/// let consumer = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
225///     println!("Sum: {}", x + y);
226/// });
227/// consumer.accept(&5, &3);
228/// ```
229///
230/// # Author
231///
232/// Haixing Hu
233pub struct BoxReadonlyBiConsumer<T, U> {
234    function: Box<ReadonlyBiConsumerFn<T, U>>,
235    name: Option<String>,
236}
237
238impl<T, U> BoxReadonlyBiConsumer<T, U>
239where
240    T: 'static,
241    U: 'static,
242{
243    /// Creates a new BoxReadonlyBiConsumer
244    ///
245    /// # Type Parameters
246    ///
247    /// * `F` - The closure type
248    ///
249    /// # Parameters
250    ///
251    /// * `f` - The closure to wrap
252    ///
253    /// # Returns
254    ///
255    /// Returns a new `BoxReadonlyBiConsumer<T, U>` instance
256    ///
257    /// # Examples
258    ///
259    /// ```rust
260    /// use prism3_function::{ReadonlyBiConsumer, BoxReadonlyBiConsumer};
261    ///
262    /// let consumer = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
263    ///     println!("Product: {}", x * y);
264    /// });
265    /// consumer.accept(&5, &3);
266    /// ```
267    pub fn new<F>(f: F) -> Self
268    where
269        F: Fn(&T, &U) + 'static,
270    {
271        BoxReadonlyBiConsumer {
272            function: Box::new(f),
273            name: None,
274        }
275    }
276
277    /// Gets the name of the consumer
278    pub fn name(&self) -> Option<&str> {
279        self.name.as_deref()
280    }
281
282    /// Sets the name of the consumer
283    pub fn set_name(&mut self, name: impl Into<String>) {
284        self.name = Some(name.into());
285    }
286
287    /// Chains another readonly bi-consumer in sequence
288    ///
289    /// Returns a new consumer executing the current operation first, then
290    /// the next operation. Consumes self.
291    ///
292    /// # Type Parameters
293    ///
294    /// * `C` - The type of the next consumer
295    ///
296    /// # Parameters
297    ///
298    /// * `next` - The consumer to execute after the current operation. **Note:
299    ///   This parameter is passed by value and will transfer ownership.** If you
300    ///   need to preserve the original consumer, clone it first (if it implements
301    ///   `Clone`). Can be:
302    ///   - A closure: `|x: &T, y: &U|`
303    ///   - A `BoxReadonlyBiConsumer<T, U>`
304    ///   - An `RcReadonlyBiConsumer<T, U>`
305    ///   - An `ArcReadonlyBiConsumer<T, U>`
306    ///   - Any type implementing `ReadonlyBiConsumer<T, U>`
307    ///
308    /// # Returns
309    ///
310    /// Returns a new composed `BoxReadonlyBiConsumer<T, U>`
311    ///
312    /// # Examples
313    ///
314    /// ## Direct value passing (ownership transfer)
315    ///
316    /// ```rust
317    /// use prism3_function::{ReadonlyBiConsumer, BoxReadonlyBiConsumer};
318    ///
319    /// let first = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
320    ///     println!("First: {}, {}", x, y);
321    /// });
322    /// let second = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
323    ///     println!("Second: sum = {}", x + y);
324    /// });
325    ///
326    /// // second is moved here
327    /// let chained = first.and_then(second);
328    /// chained.accept(&5, &3);
329    /// // second.accept(&2, &3); // Would not compile - moved
330    /// ```
331    ///
332    /// ## Preserving original with clone
333    ///
334    /// ```rust
335    /// use prism3_function::{ReadonlyBiConsumer, BoxReadonlyBiConsumer, RcReadonlyBiConsumer};
336    ///
337    /// let first = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
338    ///     println!("First: {}, {}", x, y);
339    /// });
340    /// let second = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
341    ///     println!("Second: sum = {}", x + y);
342    /// });
343    ///
344    /// // Clone to preserve original
345    /// let chained = first.and_then(second.clone());
346    /// chained.accept(&5, &3);
347    ///
348    /// // Original still usable
349    /// second.accept(&2, &3);
350    /// ```
351    pub fn and_then<C>(self, next: C) -> Self
352    where
353        C: ReadonlyBiConsumer<T, U> + 'static,
354    {
355        let first = self.function;
356        let second = next;
357        BoxReadonlyBiConsumer::new(move |t, u| {
358            first(t, u);
359            second.accept(t, u);
360        })
361    }
362
363    /// Creates a no-op readonly bi-consumer
364    ///
365    /// # Returns
366    ///
367    /// Returns a no-op readonly bi-consumer
368    pub fn noop() -> Self {
369        BoxReadonlyBiConsumer::new(|_, _| {})
370    }
371}
372
373impl<T, U> ReadonlyBiConsumer<T, U> for BoxReadonlyBiConsumer<T, U> {
374    fn accept(&self, first: &T, second: &U) {
375        (self.function)(first, second)
376    }
377
378    fn into_box(self) -> BoxReadonlyBiConsumer<T, U>
379    where
380        T: 'static,
381        U: 'static,
382    {
383        self
384    }
385
386    fn into_rc(self) -> RcReadonlyBiConsumer<T, U>
387    where
388        T: 'static,
389        U: 'static,
390    {
391        let func = self.function;
392        RcReadonlyBiConsumer::new(move |t, u| func(t, u))
393    }
394
395    fn into_arc(self) -> ArcReadonlyBiConsumer<T, U>
396    where
397        T: Send + Sync + 'static,
398        U: Send + Sync + 'static,
399    {
400        panic!(
401            "Cannot convert BoxReadonlyBiConsumer to \
402                ArcReadonlyBiConsumer: inner function may not be \
403                Send+Sync"
404        )
405    }
406
407    fn into_fn(self) -> impl Fn(&T, &U)
408    where
409        T: 'static,
410        U: 'static,
411    {
412        self.function
413    }
414}
415
416impl<T, U> fmt::Debug for BoxReadonlyBiConsumer<T, U> {
417    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
418        f.debug_struct("BoxReadonlyBiConsumer")
419            .field("name", &self.name)
420            .field("function", &"<function>")
421            .finish()
422    }
423}
424
425impl<T, U> fmt::Display for BoxReadonlyBiConsumer<T, U> {
426    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
427        match &self.name {
428            Some(name) => write!(f, "BoxReadonlyBiConsumer({})", name),
429            None => write!(f, "BoxReadonlyBiConsumer"),
430        }
431    }
432}
433
434// =======================================================================
435// 3. ArcReadonlyBiConsumer - Thread-Safe Shared Ownership
436// =======================================================================
437
438/// ArcReadonlyBiConsumer struct
439///
440/// A readonly bi-consumer implementation based on
441/// `Arc<dyn Fn(&T, &U) + Send + Sync>` for thread-safe shared ownership
442/// scenarios. No need for Mutex because operations are readonly.
443///
444/// # Features
445///
446/// - **Shared Ownership**: Cloneable via `Arc`, multiple owners allowed
447/// - **Thread-Safe**: Implements `Send + Sync`, safe for concurrent use
448/// - **No Locks**: Because readonly, no need for Mutex protection
449/// - **Non-Consuming API**: `and_then` borrows `&self`, original remains
450///   usable
451///
452/// # Use Cases
453///
454/// Choose `ArcReadonlyBiConsumer` when:
455/// - Need to share readonly bi-consumer across multiple threads
456/// - Pure observation operations like logging, monitoring, notifications
457/// - Need high-concurrency reads without lock overhead
458///
459/// # Performance Advantages
460///
461/// Compared to `ArcBiConsumer`, `ArcReadonlyBiConsumer` has no Mutex
462/// locking overhead, resulting in better performance in high-concurrency
463/// scenarios.
464///
465/// # Examples
466///
467/// ```rust
468/// use prism3_function::{ReadonlyBiConsumer, ArcReadonlyBiConsumer};
469///
470/// let consumer = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
471///     println!("Sum: {}", x + y);
472/// });
473/// let clone = consumer.clone();
474///
475/// consumer.accept(&5, &3);
476/// clone.accept(&10, &20);
477/// ```
478///
479/// # Author
480///
481/// Haixing Hu
482pub struct ArcReadonlyBiConsumer<T, U> {
483    function: Arc<ThreadSafeReadonlyBiConsumerFn<T, U>>,
484    name: Option<String>,
485}
486
487impl<T, U> ArcReadonlyBiConsumer<T, U>
488where
489    T: Send + Sync + 'static,
490    U: Send + Sync + 'static,
491{
492    /// Creates a new ArcReadonlyBiConsumer
493    ///
494    /// # Type Parameters
495    ///
496    /// * `F` - The closure type
497    ///
498    /// # Parameters
499    ///
500    /// * `f` - The closure to wrap
501    ///
502    /// # Returns
503    ///
504    /// Returns a new `ArcReadonlyBiConsumer<T, U>` instance
505    ///
506    /// # Examples
507    ///
508    /// ```rust
509    /// use prism3_function::{ReadonlyBiConsumer, ArcReadonlyBiConsumer};
510    ///
511    /// let consumer = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
512    ///     println!("Product: {}", x * y);
513    /// });
514    /// consumer.accept(&5, &3);
515    /// ```
516    pub fn new<F>(f: F) -> Self
517    where
518        F: Fn(&T, &U) + Send + Sync + 'static,
519    {
520        ArcReadonlyBiConsumer {
521            function: Arc::new(f),
522            name: None,
523        }
524    }
525
526    /// Gets the name of the consumer
527    pub fn name(&self) -> Option<&str> {
528        self.name.as_deref()
529    }
530
531    /// Sets the name of the consumer
532    pub fn set_name(&mut self, name: impl Into<String>) {
533        self.name = Some(name.into());
534    }
535
536    /// Converts to a closure (without consuming self)
537    ///
538    /// Creates a new closure that calls the underlying function via Arc.
539    ///
540    /// # Returns
541    ///
542    /// Returns a closure implementing `Fn(&T, &U)`
543    ///
544    /// # Examples
545    ///
546    /// ```rust
547    /// use prism3_function::{ReadonlyBiConsumer, ArcReadonlyBiConsumer};
548    ///
549    /// let consumer = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
550    ///     println!("Sum: {}", x + y);
551    /// });
552    ///
553    /// let func = consumer.to_fn();
554    /// func(&5, &3);
555    /// ```
556    pub fn to_fn(&self) -> impl Fn(&T, &U)
557    where
558        T: 'static,
559        U: 'static,
560    {
561        let func = Arc::clone(&self.function);
562        move |t: &T, u: &U| {
563            func(t, u);
564        }
565    }
566
567    /// Chains another ArcReadonlyBiConsumer in sequence
568    ///
569    /// Returns a new consumer executing the current operation first, then
570    /// the next operation. Borrows &self, does not consume the original
571    /// consumer.
572    ///
573    /// # Parameters
574    ///
575    /// * `next` - The consumer to execute after the current operation. **Note:
576    ///   This parameter is passed by reference, so the original consumer remains
577    ///   usable.** Can be:
578    ///   - An `ArcReadonlyBiConsumer<T, U>` (passed by reference)
579    ///   - Any type implementing `ReadonlyBiConsumer<T, U> + Send + Sync`
580    ///
581    /// # Returns
582    ///
583    /// Returns a new composed `ArcReadonlyBiConsumer<T, U>`
584    ///
585    /// # Examples
586    ///
587    /// ```rust
588    /// use prism3_function::{ReadonlyBiConsumer, ArcReadonlyBiConsumer};
589    ///
590    /// let first = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
591    ///     println!("First: {}, {}", x, y);
592    /// });
593    /// let second = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
594    ///     println!("Second: sum = {}", x + y);
595    /// });
596    ///
597    /// // second is passed by reference, so it remains usable
598    /// let chained = first.and_then(&second);
599    ///
600    /// // first and second still usable after chaining
601    /// chained.accept(&5, &3);
602    /// first.accept(&2, &3); // Still usable
603    /// second.accept(&7, &8); // Still usable
604    /// ```
605    pub fn and_then(&self, next: &ArcReadonlyBiConsumer<T, U>) -> ArcReadonlyBiConsumer<T, U> {
606        let first = Arc::clone(&self.function);
607        let second = Arc::clone(&next.function);
608        ArcReadonlyBiConsumer {
609            function: Arc::new(move |t: &T, u: &U| {
610                first(t, u);
611                second(t, u);
612            }),
613            name: None,
614        }
615    }
616}
617
618impl<T, U> ReadonlyBiConsumer<T, U> for ArcReadonlyBiConsumer<T, U> {
619    fn accept(&self, first: &T, second: &U) {
620        (self.function)(first, second)
621    }
622
623    fn into_box(self) -> BoxReadonlyBiConsumer<T, U>
624    where
625        T: 'static,
626        U: 'static,
627    {
628        let func = self.function;
629        BoxReadonlyBiConsumer::new(move |t, u| func(t, u))
630    }
631
632    fn into_rc(self) -> RcReadonlyBiConsumer<T, U>
633    where
634        T: 'static,
635        U: 'static,
636    {
637        let func = self.function;
638        RcReadonlyBiConsumer::new(move |t, u| func(t, u))
639    }
640
641    fn into_arc(self) -> ArcReadonlyBiConsumer<T, U>
642    where
643        T: Send + Sync + 'static,
644        U: Send + Sync + 'static,
645    {
646        self
647    }
648
649    fn into_fn(self) -> impl Fn(&T, &U)
650    where
651        T: 'static,
652        U: 'static,
653    {
654        let func = self.function;
655        move |t: &T, u: &U| {
656            func(t, u);
657        }
658    }
659}
660
661impl<T, U> Clone for ArcReadonlyBiConsumer<T, U> {
662    /// Clones the ArcReadonlyBiConsumer
663    ///
664    /// Creates a new ArcReadonlyBiConsumer sharing the underlying function
665    /// with the original instance.
666    fn clone(&self) -> Self {
667        Self {
668            function: Arc::clone(&self.function),
669            name: self.name.clone(),
670        }
671    }
672}
673
674impl<T, U> fmt::Debug for ArcReadonlyBiConsumer<T, U> {
675    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
676        f.debug_struct("ArcReadonlyBiConsumer")
677            .field("name", &self.name)
678            .field("function", &"<function>")
679            .finish()
680    }
681}
682
683impl<T, U> fmt::Display for ArcReadonlyBiConsumer<T, U> {
684    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
685        match &self.name {
686            Some(name) => write!(f, "ArcReadonlyBiConsumer({})", name),
687            None => write!(f, "ArcReadonlyBiConsumer"),
688        }
689    }
690}
691
692// =======================================================================
693// 4. RcReadonlyBiConsumer - Single-Threaded Shared Ownership
694// =======================================================================
695
696/// RcReadonlyBiConsumer struct
697///
698/// A readonly bi-consumer implementation based on `Rc<dyn Fn(&T, &U)>`
699/// for single-threaded shared ownership scenarios. No need for RefCell
700/// because operations are readonly.
701///
702/// # Features
703///
704/// - **Shared Ownership**: Cloneable via `Rc`, multiple owners allowed
705/// - **Single-Threaded**: Not thread-safe, cannot send across threads
706/// - **No Interior Mutability Overhead**: No need for RefCell because
707///   readonly
708/// - **Non-Consuming API**: `and_then` borrows `&self`, original remains
709///   usable
710///
711/// # Use Cases
712///
713/// Choose `RcReadonlyBiConsumer` when:
714/// - Need to share readonly bi-consumer within a single thread
715/// - Pure observation operations, performance critical
716/// - Single-threaded UI framework event handling
717///
718/// # Performance Advantages
719///
720/// `RcReadonlyBiConsumer` has neither Arc's atomic operation overhead nor
721/// RefCell's runtime borrow checking overhead, making it the best
722/// performing among the three readonly bi-consumer types.
723///
724/// # Examples
725///
726/// ```rust
727/// use prism3_function::{ReadonlyBiConsumer, RcReadonlyBiConsumer};
728///
729/// let consumer = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
730///     println!("Sum: {}", x + y);
731/// });
732/// let clone = consumer.clone();
733///
734/// consumer.accept(&5, &3);
735/// clone.accept(&10, &20);
736/// ```
737///
738/// # Author
739///
740/// Haixing Hu
741pub struct RcReadonlyBiConsumer<T, U> {
742    function: Rc<ReadonlyBiConsumerFn<T, U>>,
743    name: Option<String>,
744}
745
746impl<T, U> RcReadonlyBiConsumer<T, U>
747where
748    T: 'static,
749    U: 'static,
750{
751    /// Creates a new RcReadonlyBiConsumer
752    ///
753    /// # Type Parameters
754    ///
755    /// * `F` - The closure type
756    ///
757    /// # Parameters
758    ///
759    /// * `f` - The closure to wrap
760    ///
761    /// # Returns
762    ///
763    /// Returns a new `RcReadonlyBiConsumer<T, U>` instance
764    ///
765    /// # Examples
766    ///
767    /// ```rust
768    /// use prism3_function::{ReadonlyBiConsumer, RcReadonlyBiConsumer};
769    ///
770    /// let consumer = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
771    ///     println!("Product: {}", x * y);
772    /// });
773    /// consumer.accept(&5, &3);
774    /// ```
775    pub fn new<F>(f: F) -> Self
776    where
777        F: Fn(&T, &U) + 'static,
778    {
779        RcReadonlyBiConsumer {
780            function: Rc::new(f),
781            name: None,
782        }
783    }
784
785    /// Gets the name of the consumer
786    pub fn name(&self) -> Option<&str> {
787        self.name.as_deref()
788    }
789
790    /// Sets the name of the consumer
791    pub fn set_name(&mut self, name: impl Into<String>) {
792        self.name = Some(name.into());
793    }
794
795    /// Converts to a closure (without consuming self)
796    ///
797    /// Creates a new closure that calls the underlying function via Rc.
798    ///
799    /// # Returns
800    ///
801    /// Returns a closure implementing `Fn(&T, &U)`
802    ///
803    /// # Examples
804    ///
805    /// ```rust
806    /// use prism3_function::{ReadonlyBiConsumer, RcReadonlyBiConsumer};
807    ///
808    /// let consumer = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
809    ///     println!("Sum: {}", x + y);
810    /// });
811    ///
812    /// let func = consumer.to_fn();
813    /// func(&5, &3);
814    /// ```
815    pub fn to_fn(&self) -> impl Fn(&T, &U)
816    where
817        T: 'static,
818        U: 'static,
819    {
820        let func = Rc::clone(&self.function);
821        move |t: &T, u: &U| {
822            func(t, u);
823        }
824    }
825
826    /// Chains another RcReadonlyBiConsumer in sequence
827    ///
828    /// Returns a new consumer executing the current operation first, then
829    /// the next operation. Borrows &self, does not consume the original
830    /// consumer.
831    ///
832    /// # Parameters
833    ///
834    /// * `next` - The consumer to execute after the current operation. **Note:
835    ///   This parameter is passed by reference, so the original consumer remains
836    ///   usable.** Can be:
837    ///   - An `RcReadonlyBiConsumer<T, U>` (passed by reference)
838    ///   - Any type implementing `ReadonlyBiConsumer<T, U>`
839    ///
840    /// # Returns
841    ///
842    /// Returns a new composed `RcReadonlyBiConsumer<T, U>`
843    ///
844    /// # Examples
845    ///
846    /// ```rust
847    /// use prism3_function::{ReadonlyBiConsumer, RcReadonlyBiConsumer};
848    ///
849    /// let first = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
850    ///     println!("First: {}, {}", x, y);
851    /// });
852    /// let second = RcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
853    ///     println!("Second: sum = {}", x + y);
854    /// });
855    ///
856    /// // second is passed by reference, so it remains usable
857    /// let chained = first.and_then(&second);
858    ///
859    /// // first and second still usable after chaining
860    /// chained.accept(&5, &3);
861    /// first.accept(&2, &3); // Still usable
862    /// second.accept(&7, &8); // Still usable
863    /// ```
864    pub fn and_then(&self, next: &RcReadonlyBiConsumer<T, U>) -> RcReadonlyBiConsumer<T, U> {
865        let first = Rc::clone(&self.function);
866        let second = Rc::clone(&next.function);
867        RcReadonlyBiConsumer {
868            function: Rc::new(move |t: &T, u: &U| {
869                first(t, u);
870                second(t, u);
871            }),
872            name: None,
873        }
874    }
875}
876
877impl<T, U> ReadonlyBiConsumer<T, U> for RcReadonlyBiConsumer<T, U> {
878    fn accept(&self, first: &T, second: &U) {
879        (self.function)(first, second)
880    }
881
882    fn into_box(self) -> BoxReadonlyBiConsumer<T, U>
883    where
884        T: 'static,
885        U: 'static,
886    {
887        let func = self.function;
888        BoxReadonlyBiConsumer::new(move |t, u| func(t, u))
889    }
890
891    fn into_rc(self) -> RcReadonlyBiConsumer<T, U>
892    where
893        T: 'static,
894        U: 'static,
895    {
896        self
897    }
898
899    fn into_arc(self) -> ArcReadonlyBiConsumer<T, U>
900    where
901        T: Send + Sync + 'static,
902        U: Send + Sync + 'static,
903    {
904        panic!(
905            "Cannot convert RcReadonlyBiConsumer to \
906                ArcReadonlyBiConsumer (not Send+Sync)"
907        )
908    }
909
910    fn into_fn(self) -> impl Fn(&T, &U)
911    where
912        T: 'static,
913        U: 'static,
914    {
915        let func = self.function;
916        move |t: &T, u: &U| {
917            func(t, u);
918        }
919    }
920}
921
922impl<T, U> Clone for RcReadonlyBiConsumer<T, U> {
923    /// Clones the RcReadonlyBiConsumer
924    ///
925    /// Creates a new RcReadonlyBiConsumer sharing the underlying function
926    /// with the original instance.
927    fn clone(&self) -> Self {
928        Self {
929            function: Rc::clone(&self.function),
930            name: self.name.clone(),
931        }
932    }
933}
934
935impl<T, U> fmt::Debug for RcReadonlyBiConsumer<T, U> {
936    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
937        f.debug_struct("RcReadonlyBiConsumer")
938            .field("name", &self.name)
939            .field("function", &"<function>")
940            .finish()
941    }
942}
943
944impl<T, U> fmt::Display for RcReadonlyBiConsumer<T, U> {
945    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
946        match &self.name {
947            Some(name) => write!(f, "RcReadonlyBiConsumer({})", name),
948            None => write!(f, "RcReadonlyBiConsumer"),
949        }
950    }
951}
952
953// =======================================================================
954// 5. Implement ReadonlyBiConsumer trait for closures
955// =======================================================================
956
957/// Implements ReadonlyBiConsumer for all Fn(&T, &U)
958impl<T, U, F> ReadonlyBiConsumer<T, U> for F
959where
960    F: Fn(&T, &U),
961{
962    fn accept(&self, first: &T, second: &U) {
963        self(first, second)
964    }
965
966    fn into_box(self) -> BoxReadonlyBiConsumer<T, U>
967    where
968        Self: Sized + 'static,
969        T: 'static,
970        U: 'static,
971    {
972        BoxReadonlyBiConsumer::new(self)
973    }
974
975    fn into_rc(self) -> RcReadonlyBiConsumer<T, U>
976    where
977        Self: Sized + 'static,
978        T: 'static,
979        U: 'static,
980    {
981        RcReadonlyBiConsumer::new(self)
982    }
983
984    fn into_arc(self) -> ArcReadonlyBiConsumer<T, U>
985    where
986        Self: Sized + Send + Sync + 'static,
987        T: Send + Sync + 'static,
988        U: Send + Sync + 'static,
989    {
990        ArcReadonlyBiConsumer::new(self)
991    }
992
993    fn into_fn(self) -> impl Fn(&T, &U)
994    where
995        Self: Sized + 'static,
996        T: 'static,
997        U: 'static,
998    {
999        self
1000    }
1001}
1002
1003// =======================================================================
1004// 6. Provide extension methods for closures
1005// =======================================================================
1006
1007/// Extension trait providing readonly bi-consumer composition methods for
1008/// closures
1009///
1010/// Provides `and_then` and other composition methods for all closures
1011/// implementing `Fn(&T, &U)`, enabling direct method chaining on closures
1012/// without explicit wrapper types.
1013///
1014/// # Features
1015///
1016/// - **Natural Syntax**: Chain operations directly on closures
1017/// - **Returns BoxReadonlyBiConsumer**: Composition results can be
1018///   further chained
1019/// - **Zero Cost**: No overhead when composing closures
1020/// - **Automatic Implementation**: All `Fn(&T, &U)` closures get these
1021///   methods automatically
1022///
1023/// # Examples
1024///
1025/// ```rust
1026/// use prism3_function::{ReadonlyBiConsumer, FnReadonlyBiConsumerOps};
1027///
1028/// let chained = (|x: &i32, y: &i32| {
1029///     println!("First: {}, {}", x, y);
1030/// }).and_then(|x: &i32, y: &i32| {
1031///     println!("Second: sum = {}", x + y);
1032/// });
1033/// chained.accept(&5, &3);
1034/// ```
1035///
1036/// # Author
1037///
1038/// Haixing Hu
1039pub trait FnReadonlyBiConsumerOps<T, U>: Fn(&T, &U) + Sized {
1040    /// Chains another readonly bi-consumer in sequence
1041    ///
1042    /// Returns a new consumer executing the current operation first, then
1043    /// the next operation. Consumes the current closure and returns
1044    /// `BoxReadonlyBiConsumer<T, U>`.
1045    ///
1046    /// # Type Parameters
1047    ///
1048    /// * `C` - The type of the next consumer
1049    ///
1050    /// # Parameters
1051    ///
1052    /// * `next` - The consumer to execute after the current operation
1053    ///
1054    /// # Returns
1055    ///
1056    /// Returns the composed `BoxReadonlyBiConsumer<T, U>`
1057    ///
1058    /// # Examples
1059    ///
1060    /// ```rust
1061    /// use prism3_function::{ReadonlyBiConsumer, FnReadonlyBiConsumerOps};
1062    ///
1063    /// let chained = (|x: &i32, y: &i32| {
1064    ///     println!("First: {}, {}", x, y);
1065    /// }).and_then(|x: &i32, y: &i32| {
1066    ///     println!("Second: sum = {}", x + y);
1067    /// }).and_then(|x: &i32, y: &i32| {
1068    ///     println!("Third: product = {}", x * y);
1069    /// });
1070    ///
1071    /// chained.accept(&5, &3);
1072    /// ```
1073    fn and_then<C>(self, next: C) -> BoxReadonlyBiConsumer<T, U>
1074    where
1075        Self: 'static,
1076        C: ReadonlyBiConsumer<T, U> + 'static,
1077        T: 'static,
1078        U: 'static,
1079    {
1080        let first = self;
1081        let second = next;
1082        BoxReadonlyBiConsumer::new(move |t, u| {
1083            first(t, u);
1084            second.accept(t, u);
1085        })
1086    }
1087}
1088
1089/// Implements FnReadonlyBiConsumerOps for all closure types
1090impl<T, U, F> FnReadonlyBiConsumerOps<T, U> for F where F: Fn(&T, &U) {}