Skip to main content

BoxConditionalStatefulConsumer

Struct BoxConditionalStatefulConsumer 

Source
pub struct BoxConditionalStatefulConsumer<T> { /* private fields */ }
Expand description

BoxConditionalStatefulConsumer struct

A conditional consumer that only executes when a predicate is satisfied. Uses BoxStatefulConsumer and BoxPredicate for single ownership semantics.

This type is typically created by calling BoxStatefulConsumer::when() and is designed to work with the or_else() method to create if-then-else logic.

§Features

  • Single Ownership: Not cloneable, consumes self on use
  • Conditional Execution: Only consumes when predicate returns true
  • Chainable: Can add or_else branch to create if-then-else logic
  • Implements Consumer: Can be used anywhere a Consumer is expected

§Examples

§Basic Conditional Execution

use qubit_function::{Consumer, StatefulConsumer, BoxStatefulConsumer};
use std::sync::{Arc, Mutex};

let log = Arc::new(Mutex::new(Vec::new()));
let l = log.clone();
let consumer = BoxStatefulConsumer::new(move |x: &i32| {
    l.lock().expect("mutex should not be poisoned").push(*x);
});
let mut conditional = consumer.when(|x: &i32| *x > 0);

conditional.accept(&5);
assert_eq!(*log.lock().expect("mutex should not be poisoned"), vec![5]); // Executed

conditional.accept(&-5);
assert_eq!(*log.lock().expect("mutex should not be poisoned"), vec![5]); // Not executed

§With or_else Branch

use qubit_function::{Consumer, StatefulConsumer, BoxStatefulConsumer};
use std::sync::{Arc, Mutex};

let log = Arc::new(Mutex::new(Vec::new()));
let l1 = log.clone();
let l2 = log.clone();
let mut consumer = BoxStatefulConsumer::new(move |x: &i32| {
    l1.lock().expect("mutex should not be poisoned").push(*x);
})
.when(|x: &i32| *x > 0)
.or_else(move |x: &i32| {
    l2.lock().expect("mutex should not be poisoned").push(-*x);
});

consumer.accept(&5);
assert_eq!(*log.lock().expect("mutex should not be poisoned"), vec![5]); // when branch executed

consumer.accept(&-5);
assert_eq!(*log.lock().expect("mutex should not be poisoned"), vec![5, 5]); // or_else branch executed

Implementations§

Source§

impl<T> BoxConditionalStatefulConsumer<T>

Source

pub fn and_then<C>(self, next: C) -> BoxStatefulConsumer<T>
where T: 'static, C: StatefulConsumer<T> + 'static,

Chains another consumer in sequence

Combines the current conditional consumer with another consumer into a new consumer that implements the following semantics:

When the returned consumer is called with an argument:

  1. First, it checks the predicate of this conditional consumer
  2. If the predicate is satisfied, it executes the internal consumer of this conditional consumer
  3. Then, regardless of whether the predicate was satisfied, it unconditionally executes the next consumer

In other words, this creates a consumer that conditionally executes the first action (based on the predicate), and then always executes the second action.

§Parameters
  • next - The next consumer to execute (always executed)
§Returns

Returns a new combined consumer

§Examples
use std::sync::atomic::{AtomicI32, Ordering};
use std::sync::Arc;
use qubit_function::BoxConsumer;
use qubit_function::Consumer;

let result = Arc::new(AtomicI32::new(0));
let result1 = result.clone();
let result2 = result.clone();

let consumer1 = BoxConsumer::new(move |x: &i32| {
    result1.fetch_add(*x, Ordering::SeqCst);
});

let consumer2 = BoxConsumer::new(move |x: &i32| {
    result2.fetch_add(2 * (*x), Ordering::SeqCst);
});
let result3 = result.clone();

let conditional = consumer1.when(|x: &i32| *x > 0);
let chained = conditional.and_then(consumer2);

chained.accept(&5);  // result = 5 + (2*5) = 15
result3.store(0, Ordering::SeqCst);  // reset
chained.accept(&-5); // result = 0 + (2*-5) = -10 (not -15!)
Source

pub fn or_else<C>(self, else_consumer: C) -> BoxStatefulConsumer<T>
where T: 'static, C: StatefulConsumer<T> + 'static,

