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