Skip to main content

FnConsumerOps

Trait FnConsumerOps 

Source
pub trait FnConsumerOps<T>: Fn(&T) + Sized {
    // Provided method
    fn and_then<C>(self, next: C) -> BoxConsumer<T>
       where Self: 'static,
             C: Consumer<T> + 'static,
             T: 'static { ... }
}
Expand description

Extension trait providing non-mutating consumer composition methods for closures

Provides and_then and other composition methods for all closures implementing Fn(&T), allowing closures to directly chain methods without explicit wrapper types.

§Features

  • Natural Syntax: Chain operations directly on closures
  • Returns BoxConsumer: Combined results can continue chaining
  • Zero Cost: No overhead when composing closures
  • Auto-implementation: All Fn(&T) closures automatically get these methods

§Examples

use qubit_function::{Consumer, FnConsumerOps};

let chained = (|x: &i32| {
    println!("First: {}", x);
}).and_then(|x: &i32| {
    println!("Second: {}", x);
});
chained.accept(&5);

Provided Methods§

Source

fn and_then<C>(self, next: C) -> BoxConsumer<T>
where Self: 'static, C: Consumer<T> + 'static, T: 'static,

Sequentially chain another non-mutating consumer

Returns a new consumer that executes the current operation first, then the next operation. Consumes the current closure and returns BoxConsumer<T>.

§Type Parameters
  • C - Type of the next consumer
§Parameters
  • next - Consumer to execute after the current operation
§Returns

Returns a combined BoxConsumer<T>

§Examples
use qubit_function::{Consumer, FnConsumerOps};

let chained = (|x: &i32| {
    println!("First: {}", x);
}).and_then(|x: &i32| {
    println!("Second: {}", x);
}).and_then(|x: &i32| println!("Third: {}", x));

chained.accept(&5);
Examples found in repository?
examples/consumers/consumer_demo.rs (lines 101-103)
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}

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§

Source§

impl<T, F> FnConsumerOps<T> for F
where F: Fn(&T),

Implement FnConsumerOps for all closure types