1use crate::{ComponentMap, Keyed, WithArgs};
2
3impl<Key, Args, Comp, FnInit> ComponentMap<Key, Args, Comp, FnInit> {
4 pub fn try_init<Error>(
5 args: impl IntoIterator<Item = (Key, Args)>,
6 init: FnInit,
7 ) -> Result<Self, Error>
8 where
9 Key: Eq + std::hash::Hash,
10 FnInit: Fn(&Key, &Args) -> Result<Comp, Error>,
11 {
12 let map = args
13 .into_iter()
14 .map(|(key, args)| {
15 let component = (init)(&key, &args)?;
16 Ok((key, WithArgs { component, args }))
17 })
18 .collect::<Result<_, _>>()?;
19
20 Ok(Self { map: map, init })
21 }
22
23 pub fn try_reinit_all<Error>(
24 &mut self,
25 ) -> impl Iterator<Item = Keyed<&Key, Result<Comp, Error>>>
26 where
27 FnInit: Fn(&Key, &Args) -> Result<Comp, Error>,
28 {
29 self.map.iter_mut().map(|(key, component)| {
30 let result = (self.init)(key, &component.args)
31 .map(|next| std::mem::replace(&mut component.component, next));
32
33 Keyed::new(key, result)
34 })
35 }
36
37 pub fn try_reinit<Error>(
38 &mut self,
39 keys: impl IntoIterator<Item = Key>,
40 ) -> impl Iterator<Item = Keyed<Key, Option<Result<Comp, Error>>>>
41 where
42 Key: Eq + std::hash::Hash,
43 FnInit: Fn(&Key, &Args) -> Result<Comp, Error>,
44 {
45 keys.into_iter().map(|key| {
46 let prev = self.map.get_mut(&key).map(|component| {
47 (self.init)(&key, &component.args)
48 .map(|next| std::mem::replace(&mut component.component, next))
49 });
50
51 Keyed::new(key, prev)
52 })
53 }
54
55 #[allow(clippy::type_complexity)]
56 pub fn try_update<Error>(
57 &mut self,
58 updates: impl IntoIterator<Item = (Key, Args)>,
59 ) -> impl Iterator<Item = Keyed<Key, Option<Result<WithArgs<Args, Comp>, Error>>>>
60 where
61 Key: Clone + Eq + std::hash::Hash,
62 FnInit: Fn(&Key, &Args) -> Result<Comp, Error>,
63 {
64 updates.into_iter().map(move |(key, args)| {
65 let result = (self.init)(&key, &args)
66 .map(|component| self.map.insert(key.clone(), WithArgs { component, args }));
67
68 Keyed::new(key, result.transpose())
69 })
70 }
71}
72
73#[cfg(test)]
74mod tests {
75 use super::*;
76 use std::sync::{Arc, Mutex};
77
78 #[derive(Debug, Clone, PartialEq, Eq)]
79 struct Counter(usize);
80
81 #[derive(Debug, Clone, PartialEq, Eq)]
82 struct FailArgs {
83 value: usize,
84 should_fail: bool,
85 }
86
87 #[derive(Debug, PartialEq, Eq)]
88 struct TestError(String);
89
90 #[test]
91 fn test_try_init_success() {
92 let init = |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
93 if args.should_fail {
94 Err(TestError("Failed".to_string()))
95 } else {
96 Ok(Counter(args.value))
97 }
98 };
99
100 let result = ComponentMap::try_init(
101 [
102 (
103 "key1",
104 FailArgs {
105 value: 1,
106 should_fail: false,
107 },
108 ),
109 (
110 "key2",
111 FailArgs {
112 value: 2,
113 should_fail: false,
114 },
115 ),
116 ],
117 init,
118 );
119
120 assert!(result.is_ok());
121 let manager = result.unwrap();
122 assert_eq!(manager.map.len(), 2);
123 assert_eq!(manager.map.get("key1").unwrap().component, Counter(1));
124 assert_eq!(manager.map.get("key2").unwrap().component, Counter(2));
125 }
126
127 #[test]
128 fn test_try_init_failure() {
129 let init = |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
130 if args.should_fail {
131 Err(TestError("Failed".to_string()))
132 } else {
133 Ok(Counter(args.value))
134 }
135 };
136
137 let result = ComponentMap::try_init(
138 [
139 (
140 "key1",
141 FailArgs {
142 value: 1,
143 should_fail: false,
144 },
145 ),
146 (
147 "key2",
148 FailArgs {
149 value: 2,
150 should_fail: true,
151 },
152 ),
153 ],
154 init,
155 );
156
157 assert!(result.is_err());
158 assert_eq!(result.err().unwrap(), TestError("Failed".to_string()));
159 }
160
161 #[test]
162 fn test_try_init_empty() {
163 let init = |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
164 if args.should_fail {
165 Err(TestError("Failed".to_string()))
166 } else {
167 Ok(Counter(args.value))
168 }
169 };
170
171 let result: Result<ComponentMap<&str, FailArgs, Counter, _>, TestError> =
172 ComponentMap::try_init([], init);
173
174 assert!(result.is_ok());
175 assert_eq!(result.unwrap().map.len(), 0);
176 }
177
178 #[test]
179 fn test_try_init_all_fail() {
180 let init = |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
181 if args.should_fail {
182 Err(TestError("Failed".to_string()))
183 } else {
184 Ok(Counter(args.value))
185 }
186 };
187
188 let result = ComponentMap::try_init(
189 [
190 (
191 "key1",
192 FailArgs {
193 value: 1,
194 should_fail: true,
195 },
196 ),
197 (
198 "key2",
199 FailArgs {
200 value: 2,
201 should_fail: true,
202 },
203 ),
204 ],
205 init,
206 );
207
208 assert!(result.is_err());
209 }
210
211 #[test]
212 fn test_try_reinit_all_success() {
213 let init = |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
214 if args.should_fail {
215 Err(TestError("Failed".to_string()))
216 } else {
217 Ok(Counter(args.value * 2))
218 }
219 };
220
221 let mut manager = ComponentMap::try_init(
222 [
223 (
224 "key1",
225 FailArgs {
226 value: 1,
227 should_fail: false,
228 },
229 ),
230 (
231 "key2",
232 FailArgs {
233 value: 2,
234 should_fail: false,
235 },
236 ),
237 ],
238 init,
239 )
240 .unwrap();
241
242 let results: Vec<_> = manager.try_reinit_all().collect();
243
244 assert_eq!(results.len(), 2);
245 assert!(results.iter().all(|r| r.value.is_ok()));
246
247 assert_eq!(manager.map.get("key1").unwrap().component, Counter(2));
249 assert_eq!(manager.map.get("key2").unwrap().component, Counter(4));
250 }
251
252 #[test]
253 fn test_try_reinit_all_with_failure() {
254 let call_count = Arc::new(Mutex::new(0));
255 let call_count_clone = call_count.clone();
256
257 let init = move |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
258 let count = *call_count_clone.lock().unwrap();
259 *call_count_clone.lock().unwrap() += 1;
260
261 if count >= 2 && args.should_fail {
263 Err(TestError("Failed on reinit".to_string()))
264 } else {
265 Ok(Counter(args.value * 2))
266 }
267 };
268
269 let mut manager = ComponentMap::try_init(
270 [
271 (
272 "key1",
273 FailArgs {
274 value: 1,
275 should_fail: false,
276 },
277 ),
278 (
279 "key2",
280 FailArgs {
281 value: 2,
282 should_fail: true,
283 },
284 ),
285 ],
286 init,
287 )
288 .unwrap();
289
290 let results: Vec<_> = manager.try_reinit_all().collect();
291
292 assert_eq!(results.len(), 2);
293 let failures: Vec<_> = results.iter().filter(|r| r.value.is_err()).collect();
294 assert_eq!(failures.len(), 1);
295 let successes: Vec<_> = results.iter().filter(|r| r.value.is_ok()).collect();
296 assert_eq!(successes.len(), 1);
297 }
298
299 #[test]
300 fn test_try_reinit_all_preserves_on_error() {
301 let init = |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
302 if args.should_fail {
303 Err(TestError("Failed".to_string()))
304 } else {
305 Ok(Counter(args.value * 2))
306 }
307 };
308
309 let mut manager = ComponentMap::try_init(
310 [(
311 "key1",
312 FailArgs {
313 value: 1,
314 should_fail: false,
315 },
316 )],
317 init,
318 )
319 .unwrap();
320
321 manager.map.get_mut("key1").unwrap().args.should_fail = true;
323
324 let original_value = manager.map.get("key1").unwrap().component.clone();
325 let _results: Vec<_> = manager.try_reinit_all().collect();
326
327 assert_eq!(manager.map.get("key1").unwrap().component, original_value);
329 }
330
331 #[test]
332 fn test_try_reinit_specific_keys_success() {
333 let init = |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
334 if args.should_fail {
335 Err(TestError("Failed".to_string()))
336 } else {
337 Ok(Counter(args.value * 3))
338 }
339 };
340
341 let mut manager = ComponentMap::try_init(
342 [
343 (
344 "key1",
345 FailArgs {
346 value: 1,
347 should_fail: false,
348 },
349 ),
350 (
351 "key2",
352 FailArgs {
353 value: 2,
354 should_fail: false,
355 },
356 ),
357 ],
358 init,
359 )
360 .unwrap();
361
362 let results: Vec<_> = manager.try_reinit(["key1"]).collect();
363
364 assert_eq!(results.len(), 1);
365 assert!(results[0].value.as_ref().unwrap().is_ok());
366 assert_eq!(manager.map.get("key1").unwrap().component, Counter(3));
367 assert_eq!(manager.map.get("key2").unwrap().component, Counter(6));
369 }
370
371 #[test]
372 fn test_try_reinit_nonexistent_key() {
373 let init = |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
374 if args.should_fail {
375 Err(TestError("Failed".to_string()))
376 } else {
377 Ok(Counter(args.value))
378 }
379 };
380
381 let mut manager = ComponentMap::try_init(
382 [(
383 "key1",
384 FailArgs {
385 value: 1,
386 should_fail: false,
387 },
388 )],
389 init,
390 )
391 .unwrap();
392
393 let results: Vec<_> = manager.try_reinit(["nonexistent"]).collect();
394
395 assert_eq!(results.len(), 1);
396 assert_eq!(results[0].key, "nonexistent");
397 assert!(results[0].value.is_none());
398 }
399
400 #[test]
401 fn test_try_reinit_with_failure() {
402 let init = |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
403 if args.should_fail {
404 Err(TestError("Failed".to_string()))
405 } else {
406 Ok(Counter(args.value))
407 }
408 };
409
410 let mut manager = ComponentMap::try_init(
411 [(
412 "key1",
413 FailArgs {
414 value: 1,
415 should_fail: false,
416 },
417 )],
418 init,
419 )
420 .unwrap();
421
422 manager.map.get_mut("key1").unwrap().args.should_fail = true;
424
425 let results: Vec<_> = manager.try_reinit(["key1"]).collect();
426
427 assert_eq!(results.len(), 1);
428 assert!(results[0].value.as_ref().unwrap().is_err());
429 }
430
431 #[test]
432 fn test_try_update_new_key_success() {
433 let init = |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
434 if args.should_fail {
435 Err(TestError("Failed".to_string()))
436 } else {
437 Ok(Counter(args.value))
438 }
439 };
440
441 let mut manager = ComponentMap::try_init(
442 [(
443 "key1",
444 FailArgs {
445 value: 1,
446 should_fail: false,
447 },
448 )],
449 init,
450 )
451 .unwrap();
452
453 let results: Vec<_> = manager
454 .try_update([(
455 "key2",
456 FailArgs {
457 value: 20,
458 should_fail: false,
459 },
460 )])
461 .collect();
462
463 assert_eq!(results.len(), 1);
464 assert!(results[0].value.is_none());
465 assert_eq!(manager.map.len(), 2);
466 assert_eq!(manager.map.get("key2").unwrap().component, Counter(20));
467 }
468
469 #[test]
470 fn test_try_update_existing_key_success() {
471 let init = |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
472 if args.should_fail {
473 Err(TestError("Failed".to_string()))
474 } else {
475 Ok(Counter(args.value))
476 }
477 };
478
479 let mut manager = ComponentMap::try_init(
480 [(
481 "key1",
482 FailArgs {
483 value: 1,
484 should_fail: false,
485 },
486 )],
487 init,
488 )
489 .unwrap();
490
491 let results: Vec<_> = manager
492 .try_update([(
493 "key1",
494 FailArgs {
495 value: 10,
496 should_fail: false,
497 },
498 )])
499 .collect();
500
501 assert_eq!(results.len(), 1);
502 assert!(results[0].value.is_some());
503 let prev = results[0].value.as_ref().unwrap().as_ref().unwrap();
504 assert_eq!(prev.component, Counter(1));
505
506 assert_eq!(manager.map.get("key1").unwrap().component, Counter(10));
507 }
508
509 #[test]
510 fn test_try_update_failure() {
511 let init = |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
512 if args.should_fail {
513 Err(TestError("Failed".to_string()))
514 } else {
515 Ok(Counter(args.value))
516 }
517 };
518
519 let mut manager = ComponentMap::try_init(
520 [(
521 "key1",
522 FailArgs {
523 value: 1,
524 should_fail: false,
525 },
526 )],
527 init,
528 )
529 .unwrap();
530
531 let results: Vec<_> = manager
532 .try_update([(
533 "key2",
534 FailArgs {
535 value: 20,
536 should_fail: true,
537 },
538 )])
539 .collect();
540
541 assert_eq!(results.len(), 1);
542 assert!(results[0].value.is_some());
543 assert!(results[0].value.as_ref().unwrap().is_err());
544
545 assert_eq!(manager.map.len(), 1);
547 assert!(manager.map.get("key2").is_none());
548 }
549
550 #[test]
551 fn test_try_update_multiple_mixed() {
552 let init = |_key: &&str, args: &FailArgs| -> Result<Counter, TestError> {
553 if args.should_fail {
554 Err(TestError("Failed".to_string()))
555 } else {
556 Ok(Counter(args.value))
557 }
558 };
559
560 let mut manager = ComponentMap::try_init(
561 [(
562 "key1",
563 FailArgs {
564 value: 1,
565 should_fail: false,
566 },
567 )],
568 init,
569 )
570 .unwrap();
571
572 let results: Vec<_> = manager
573 .try_update([
574 (
575 "key2",
576 FailArgs {
577 value: 20,
578 should_fail: false,
579 },
580 ),
581 (
582 "key3",
583 FailArgs {
584 value: 30,
585 should_fail: true,
586 },
587 ),
588 (
589 "key4",
590 FailArgs {
591 value: 40,
592 should_fail: false,
593 },
594 ),
595 ])
596 .collect();
597
598 assert_eq!(results.len(), 3);
599
600 assert_eq!(manager.map.len(), 3); assert!(manager.map.get("key2").is_some());
603 assert!(manager.map.get("key3").is_none());
604 assert!(manager.map.get("key4").is_some());
605 }
606}