ArcReadonlyBiConsumer

Struct ArcReadonlyBiConsumer 

Source
pub struct ArcReadonlyBiConsumer<T, U> { /* private fields */ }
Expand description

ArcReadonlyBiConsumer struct

A readonly bi-consumer implementation based on Arc<dyn Fn(&T, &U) + Send + Sync> for thread-safe shared ownership scenarios. No need for Mutex because operations are readonly.

§Features

  • Shared Ownership: Cloneable via Arc, multiple owners allowed
  • Thread-Safe: Implements Send + Sync, safe for concurrent use
  • No Locks: Because readonly, no need for Mutex protection
  • Non-Consuming API: and_then borrows &self, original remains usable

§Use Cases

Choose ArcReadonlyBiConsumer when:

  • Need to share readonly bi-consumer across multiple threads
  • Pure observation operations like logging, monitoring, notifications
  • Need high-concurrency reads without lock overhead

§Performance Advantages

Compared to ArcBiConsumer, ArcReadonlyBiConsumer has no Mutex locking overhead, resulting in better performance in high-concurrency scenarios.

§Examples

use prism3_function::{ReadonlyBiConsumer, ArcReadonlyBiConsumer};

let consumer = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
    println!("Sum: {}", x + y);
});
let clone = consumer.clone();

consumer.accept(&5, &3);
clone.accept(&10, &20);

§Author

Haixing Hu

Implementations§

Source§

impl<T, U> ArcReadonlyBiConsumer<T, U>
where T: Send + Sync + 'static, U: Send + Sync + 'static,

Source

pub fn new<F>(f: F) -> Self
where F: Fn(&T, &U) + Send + Sync + 'static,

Creates a new ArcReadonlyBiConsumer

§Type Parameters
  • F - The closure type
§Parameters
  • f - The closure to wrap
§Returns

Returns a new ArcReadonlyBiConsumer<T, U> instance

§Examples
use prism3_function::{ReadonlyBiConsumer, ArcReadonlyBiConsumer};

