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