mail_core/resource/
loading.rs1use std::{
3 borrow::{ToOwned, Borrow},
4 collections::HashMap,
5 mem
6};
7
8use futures::{
9 Future, Poll, Async,
10 try_ready,
11 future::{self, JoinAll}
12};
13
14use crate::{
15 Context, MaybeEncData, Resource,
16 utils::SendBoxFuture,
17 error::ResourceLoadingError
18};
19
20pub trait ContainedResourcesAccess {
21 type Key: ToOwned + ?Sized;
22
23 fn visit_resources(&self, visitor: &mut impl FnMut(&Self::Key, &Resource));
30
31 fn access_resource_mut<R>(
41 &mut self,
42 key: &Self::Key,
43 modify: impl FnOnce(Option<&mut Resource>) -> R
44 ) -> R;
45
46 fn access_resource<R>(
48 &self,
49 key: &Self::Key,
50 modify: impl FnOnce(Option<&Resource>) -> R
51 ) -> R;
52}
53
54
55impl ContainedResourcesAccess for Vec<Resource> {
56 type Key = usize;
57
58 fn visit_resources(&self, visitor: &mut impl FnMut(&Self::Key, &Resource)) {
59 for (idx, resource) in self.iter().enumerate() {
60 visitor(&idx, resource)
61 }
62 }
63
64 fn access_resource_mut<R>(
65 &mut self,
66 key: &Self::Key,
67 modify: impl FnOnce(Option<&mut Resource>) -> R
68 ) -> R {
69 modify(self.get_mut(*key))
70 }
71
72 fn access_resource<R>(
74 &self,
75 key: &Self::Key,
76 modify: impl FnOnce(Option<&Resource>) -> R
77 ) -> R {
78 modify(self.get(*key))
79 }
80}
81
82impl ContainedResourcesAccess for HashMap<String, Resource> {
83 type Key = str;
84
85 fn visit_resources(&self, visitor: &mut impl FnMut(&Self::Key, &Resource)) {
86 for (key, resource) in self.iter() {
87 visitor(&key, resource)
88 }
89 }
90
91 fn access_resource_mut<R>(
92 &mut self,
93 key: &Self::Key,
94 modify: impl FnOnce(Option<&mut Resource>) -> R
95 ) -> R {
96 modify(self.get_mut(key))
97 }
98
99 fn access_resource<R>(
101 &self,
102 key: &Self::Key,
103 modify: impl FnOnce(Option<&Resource>) -> R
104 ) -> R {
105 modify(self.get(key))
106 }
107}
108
109impl Resource {
113
114 pub fn load_container<CO>(container: CO, ctx: &impl Context)
115 -> ResourceContainerLoadingFuture<CO>
116 where CO: ContainedResourcesAccess
117 {
118 ResourceContainerLoadingFuture::start_loading(container, ctx)
119 }
120}
121
122pub struct ResourceContainerLoadingFuture<C>
123 where C: ContainedResourcesAccess
124{
125 inner: Option<InnerFuture<C>>
126}
127
128struct InnerFuture<C>
129 where C: ContainedResourcesAccess
130{
131 container: C,
132 keys: Vec<<C::Key as ToOwned>::Owned>,
133 futs: JoinAll<Vec<SendBoxFuture<MaybeEncData, ResourceLoadingError>>>
134}
135
136impl<CO> ResourceContainerLoadingFuture<CO>
137 where CO: ContainedResourcesAccess
138{
139 pub fn start_loading(container: CO, ctx: &impl Context) -> Self {
140 let mut keys = Vec::new();
141 let mut futs = Vec::new();
142
143 container.visit_resources(&mut |key, resource| {
144 if let &Resource::Source(ref source) = resource {
145 let fut = ctx.load_resource(source);
146 futs.push(fut);
147 keys.push(key.to_owned());
148 }
149 });
150
151 let futs = future::join_all(futs);
152
153 ResourceContainerLoadingFuture {
154 inner: Some(InnerFuture {
155 container,
156 keys,
157 futs
158 }),
159 }
160 }
161}
162
163impl<C> Future for ResourceContainerLoadingFuture<C>
164 where C: ContainedResourcesAccess
165{
166 type Item = C;
167 type Error = ResourceLoadingError;
168
169 fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
170 let loaded;
171
172 if let Some(loading) = self.inner.as_mut().map(|inner| &mut inner.futs) {
173 loaded = try_ready!(loading.poll());
174 } else {
175 panic!("future called after it resolved");
176 };
177
178 let InnerFuture { mut container, keys, futs:_ } = self.inner.take().unwrap();
180
181 for (key, new_resource) in keys.into_iter().zip(loaded.into_iter()) {
182 container.access_resource_mut(key.borrow(), |resource_ref| {
183 if let Some(resource_ref) = resource_ref {
184 mem::replace(resource_ref, new_resource.to_resource());
185 }
186 })
187 }
188
189 Ok(Async::Ready(container))
190 }
191}