let consumer = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
    println!("Product: {}", x * y);
});
consumer.accept(&5, &3);
Examples found in repository?
examples/readonly_bi_consumer_demo.rs (lines 51-54)
22fn main() {
23    println!("=== ReadonlyBiConsumer Demo ===\n");
24
25    // 1. BoxReadonlyBiConsumer - Single ownership
26    println!("1. BoxReadonlyBiConsumer - Single ownership:");
27    let box_consumer = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
28        println!("  Values: x={}, y={}, sum={}", x, y, x + y);
29    });
30    box_consumer.accept(&10, &5);
31    println!();
32
33    // 2. Method chaining with BoxReadonlyBiConsumer
34    println!("2. BoxReadonlyBiConsumer with method chaining:");
35    let chained = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
36        println!("  First operation: x={}, y={}", x, y);
37    })
38    .and_then(|x: &i32, y: &i32| {
39        println!("  Second operation: sum={}", x + y);
40    })
41    .and_then(|x: &i32, y: &i32| {
42        println!("  Third operation: product={}", x * y);
43    });
44    chained.accept(&5, &3);
45    println!();
46
47    // 3. ArcReadonlyBiConsumer - Thread-safe shared ownership
48    println!("3. ArcReadonlyBiConsumer - Thread-safe shared ownership:");
49    let counter = Arc::new(AtomicUsize::new(0));
50    let c = counter.clone();
51    let arc_consumer = ArcReadonlyBiConsumer::new(move |x: &i32, y: &i32| {
52        c.fetch_add(1, Ordering::SeqCst);
53        println!("  Thread {:?}: sum={}", thread::current().id(), x + y);
54    });
55
56    let consumer1 = arc_consumer.clone();
57    let consumer2 = arc_consumer.clone();
58
59    let handle1 = thread::spawn(move || {
60        consumer1.accept(&10, &5);
61    });
62
63    let handle2 = thread::spawn(move || {
64        consumer2.accept(&20, &8);
65    });
66
67    handle1.join().unwrap();
68    handle2.join().unwrap();
69    println!("  Total calls: {}\n", counter.load(Ordering::SeqCst));
70
71    // 4. RcReadonlyBiConsumer - Single-threaded shared ownership
72    println!("4. RcReadonlyBiConsumer - Single-threaded shared ownership:");
73    let counter = Rc::new(std::cell::Cell::new(0));
74    let c = counter.clone();
75    let rc_consumer = RcReadonlyBiConsumer::new(move |x: &i32, y: &i32| {
76        c.set(c.get() + 1);
77        println!("  Call {}: sum={}", c.get(), x + y);
78    });
79
80    let clone1 = rc_consumer.clone();
81    let clone2 = rc_consumer.clone();
82
83    clone1.accept(&5, &3);
84    clone2.accept(&7, &2);
85    println!("  Total calls: {}\n", counter.get());
86
87    // 5. Working with closures directly
88    println!("5. Working with closures directly:");
89    let closure = |x: &i32, y: &i32| {
90        println!("  x={}, y={}, product={}", x, y, x * y);
91    };
92    closure.accept(&10, &20);
93    println!();
94
95    // 6. Pure observation - logging
96    println!("6. Pure observation - logging:");
97    let logger = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
98        println!("  [LOG] Processing pair: ({}, {})", x, y);
99    });
100    logger.accept(&5, &3);
101    logger.accept(&10, &7);
102    println!();
103
104    // 7. Chaining observations
105    println!("7. Chaining observations:");
106    let log_input = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
107        println!("  [INPUT] x={}, y={}", x, y);
108    });
109    let log_sum = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
110        println!("  [SUM] {}", x + y);
111    });
112    let log_product = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
113        println!("  [PRODUCT] {}", x * y);
114    });
115
116    let chained = log_input.and_then(log_sum).and_then(log_product);
117    chained.accept(&5, &3);
118    println!();
119
120    // 8. ArcReadonlyBiConsumer - Reusability
121    println!("8. ArcReadonlyBiConsumer - Reusability:");
122    let first = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
123        println!("  First: x={}, y={}", x, y);
124    });
125    let second = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
126        println!("  Second: sum={}", x + y);
127    });
128
129    // Both first and second can be reused after chaining
130    let chained1 = first.and_then(&second);
131    let chained2 = first.and_then(&second);
132
133    println!("  Using chained1:");
134    chained1.accept(&5, &3);
135
136    println!("  Using chained2:");
137    chained2.accept(&10, &2);
138    println!();
139
140    // 9. Name support
141    println!("9. Name support:");
142    let mut named_consumer = BoxReadonlyBiConsumer::<i32, i32>::noop();
143    println!("  Initial name: {:?}", named_consumer.name());
144
145    named_consumer.set_name("sum_logger");
146    println!("  After setting name: {:?}", named_consumer.name());
147    println!("  Display: {}\n", named_consumer);
148
149    // 10. No-op consumer
150    println!("10. No-op consumer:");
151    let noop = BoxReadonlyBiConsumer::<i32, i32>::noop();
152    noop.accept(&42, &10);
153    println!("  No-op completed (no output expected)\n");
154
155    println!("=== Demo Complete ===");
156}
Source

pub fn noop() -> Self

Creates a no-op readonly bi-consumer

§Returns

Returns a no-op readonly bi-consumer

Source

pub fn name(&self) -> Option<&str>

Gets the name of the consumer

Source

pub fn set_name(&mut self, name: impl Into<String>)

Sets the name of the consumer

Source

pub fn and_then( &self, next: &ArcReadonlyBiConsumer<T, U>, ) -> ArcReadonlyBiConsumer<T, U>

Chains another ArcReadonlyBiConsumer in sequence

Returns a new consumer executing the current operation first, then the next operation. Borrows &self, does not consume the original consumer.

§Parameters
  • next - The consumer to execute after the current operation. Note: This parameter is passed by reference, so the original consumer remains usable. Can be:
    • An ArcReadonlyBiConsumer<T, U> (passed by reference)
    • Any type implementing ReadonlyBiConsumer<T, U> + Send + Sync
§Returns

Returns a new composed ArcReadonlyBiConsumer<T, U>

§Examples
use prism3_function::{ReadonlyBiConsumer, ArcReadonlyBiConsumer};