Adds an else branch

Executes the original consumer when the condition is satisfied, otherwise executes else_consumer.

§Parameters
  • else_consumer - The consumer for the else branch
§Returns

Returns a new consumer with if-then-else logic

Examples found in repository?
examples/consumers/consumer_demo.rs (line 161)
34fn main() {
35    println!("=== Consumer Examples ===\n");
36    println!("Note: Consumer only reads values, does not modify the original value");
37    println!("If you need to modify values, please refer to mutator_demo.rs\n");
38
39    // ========================================================================
40    // Example 1: BoxConsumer basic usage
41    // ========================================================================
42    println!("Example 1: BoxConsumer basic usage");
43    println!("{}", "-".repeat(50));
44
45    let consumer = BoxConsumer::new(|x: &i32| {
46        println!("Read and calculate: {} * 2 = {}", x, x * 2);
47    });
48    let value = 5;
49    println!("Value: {}", value);
50    consumer.accept(&value);
51    println!("Value remains: {} (not modified)\n", value);
52
53    // ========================================================================
54    // Example 2: BoxConsumer method chaining
55    // ========================================================================
56    println!("Example 2: BoxConsumer method chaining");
57    println!("{}", "-".repeat(50));
58
59    let results = Arc::new(Mutex::new(Vec::new()));
60    let r1 = results.clone();
61    let r2 = results.clone();
62    let r3 = results.clone();
63
64    let chained = BoxConsumer::new(move |x: &i32| {
65        r1.lock()
66            .expect("mutex should not be poisoned")
67            .push(*x * 2);
68    })
69    .and_then(move |x: &i32| {
70        r2.lock()
71            .expect("mutex should not be poisoned")
72            .push(*x + 10);
73    })
74    .and_then(move |x: &i32| {
75        r3.lock().expect("mutex should not be poisoned").push(*x);
76        println!("Processing value: {}", x);
77    });
78
79    let value = 5;
80    println!("Initial value: {}", value);
81    chained.accept(&value);
82    println!(
83        "Collected results: {:?}",
84        *results.lock().expect("mutex should not be poisoned")
85    );
86    println!("Original value: {} (not modified)\n", value);
87
88    // ========================================================================
89    // Example 3: Closure extension methods
90    // ========================================================================
91    println!("Example 3: Direct use of extension methods on closures");
92    println!("{}", "-".repeat(50));
93
94    let result = Arc::new(Mutex::new(0));
95    let r1 = result.clone();
96    let r2 = result.clone();
97
98    let closure_chain = (move |x: &i32| {
99        *r1.lock().expect("mutex should not be poisoned") = *x * 2;
100    })
101    .and_then(move |_x: &i32| {
102        *r2.lock().expect("mutex should not be poisoned") += 10;
103    });
104
105    let value = 5;
106    println!("Initial value: {}", value);
107    closure_chain.accept(&value);
108    println!(
109        "Calculation result: {}",
110        *result.lock().expect("mutex should not be poisoned")
111    );
112    println!("Original value: {} (not modified)\n", value);
113
114    // ========================================================================
115    // Example 4: BoxConsumer factory methods
116    // ========================================================================
117    println!("Example 4: BoxConsumer factory methods");
118    println!("{}", "-".repeat(50));
119
120    // noop
121    println!("noop - does nothing:");
122    let noop = BoxConsumer::<i32>::noop();
123    let value = 42;
124    noop.accept(&value);
125    println!("Value: {}\n", value);
126
127    // print
128    print!("print - prints value: ");
129    let print = BoxConsumer::new(|x: &i32| println!("{}", x));
130    let value = 42;
131    print.accept(&value);
132    println!();
133
134    // print with prefix
135    let print_with = BoxConsumer::new(|x: &i32| println!("Value is: {}", x));
136    let value = 42;
137    print_with.accept(&value);
138    println!();
139
140    // ========================================================================
141    // Example 5: Conditional Consumer
142    // ========================================================================
143    println!("Example 5: Conditional Consumer");
144    println!("{}", "-".repeat(50));
145
146    // when
147    let mut check_positive =
148        BoxStatefulConsumer::new(|x: &i32| println!("Positive: {}", x)).when(|x: &i32| *x > 0);
149
150    let positive = 5;
151    let negative = -5;
152    print!("Check {}: ", positive);
153    check_positive.accept(&positive);
154    print!("Check {}: ", negative);
155    check_positive.accept(&negative);
156    println!("(negative numbers not printed)\n");
157
158    // when().or_else()
159    let mut categorize = BoxStatefulConsumer::new(|x: &i32| println!("Positive: {}", x))
160        .when(|x: &i32| *x > 0)
161        .or_else(|x: &i32| println!("Non-positive: {}", x));
162
163    let positive = 10;
164    let negative = -10;
165    categorize.accept(&positive);
166    categorize.accept(&negative);
167    println!();
168
169    // ========================================================================
170    // Example 6: ArcConsumer - multi-threaded sharing
171    // ========================================================================
172    println!("Example 6: ArcConsumer - multi-threaded sharing");
173    println!("{}", "-".repeat(50));
174
175    let shared = ArcConsumer::new(|x: &i32| println!("Processing value: {}", x * 2));
176
177    // Clone for another thread
178    let shared_clone = shared.clone();
179    let handle = thread::spawn(move || {
180        let value = 5;
181        let consumer = shared_clone;
182        consumer.accept(&value);
183        value
184    });
185
186    // Use in main thread
187    let value = 3;
188    let consumer = shared;
189    consumer.accept(&value);
190
191    let thread_result = handle.join().expect("thread should not panic");
192    println!("Thread result: {}\n", thread_result);
193
194    // ========================================================================
195    // Example 7: ArcConsumer composition (does not consume original consumer)
196    // ========================================================================
197    println!("Example 7: ArcConsumer composition (borrowing &self)");
198    println!("{}", "-".repeat(50));
199
200    let double = ArcConsumer::new(|x: &i32| println!("double: {}", x * 2));
201    let add_ten = ArcConsumer::new(|x: &i32| println!("add_ten: {}", x + 10));
202
203    // Composition does not consume original consumer
204    let pipeline1 = double.and_then(add_ten.clone());
205    let pipeline2 = add_ten.and_then(double.clone());
206
207    let value1 = 5;
208    let p1 = pipeline1;
209    print!("pipeline1 processing 5: ");
210    p1.accept(&value1);
211
212    let value2 = 5;
213    let p2 = pipeline2;
214    print!("pipeline2 processing 5: ");
215    p2.accept(&value2);
216
217    // double and add_ten are still available
218    let value3 = 10;
219    let d = double;
220    print!("Original double still available, processing 10: ");
221    d.accept(&value3);
222    println!();
223
224    // ========================================================================
225    // Example 8: RcConsumer - single-threaded sharing
226    // ========================================================================
227    println!("Example 8: RcConsumer - single-threaded sharing");
228    println!("{}", "-".repeat(50));
229
230    let rc_consumer = RcConsumer::new(|x: &i32| println!("Processing: {}", x * 2));
231
232    // Clone multiple copies
233    let clone1 = rc_consumer.clone();
234    let clone2 = rc_consumer.clone();
235
236    let value1 = 5;
237    let c1 = clone1;
238    print!("clone1 processing 5: ");
239    c1.accept(&value1);
240
241    let value2 = 3;
242    let c2 = clone2;
243    print!("clone2 processing 3: ");
244    c2.accept(&value2);
245
246    let value3 = 7;
247    let c3 = rc_consumer;
248    print!("Original processing 7: ");
249    c3.accept(&value3);
250    println!();
251
252    // ========================================================================
253    // Example 9: RcConsumer composition (borrowing &self)
254    // ========================================================================
255    println!("Example 9: RcConsumer composition (borrowing &self)");
256    println!("{}", "-".repeat(50));
257
258    let double = RcConsumer::new(|x: &i32| println!("double: {}", x * 2));
259    let add_ten = RcConsumer::new(|x: &i32| println!("add_ten: {}", x + 10));
260
261    let pipeline1 = double.and_then(add_ten.clone());
262    let pipeline2 = add_ten.and_then(double.clone());
263
264    let value1 = 5;
265    let p1 = pipeline1;
266    print!("pipeline1 processing 5: ");
267    p1.accept(&value1);
268
269    let value2 = 5;
270    let p2 = pipeline2;
271    print!("pipeline2 processing 5: ");
272    p2.accept(&value2);
273    println!();
274
275    // ========================================================================
276    // Example 10: Unified Consumer trait
277    // ========================================================================
278    println!("Example 10: Unified Consumer trait");
279    println!("{}", "-".repeat(50));
280
281    fn log_all<C: Consumer<i32>>(consumer: &mut C, values: &[i32]) {
282        for value in values.iter() {
283            consumer.accept(value);
284        }
285    }
286
287    let values = vec![1, 2, 3, 4, 5];
288
289    let mut box_con = BoxConsumer::new(|x: &i32| print!("{} ", x * 2));
290    print!("BoxConsumer processing {:?}: ", values);
291    log_all(&mut box_con, &values);
292    println!();
293
294    let mut arc_con = ArcConsumer::new(|x: &i32| print!("{} ", x * 2));
295    print!("ArcConsumer processing {:?}: ", values);
296    log_all(&mut arc_con, &values);
297    println!();
298
299    let mut rc_con = RcConsumer::new(|x: &i32| print!("{} ", x * 2));
300    print!("RcConsumer processing {:?}: ", values);
301    log_all(&mut rc_con, &values);
302    println!();
303
304    let mut closure = |x: &i32| print!("{} ", x * 2);
305    print!("Closure processing {:?}: ", values);
306    log_all(&mut closure, &values);
307    println!("\n");
308
309    // ========================================================================
310    // Example 11: Data validation and logging
311    // ========================================================================
312    println!("Example 11: Data validation and logging");
313    println!("{}", "-".repeat(50));
314
315    let validator = BoxConsumer::new(|x: &i32| {
316        let status = if *x >= 0 && *x <= 100 {
317            "valid"
318        } else {
319            "out of range"
320        };
321        println!("Validate {}: {}", x, status);
322    });
323
324    let logger = BoxConsumer::new(|x: &i32| {
325        println!("Log to file: value={}, square={}", x, x * x);
326    });
327
328    let pipeline = validator.and_then(logger);
329
330    let test_values = vec![-50, 30, 200];
331    for value in test_values {
332        pipeline.accept(&value);
333    }
334    println!();
335
336    // ========================================================================
337    // Example 12: String analysis
338    // ========================================================================
339    println!("Example 12: String analysis");
340    println!("{}", "-".repeat(50));
341
342    let string_analyzer = BoxConsumer::new(|s: &String| {
343        println!("Length: {}", s.len());
344    })
345    .and_then(|s: &String| {
346        println!("Lowercase: {}", s.to_lowercase());
347    })
348    .and_then(|s: &String| {
349        println!("Uppercase: {}", s.to_uppercase());
350    })
351    .and_then(|s: &String| {
352        let word_count = s.split_whitespace().count();
353        println!("Word count: {}", word_count);
354    });
355
356    let text = String::from("Hello World");
357    println!("Analyzing text: \"{}\"", text);
358    string_analyzer.accept(&text);
359    println!("Original text: \"{}\" (not modified)\n", text);
360
361    // ========================================================================
362    // Example 13: Type conversion
363    // ========================================================================
364    println!("Example 13: Type conversion");
365    println!("{}", "-".repeat(50));
366
367    // Closure -> BoxConsumer
368    let closure = |x: &i32| print!("Processing: {} ", x * 2);
369    let box_con = Consumer::into_box(closure);
370    let value = 5;
371    print!("Closure -> BoxConsumer: ");
372    box_con.accept(&value);
373    println!();
374
375    // Closure -> RcConsumer
376    let closure = |x: &i32| print!("Processing: {} ", x * 2);
377    let rc_con = Consumer::into_rc(closure);
378    let value = 5;
379    print!("Closure -> RcConsumer: ");
380    rc_con.accept(&value);
381    println!();
382
383    // Closure -> ArcConsumer
384    let closure = |x: &i32| print!("Processing: {} ", x * 2);
385    let arc_con = Consumer::into_arc(closure);
386    let value = 5;
387    print!("Closure -> ArcConsumer: ");
388    arc_con.accept(&value);
389    println!();
390
391    // BoxConsumer -> RcConsumer
392    let box_con = BoxConsumer::new(|x: &i32| print!("Processing: {} ", x * 2));
393    let rc_con = box_con.into_rc();
394    let value = 5;
395    print!("BoxConsumer -> RcConsumer: ");
396    rc_con.accept(&value);
397    println!();
398
399    // RcConsumer -> BoxConsumer
400    let rc_con = RcConsumer::new(|x: &i32| print!("Processing: {} ", x * 2));
401    let box_con = rc_con.into_box();
402    let value = 5;
403    print!("RcConsumer -> BoxConsumer: ");
404    box_con.accept(&value);
405    println!("\n");
406
407    // ========================================================================
408    // Example 14: Custom types
409    // ========================================================================
410    println!("Example 14: Custom types");
411    println!("{}", "-".repeat(50));
412
413    #[derive(Debug, Clone)]
414    struct Point {
415        x: i32,
416        y: i32,
417    }
418
419    let analyzer = BoxConsumer::new(|p: &Point| {
420        println!("Point coordinates: ({}, {})", p.x, p.y);
421    })
422    .and_then(|p: &Point| {
423        let distance = ((p.x * p.x + p.y * p.y) as f64).sqrt();
424        println!("Distance from origin: {:.2}", distance);
425    })
426    .and_then(|p: &Point| {
427        let quadrant = match (p.x >= 0, p.y >= 0) {
428            (true, true) => "First quadrant",
429            (false, true) => "Second quadrant",
430            (false, false) => "Third quadrant",
431            (true, false) => "Fourth quadrant",
432        };
433        println!("Quadrant: {}", quadrant);
434    });
435
436    let point = Point { x: 3, y: 4 };
437    println!("Analyzing point: {:?}", point);
438    analyzer.accept(&point);
439    println!("Original point: {:?} (not modified)\n", point);
440
441    // ========================================================================
442    // Example 15: Data collection and statistics
443    // ========================================================================
444    println!("Example 15: Data collection and statistics");
445    println!("{}", "-".repeat(50));
446
447    let sum = Arc::new(Mutex::new(0));
448    let count = Arc::new(Mutex::new(0));
449    let sum_clone = sum.clone();
450    let count_clone = count.clone();
451
452    let collector = BoxConsumer::new(move |x: &i32| {
453        *sum_clone.lock().expect("mutex should not be poisoned") += *x;
454        *count_clone.lock().expect("mutex should not be poisoned") += 1;
455    });
456
457    let numbers = vec![10, 20, 30, 40, 50];
458    println!("Numbers: {:?}", numbers);
459    for num in &numbers {
460        collector.accept(num);
461    }
462
463    let total = *sum.lock().expect("mutex should not be poisoned");
464    let cnt = *count.lock().expect("mutex should not be poisoned");
465    println!("Sum: {}", total);
466    println!("Count: {}", cnt);
467    println!("Average: {:.2}\n", total as f64 / cnt as f64);
468
469    println!("=== All examples completed ===");
470    println!("\nTip: For value modification functionality, please refer to mutator_demo.rs");
471}

Trait Implementations§

Source§

impl<T> Debug for BoxConditionalStatefulConsumer<T>

Source§

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

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

impl<T> Display for BoxConditionalStatefulConsumer<T>

Source§

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

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

impl<T> StatefulConsumer<T> for BoxConditionalStatefulConsumer<T>

Source§

fn accept(&mut self, value: &T)

Execute consumption operation Read more
Source§

fn into_box(self) -> BoxStatefulConsumer<T>
where Self: 'static,

Convert to BoxStatefulConsumer Read more
Source§

fn into_rc(self) -> RcStatefulConsumer<T>
where Self: 'static,

Convert to RcStatefulConsumer Read more
Source§

fn into_fn(self) -> impl FnMut(&T)

Convert to closure Read more
Source§

fn into_arc(self) -> ArcStatefulConsumer<T>
where Self: Sized + Send + 'static,

Convert to ArcStatefulConsumer Read more
Source§

fn into_once(self) -> BoxConsumerOnce<T>
where Self: Sized + 'static,

Convert to ConsumerOnce Read more

Auto Trait Implementations§

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> 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> 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.