Skip to main content

bi_consumer_observation_demo/
bi_consumer_observation_demo.rs

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