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) {}