Skip to main content

component_map/
async_infallible.rs

1use crate::{ComponentMap, Keyed, WithArgs};
2use futures::future::join_all;
3
4impl<Key, Args, Comp, FnInit> ComponentMap<Key, Args, Comp, FnInit> {
5    pub async fn init_async(args: impl IntoIterator<Item = (Key, Args)>, init: FnInit) -> Self
6    where
7        Key: Eq + std::hash::Hash,
8        FnInit: AsyncFn(&Args) -> Comp + Clone,
9    {
10        let components_fut = args.into_iter().map(|(key, args)| {
11            let init = init.clone();
12            async move {
13                let component = (init)(&args).await;
14                (key, WithArgs { component, args })
15            }
16        });
17
18        let map = join_all(components_fut).await.into_iter().collect();
19
20        Self { map, init }
21    }
22
23    pub async fn reinit_all_async(&mut self) -> impl Iterator<Item = Keyed<&Key, Comp>>
24    where
25        Key: Clone,
26        FnInit: AsyncFn(&Args) -> Comp + Clone,
27    {
28        let next_components_fut = self
29            .map
30            .values()
31            .map(|component| (self.init)(&component.args));
32
33        let next_components = join_all(next_components_fut).await;
34
35        self.map
36            .iter_mut()
37            .zip(next_components)
38            .map(|((key, prev), next)| {
39                let prev = std::mem::replace(&mut prev.component, next);
40                Keyed::new(key, prev)
41            })
42    }
43
44    pub async fn reinit_async(
45        &mut self,
46        keys: impl IntoIterator<Item = Key>,
47    ) -> impl Iterator<Item = Keyed<Key, Option<Comp>>>
48    where
49        Key: Eq + std::hash::Hash + Clone,
50        FnInit: AsyncFn(&Args) -> Comp + Clone,
51    {
52        let next_components_fut = keys.into_iter().map(|key| {
53            let init = self.init.clone();
54            let args = self.map.get(&key).map(|component| &component.args);
55            async move {
56                let next = match args {
57                    Some(args) => Some((init)(args).await),
58                    None => None,
59                };
60                Keyed::new(key, next)
61            }
62        });
63
64        let results = join_all(next_components_fut).await;
65
66        results.into_iter().map(|Keyed { key, value: next }| {
67            let prev = next.and_then(|next| {
68                self.map
69                    .get_mut(&key)
70                    .map(|component| std::mem::replace(&mut component.component, next))
71            });
72            Keyed::new(key, prev)
73        })
74    }
75
76    pub async fn update_async(
77        &mut self,
78        updates: impl IntoIterator<Item = (Key, Args)>,
79    ) -> impl Iterator<Item = Keyed<Key, Option<WithArgs<Args, Comp>>>>
80    where
81        Key: Clone + Eq + std::hash::Hash,
82        FnInit: AsyncFn(&Args) -> Comp + Clone,
83    {
84        let updated_components_fut = updates.into_iter().map(|(key, args)| {
85            let init = self.init.clone();
86            async move {
87                let component = (init)(&args).await;
88                (key, WithArgs { component, args })
89            }
90        });
91
92        join_all(updated_components_fut)
93            .await
94            .into_iter()
95            .map(|(key, component)| {
96                let prev = self.map.insert(key.clone(), component);
97                Keyed::new(key, prev)
98            })
99    }
100}
101
102#[cfg(test)]
103mod tests {
104    use super::*;
105    use std::sync::{Arc, Mutex};
106
107    #[derive(Debug, Clone, PartialEq, Eq)]
108    struct Counter(usize);
109
110    #[derive(Debug, Clone, PartialEq, Eq)]
111    struct Args {
112        value: usize,
113    }
114
115    #[tokio::test]
116    async fn test_init_async() {
117        let init = |args: &Args| {
118            let value = args.value;
119            async move { Counter(value) }
120        };
121        let manager = ComponentMap::init_async(
122            [("key1", Args { value: 1 }), ("key2", Args { value: 2 })],
123            init,
124        )
125        .await;
126
127        assert_eq!(manager.components().len(), 2);
128        assert_eq!(
129            manager.components().get("key1").unwrap().component,
130            Counter(1)
131        );
132        assert_eq!(
133            manager.components().get("key2").unwrap().component,
134            Counter(2)
135        );
136        assert_eq!(manager.components().get("key1").unwrap().args.value, 1);
137    }
138
139    #[tokio::test]
140    async fn test_init_async_empty() {
141        let init = |args: &Args| {
142            let value = args.value;
143            async move { Counter(value) }
144        };
145        let manager: ComponentMap<&str, Args, Counter, _> =
146            ComponentMap::init_async([], init).await;
147
148        assert_eq!(manager.components().len(), 0);
149    }
150
151    #[tokio::test]
152    async fn test_reinit_all_async() {
153        let call_count = Arc::new(Mutex::new(0));
154        let call_count_clone = call_count.clone();
155
156        let init = move |args: &Args| {
157            let call_count = call_count_clone.clone();
158            let value = args.value;
159            async move {
160                *call_count.lock().unwrap() += 1;
161                Counter(value * 2)
162            }
163        };
164
165        let mut manager = ComponentMap::init_async(
166            [("key1", Args { value: 1 }), ("key2", Args { value: 2 })],
167            init,
168        )
169        .await;
170
171        let prev_components: Vec<_> = manager.reinit_all_async().await.collect();
172
173        assert_eq!(prev_components.len(), 2);
174        assert_eq!(
175            manager.components().get("key1").unwrap().component,
176            Counter(2)
177        );
178        assert_eq!(
179            manager.components().get("key2").unwrap().component,
180            Counter(4)
181        );
182
183        // Should have called init 4 times (2 for init_async, 2 for reinit_all_async)
184        assert_eq!(*call_count.lock().unwrap(), 4);
185    }
186
187    #[tokio::test]
188    async fn test_reinit_all_async_empty() {
189        let init = |args: &Args| {
190            let value = args.value;
191            async move { Counter(value) }
192        };
193        let mut manager: ComponentMap<&str, Args, Counter, _> =
194            ComponentMap::init_async([], init).await;
195
196        let results: Vec<_> = manager.reinit_all_async().await.collect();
197        assert_eq!(results.len(), 0);
198    }
199
200    #[tokio::test]
201    async fn test_reinit_async_existing_key() {
202        let init = |args: &Args| {
203            let value = args.value;
204            async move { Counter(value * 2) }
205        };
206
207        let mut manager = ComponentMap::init_async(
208            [("key1", Args { value: 1 }), ("key2", Args { value: 2 })],
209            init,
210        )
211        .await;
212
213        let results: Vec<_> = manager.reinit_async(["key1"]).await.collect();
214
215        assert_eq!(results.len(), 1);
216        assert_eq!(results[0].key, "key1");
217        assert_eq!(results[0].value, Some(Counter(2)));
218
219        assert_eq!(
220            manager.components().get("key1").unwrap().component,
221            Counter(2)
222        );
223        assert_eq!(
224            manager.components().get("key2").unwrap().component,
225            Counter(4)
226        );
227    }
228
229    #[tokio::test]
230    async fn test_reinit_async_multiple_keys() {
231        let init = |args: &Args| {
232            let value = args.value;
233            async move { Counter(value * 3) }
234        };
235
236        let mut manager = ComponentMap::init_async(
237            [
238                ("key1", Args { value: 1 }),
239                ("key2", Args { value: 2 }),
240                ("key3", Args { value: 3 }),
241            ],
242            init,
243        )
244        .await;
245
246        let results: Vec<_> = manager.reinit_async(["key1", "key3"]).await.collect();
247
248        assert_eq!(results.len(), 2);
249        assert_eq!(
250            manager.components().get("key1").unwrap().component,
251            Counter(3)
252        );
253        assert_eq!(
254            manager.components().get("key2").unwrap().component,
255            Counter(6)
256        );
257        assert_eq!(
258            manager.components().get("key3").unwrap().component,
259            Counter(9)
260        );
261    }
262
263    #[tokio::test]
264    async fn test_reinit_async_nonexistent_key() {
265        let init = |args: &Args| {
266            let value = args.value;
267            async move { Counter(value) }
268        };
269
270        let mut manager = ComponentMap::init_async([("key1", Args { value: 1 })], init).await;
271
272        let results: Vec<_> = manager.reinit_async(["nonexistent"]).await.collect();
273
274        assert_eq!(results.len(), 1);
275        assert_eq!(results[0].key, "nonexistent");
276        assert_eq!(results[0].value, None);
277        assert_eq!(manager.components().len(), 1);
278    }
279
280    #[tokio::test]
281    async fn test_update_async_existing() {
282        let init = |args: &Args| {
283            let value = args.value;
284            async move { Counter(value) }
285        };
286
287        let mut manager = ComponentMap::init_async([("key1", Args { value: 1 })], init).await;
288
289        let results: Vec<_> = manager
290            .update_async([("key1", Args { value: 10 })])
291            .await
292            .collect();
293
294        assert_eq!(results.len(), 1);
295        assert_eq!(results[0].key, "key1");
296        assert!(results[0].value.is_some());
297        assert_eq!(results[0].value.as_ref().unwrap().component, Counter(1));
298
299        assert_eq!(
300            manager.components().get("key1").unwrap().component,
301            Counter(10)
302        );
303        assert_eq!(manager.components().get("key1").unwrap().args.value, 10);
304    }
305
306    #[tokio::test]
307    async fn test_update_async_new_key() {
308        let init = |args: &Args| {
309            let value = args.value;
310            async move { Counter(value) }
311        };
312
313        let mut manager = ComponentMap::init_async([("key1", Args { value: 1 })], init).await;
314
315        let results: Vec<_> = manager
316            .update_async([("key2", Args { value: 20 })])
317            .await
318            .collect();
319
320        assert_eq!(results.len(), 1);
321        assert_eq!(results[0].key, "key2");
322        assert!(results[0].value.is_none());
323
324        assert_eq!(manager.components().len(), 2);
325        assert_eq!(
326            manager.components().get("key2").unwrap().component,
327            Counter(20)
328        );
329    }
330
331    #[tokio::test]
332    async fn test_update_async_multiple() {
333        let init = |args: &Args| {
334            let value = args.value;
335            async move { Counter(value) }
336        };
337
338        let mut manager = ComponentMap::init_async([("key1", Args { value: 1 })], init).await;
339
340        let results: Vec<_> = manager
341            .update_async([
342                ("key1", Args { value: 10 }),
343                ("key2", Args { value: 20 }),
344                ("key3", Args { value: 30 }),
345            ])
346            .await
347            .collect();
348
349        assert_eq!(results.len(), 3);
350        assert_eq!(manager.components().len(), 3);
351        assert_eq!(
352            manager.components().get("key1").unwrap().component,
353            Counter(10)
354        );
355        assert_eq!(
356            manager.components().get("key2").unwrap().component,
357            Counter(20)
358        );
359        assert_eq!(
360            manager.components().get("key3").unwrap().component,
361            Counter(30)
362        );
363    }
364}