let first = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
    println!("First: {}, {}", x, y);
});
let second = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
    println!("Second: sum = {}", x + y);
});

// second is passed by reference, so it remains usable
let chained = first.and_then(&second);

// first and second still usable after chaining
chained.accept(&5, &3);
first.accept(&2, &3); // Still usable
second.accept(&7, &8); // Still usable
Examples found in repository?
examples/readonly_bi_consumer_demo.rs (line 130)
22fn main() {
23    println!("=== ReadonlyBiConsumer Demo ===\n");
24
25    // 1. BoxReadonlyBiConsumer - Single ownership
26    println!("1. BoxReadonlyBiConsumer - Single ownership:");
27    let box_consumer = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
28        println!("  Values: x={}, y={}, sum={}", x, y, x + y);
29    });
30    box_consumer.accept(&10, &5);
31    println!();
32
33    // 2. Method chaining with BoxReadonlyBiConsumer
34    println!("2. BoxReadonlyBiConsumer with method chaining:");
35    let chained = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
36        println!("  First operation: x={}, y={}", x, y);
37    })
38    .and_then(|x: &i32, y: &i32| {
39        println!("  Second operation: sum={}", x + y);
40    })
41    .and_then(|x: &i32, y: &i32| {
42        println!("  Third operation: product={}", x * y);
43    });
44    chained.accept(&5, &3);
45    println!();
46
47    // 3. ArcReadonlyBiConsumer - Thread-safe shared ownership
48    println!("3. ArcReadonlyBiConsumer - Thread-safe shared ownership:");
49    let counter = Arc::new(AtomicUsize::new(0));
50    let c = counter.clone();
51    let arc_consumer = ArcReadonlyBiConsumer::new(move |x: &i32, y: &i32| {
52        c.fetch_add(1, Ordering::SeqCst);
53        println!("  Thread {:?}: sum={}", thread::current().id(), x + y);
54    });
55
56    let consumer1 = arc_consumer.clone();
57    let consumer2 = arc_consumer.clone();
58
59    let handle1 = thread::spawn(move || {
60        consumer1.accept(&10, &5);
61    });
62
63    let handle2 = thread::spawn(move || {
64        consumer2.accept(&20, &8);
65    });
66
67    handle1.join().unwrap();
68    handle2.join().unwrap();
69    println!("  Total calls: {}\n", counter.load(Ordering::SeqCst));
70
71    // 4. RcReadonlyBiConsumer - Single-threaded shared ownership
72    println!("4. RcReadonlyBiConsumer - Single-threaded shared ownership:");
73    let counter = Rc::new(std::cell::Cell::new(0));
74    let c = counter.clone();
75    let rc_consumer = RcReadonlyBiConsumer::new(move |x: &i32, y: &i32| {
76        c.set(c.get() + 1);
77        println!("  Call {}: sum={}", c.get(), x + y);
78    });
79
80    let clone1 = rc_consumer.clone();
81    let clone2 = rc_consumer.clone();
82
83    clone1.accept(&5, &3);
84    clone2.accept(&7, &2);
85    println!("  Total calls: {}\n", counter.get());
86
87    // 5. Working with closures directly
88    println!("5. Working with closures directly:");
89    let closure = |x: &i32, y: &i32| {
90        println!("  x={}, y={}, product={}", x, y, x * y);
91    };
92    closure.accept(&10, &20);
93    println!();
94
95    // 6. Pure observation - logging
96    println!("6. Pure observation - logging:");
97    let logger = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
98        println!("  [LOG] Processing pair: ({}, {})", x, y);
99    });
100    logger.accept(&5, &3);
101    logger.accept(&10, &7);
102    println!();
103
104    // 7. Chaining observations
105    println!("7. Chaining observations:");
106    let log_input = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
107        println!("  [INPUT] x={}, y={}", x, y);
108    });
109    let log_sum = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
110        println!("  [SUM] {}", x + y);
111    });
112    let log_product = BoxReadonlyBiConsumer::new(|x: &i32, y: &i32| {
113        println!("  [PRODUCT] {}", x * y);
114    });
115
116    let chained = log_input.and_then(log_sum).and_then(log_product);
117    chained.accept(&5, &3);
118    println!();
119
120    // 8. ArcReadonlyBiConsumer - Reusability
121    println!("8. ArcReadonlyBiConsumer - Reusability:");
122    let first = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
123        println!("  First: x={}, y={}", x, y);
124    });
125    let second = ArcReadonlyBiConsumer::new(|x: &i32, y: &i32| {
126        println!("  Second: sum={}", x + y);
127    });
128
129    // Both first and second can be reused after chaining
130    let chained1 = first.and_then(&second);
131    let chained2 = first.and_then(&second);
132
133    println!("  Using chained1:");
134    chained1.accept(&5, &3);
135
136    println!("  Using chained2:");
137    chained2.accept(&10, &2);
138    println!();
139
140    // 9. Name support
141    println!("9. Name support:");
142    let mut named_consumer = BoxReadonlyBiConsumer::<i32, i32>::noop();
143    println!("  Initial name: {:?}", named_consumer.name());
144
145    named_consumer.set_name("sum_logger");
146    println!("  After setting name: {:?}", named_consumer.name());
147    println!("  Display: {}\n", named_consumer);
148
149    // 10. No-op consumer
150    println!("10. No-op consumer:");
151    let noop = BoxReadonlyBiConsumer::<i32, i32>::noop();
152    noop.accept(&42, &10);
153    println!("  No-op completed (no output expected)\n");
154
155    println!("=== Demo Complete ===");
156}

