Skip to main content

mutator_once_conditional_demo/
mutator_once_conditional_demo.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10//! # MutatorOnce Conditional Execution Demo
11//!
12//! Demonstrates conditional execution features of BoxMutatorOnce
13
14use qubit_function::{
15    BoxMutatorOnce,
16    BoxPredicate,
17    FnPredicateOps,
18    MutatorOnce,
19};
20
21fn main() {
22    println!("=== MutatorOnce Conditional Execution Examples ===\n");
23
24    // 1. Basic conditional execution - when condition is satisfied
25    println!("1. Basic conditional execution - when condition is satisfied");
26    let data = vec![1, 2, 3];
27    let mutator = BoxMutatorOnce::new(move |x: &mut Vec<i32>| {
28        println!("   Extending vector with data: {:?}", data);
29        x.extend(data);
30    });
31    let conditional = mutator.when(|x: &Vec<i32>| {
32        println!("   Checking condition: !x.is_empty()");
33        !x.is_empty()
34    });
35
36    let mut target = vec![0];
37    println!("   Initial: {:?}", target);
38    conditional.apply(&mut target);
39    println!("   Result: {:?}\n", target);
40
41    // 2. Conditional execution - when condition is not satisfied
42    println!("2. Conditional execution - when condition is not satisfied");
43    let data = vec![4, 5, 6];
44    let mutator = BoxMutatorOnce::new(move |x: &mut Vec<i32>| {
45        println!("   This should not be executed");
46        x.extend(data);
47    });
48    let conditional = mutator.when(|x: &Vec<i32>| {
49        println!("   Checking condition: x.len() > 10");
50        x.len() > 10
51    });
52
53    let mut target = vec![0];
54    println!("   Initial: {:?}", target);
55    conditional.apply(&mut target);
56    println!("   Result: {:?} (unchanged)\n", target);
57
58    // 3. Using BoxPredicate
59    println!("3. Using BoxPredicate");
60    let pred = BoxPredicate::new(|x: &Vec<i32>| {
61        println!("   Predicate: checking if vector is not empty");
62        !x.is_empty()
63    });
64    let data = vec![7, 8, 9];
65    let mutator = BoxMutatorOnce::new(move |x: &mut Vec<i32>| {
66        println!("   Adding data: {:?}", data);
67        x.extend(data);
68    });
69    let conditional = mutator.when(pred);
70
71    let mut target = vec![0];
72    println!("   Initial: {:?}", target);
73    conditional.apply(&mut target);
74    println!("   Result: {:?}\n", target);
75
76    // 4. Using composed predicate
77    println!("4. Using composed predicate");
78    let pred = (|x: &Vec<i32>| {
79        println!("   Condition 1: !x.is_empty()");
80        !x.is_empty()
81    })
82    .and(|x: &Vec<i32>| {
83        println!("   Condition 2: x.len() < 10");
84        x.len() < 10
85    });
86    let data = vec![10, 11, 12];
87    let mutator = BoxMutatorOnce::new(move |x: &mut Vec<i32>| {
88        println!("   Adding data: {:?}", data);
89        x.extend(data);
90    });
91    let conditional = mutator.when(pred);
92
93    let mut target = vec![0];
94    println!("   Initial: {:?}", target);
95    conditional.apply(&mut target);
96    println!("   Result: {:?}\n", target);
97
98    // 5. If-then-else with or_else - when branch
99    println!("5. If-then-else with or_else - when branch");
100    let data1 = vec![1, 2, 3];
101    let data2 = vec![99];
102    let mutator = BoxMutatorOnce::new(move |x: &mut Vec<i32>| {
103        println!("   When branch: adding {:?}", data1);
104        x.extend(data1);
105    })
106    .when(|x: &Vec<i32>| {
107        println!("   Checking: !x.is_empty()");
108        !x.is_empty()
109    })
110    .or_else(move |x: &mut Vec<i32>| {
111        println!("   Else branch: adding {:?}", data2);
112        x.extend(data2);
113    });
114
115    let mut target = vec![0];
116    println!("   Initial: {:?}", target);
117    mutator.apply(&mut target);
118    println!("   Result: {:?}\n", target);
119
120    // 6. If-then-else with or_else - else branch
121    println!("6. If-then-else with or_else - else branch");
122    let data1 = vec![4, 5, 6];
123    let data2 = vec![99];
124    let mutator = BoxMutatorOnce::new(move |x: &mut Vec<i32>| {
125        println!("   When branch: adding {:?}", data1);
126        x.extend(data1);
127    })
128    .when(|x: &Vec<i32>| {
129        println!("   Checking: x.is_empty()");
130        x.is_empty()
131    })
132    .or_else(move |x: &mut Vec<i32>| {
133        println!("   Else branch: adding {:?}", data2);
134        x.extend(data2);
135    });
136
137    let mut target = vec![0];
138    println!("   Initial: {:?}", target);
139    mutator.apply(&mut target);
140    println!("   Result: {:?}\n", target);
141
142    // 7. Conditional with integers
143    println!("7. Conditional with integers");
144    let mutator = BoxMutatorOnce::new(|x: &mut i32| {
145        println!("   Multiplying by 2");
146        *x *= 2;
147    })
148    .when(|x: &i32| {
149        println!("   Checking: *x > 0");
150        *x > 0
151    });
152
153    let mut positive = 5;
154    println!("   Initial (positive): {}", positive);
155    mutator.apply(&mut positive);
156    println!("   Result: {}\n", positive);
157
158    // 8. Conditional with integers - not executed
159    println!("8. Conditional with integers - not executed");
160    let mutator = BoxMutatorOnce::new(|x: &mut i32| {
161        println!("   This should not be executed");
162        *x *= 2;
163    })
164    .when(|x: &i32| {
165        println!("   Checking: *x > 0");
166        *x > 0
167    });
168
169    let mut negative = -5;
170    println!("   Initial (negative): {}", negative);
171    mutator.apply(&mut negative);
172    println!("   Result: {} (unchanged)\n", negative);
173
174    // 9. Chaining conditional mutators
175    println!("9. Chaining conditional mutators");
176    let data1 = vec![1, 2];
177    let cond1 = BoxMutatorOnce::new(move |x: &mut Vec<i32>| {
178        println!("   First mutator: adding {:?}", data1);
179        x.extend(data1);
180    })
181    .when(|x: &Vec<i32>| {
182        println!("   First condition: !x.is_empty()");
183        !x.is_empty()
184    });
185
186    let data2 = vec![3, 4];
187    let cond2 = BoxMutatorOnce::new(move |x: &mut Vec<i32>| {
188        println!("   Second mutator: adding {:?}", data2);
189        x.extend(data2);
190    })
191    .when(|x: &Vec<i32>| {
192        println!("   Second condition: x.len() < 10");
193        x.len() < 10
194    });
195
196    let chained = cond1.and_then(cond2);
197
198    let mut target = vec![0];
199    println!("   Initial: {:?}", target);
200    chained.apply(&mut target);
201    println!("   Result: {:?}\n", target);
202
203    // 10. Complex conditional chain
204    println!("10. Complex conditional chain");
205    let data1 = vec![1, 2];
206    let data2 = vec![99];
207    let data3 = vec![5, 6];
208
209    let mutator = BoxMutatorOnce::new(move |x: &mut Vec<i32>| {
210        println!("   When branch: adding {:?}", data1);
211        x.extend(data1);
212    })
213    .when(|x: &Vec<i32>| {
214        println!("   Checking: !x.is_empty()");
215        !x.is_empty()
216    })
217    .or_else(move |x: &mut Vec<i32>| {
218        println!("   Else branch: adding {:?}", data2);
219        x.extend(data2);
220    })
221    .and_then(move |x: &mut Vec<i32>| {
222        println!("   Final step: adding {:?}", data3);
223        x.extend(data3);
224    });
225
226    let mut target = vec![0];
227    println!("   Initial: {:?}", target);
228    mutator.apply(&mut target);
229    println!("   Result: {:?}\n", target);
230
231    // 11. Real-world scenario: data validation and processing
232    println!("11. Real-world scenario: data validation and processing");
233
234    struct DataProcessor {
235        on_valid: Option<BoxMutatorOnce<Vec<String>>>,
236        on_invalid: Option<BoxMutatorOnce<Vec<String>>>,
237    }
238
239    impl DataProcessor {
240        fn new<V, I>(on_valid: V, on_invalid: I) -> Self
241        where
242            V: FnOnce(&mut Vec<String>) + 'static,
243            I: FnOnce(&mut Vec<String>) + 'static,
244        {
245            Self {
246                on_valid: Some(BoxMutatorOnce::new(on_valid)),
247                on_invalid: Some(BoxMutatorOnce::new(on_invalid)),
248            }
249        }
250
251        fn process(mut self, data: &mut Vec<String>) {
252            let is_valid = !data.is_empty() && data.iter().all(|s| !s.is_empty());
253            println!(
254                "   Data validation: {}",
255                if is_valid { "VALID" } else { "INVALID" }
256            );
257
258            if is_valid {
259                if let Some(callback) = self.on_valid.take() {
260                    callback.apply(data);
261                }
262            } else if let Some(callback) = self.on_invalid.take() {
263                callback.apply(data);
264            }
265        }
266    }
267
268    let valid_suffix = vec!["processed".to_string()];
269    let invalid_marker = vec!["[INVALID]".to_string()];
270
271    let processor = DataProcessor::new(
272        move |data| {
273            println!("   Valid data callback: adding suffix");
274            data.extend(valid_suffix);
275        },
276        move |data| {
277            println!("   Invalid data callback: adding error marker");
278            data.clear();
279            data.extend(invalid_marker);
280        },
281    );
282
283    let mut valid_data = vec!["item1".to_string(), "item2".to_string()];
284    println!("   Processing valid data: {:?}", valid_data);
285    processor.process(&mut valid_data);
286    println!("   Result: {:?}\n", valid_data);
287
288    println!("=== Examples completed ===");
289}