Trait Implementations§

Source§

impl<T, U> Clone for ArcReadonlyBiConsumer<T, U>

Source§

fn clone(&self) -> Self

Clones the ArcReadonlyBiConsumer

Creates a new ArcReadonlyBiConsumer sharing the underlying function with the original instance.

1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T, U> Debug for ArcReadonlyBiConsumer<T, U>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T, U> Display for ArcReadonlyBiConsumer<T, U>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T, U> ReadonlyBiConsumer<T, U> for ArcReadonlyBiConsumer<T, U>

Source§

fn accept(&self, first: &T, second: &U)

Performs the readonly consumption operation Read more
Source§

fn into_box(self) -> BoxReadonlyBiConsumer<T, U>
where T: 'static, U: 'static,

Converts to BoxReadonlyBiConsumer Read more
Source§

fn into_rc(self) -> RcReadonlyBiConsumer<T, U>
where T: 'static, U: 'static,

Converts to RcReadonlyBiConsumer Read more
Source§

fn into_arc(self) -> ArcReadonlyBiConsumer<T, U>
where T: Send + Sync + 'static, U: Send + Sync + 'static,

Converts to ArcReadonlyBiConsumer Read more
Source§

fn into_fn(self) -> impl Fn(&T, &U)
where T: 'static, U: 'static,

Converts readonly bi-consumer to a closure Read more
Source§

fn to_box(&self) -> BoxReadonlyBiConsumer<T, U>
where T: 'static, U: 'static,

Converts to BoxReadonlyBiConsumer (without consuming self) Read more
Source§

fn to_rc(&self) -> RcReadonlyBiConsumer<T, U>
where T: 'static, U: 'static,

Converts to RcReadonlyBiConsumer (without consuming self) Read more
Source§

fn to_arc(&self) -> ArcReadonlyBiConsumer<T, U>
where T: Send + Sync + 'static, U: Send + Sync + 'static,

Converts to ArcReadonlyBiConsumer (without consuming self) Read more
Source§

fn to_fn(&self) -> impl Fn(&T, &U)
where T: 'static, U: 'static,

Converts to a closure (without consuming self) Read more

Auto Trait Implementations§

§

impl<T, U> Freeze for ArcReadonlyBiConsumer<T, U>

§

impl<T, U> !RefUnwindSafe for ArcReadonlyBiConsumer<T, U>

§

impl<T, U> Send for ArcReadonlyBiConsumer<T, U>

§

impl<T, U> Sync for ArcReadonlyBiConsumer<T, U>

§

impl<T, U> Unpin for ArcReadonlyBiConsumer<T, U>

§

impl<T, U> !UnwindSafe for ArcReadonlyBiConsumer<T, U>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.