1use failure::Error;
29use std::sync::{Arc, Mutex};
30use uuid::Uuid;
31
32use crate::utils::prelude::{FastHashMap, HandleLike, ObjectPool};
33
34use super::state::ResourceState;
35
36pub trait ResourceLoader: Send + Sync {
37 type Handle: Send;
38 type Intermediate: Send;
39 type Resource: Send;
40
41 fn load(&self, _: Self::Handle, _: &[u8]) -> Result<Self::Intermediate, Error>;
42 fn create(&self, _: Self::Handle, _: Self::Intermediate) -> Result<Self::Resource, Error>;
43 fn delete(&self, _: Self::Handle, _: Self::Resource);
44}
45
46pub struct ResourcePool<H, Loader>
49where
50 H: HandleLike + 'static,
51 Loader: ResourceLoader<Handle = H> + Clone + 'static,
52{
53 items: ObjectPool<H, Item<Loader::Resource>>,
54 requests: FastHashMap<H, Arc<Mutex<ResourceAsyncState<Loader::Intermediate>>>>,
55 registry: FastHashMap<Uuid, H>,
56 loader: Loader,
57}
58
59impl<H, Loader> ResourcePool<H, Loader>
60where
61 H: HandleLike + 'static,
62 Loader: ResourceLoader<Handle = H> + Clone + 'static,
63{
64 pub fn new(loader: Loader) -> Self {
66 ResourcePool {
67 items: ObjectPool::new(),
68 registry: FastHashMap::default(),
69 requests: FastHashMap::default(),
70 loader,
71 }
72 }
73
74 pub fn advance(&mut self) -> Result<(), Error> {
75 let items = &mut self.items;
76 let loader = &self.loader;
77
78 self.requests.retain(|&handle, req| {
79 let mut req = req.lock().unwrap();
80 if let ResourceAsyncState::NotReady = *req {
81 return true;
82 }
83
84 let mut tmp = ResourceAsyncState::NotReady;
85 std::mem::swap(&mut *req, &mut tmp);
86
87 match tmp {
88 ResourceAsyncState::Err(err) => {
89 warn!("{:?}", err);
90 if let Some(item) = items.get_mut(handle) {
91 item.error = Some(err);
92 }
93 }
94 ResourceAsyncState::Ok(intermediate) => {
95 if let Some(item) = items.get_mut(handle) {
96 match loader.create(handle, intermediate) {
97 Ok(resource) => item.resource = Some(resource),
98 Err(err) => {
99 warn!("{:?}", err);
100 item.error = Some(err);
101 }
102 }
103 }
104 }
105 _ => unreachable!(),
106 }
107
108 false
109 });
110
111 Ok(())
112 }
113
114 #[inline]
118 pub fn create(&mut self, params: Loader::Intermediate) -> Result<H, Error> {
119 let handle = self.alloc(None);
120 match self.loader.create(handle, params) {
121 Ok(value) => {
122 self.items.get_mut(handle).unwrap().resource = Some(value);
123 Ok(handle)
124 }
125 Err(error) => {
126 self.delete(handle);
127 Err(error)
128 }
129 }
130 }
131
132 #[inline]
134 pub fn create_from<T: AsRef<str>>(&mut self, url: T) -> Result<H, Error> {
135 let url = url.as_ref();
136 let uuid = crate::res::find(url)
137 .ok_or_else(|| format_err!("Could not found resource '{}'.", url))?;
138 self.create_from_uuid(uuid)
139 }
140
141 #[inline]
143 pub fn create_from_uuid(&mut self, uuid: Uuid) -> Result<H, Error> {
144 if let Some(&handle) = self.registry.get(&uuid) {
145 self.items.get_mut(handle).unwrap().rc += 1;
146 return Ok(handle);
147 }
148
149 let handle = self.alloc(Some(uuid));
150
151 let rx = Arc::new(Mutex::new(ResourceAsyncState::NotReady));
152 let tx = rx.clone();
153 let loader = self.loader.clone();
154
155 let result = crate::res::load_with_callback(uuid, move |rsp| match rsp {
156 Ok(bytes) => {
157 let itermediate = loader.load(handle, &bytes);
158
159 match itermediate {
160 Ok(item) => {
161 *tx.lock().unwrap() = ResourceAsyncState::Ok(item);
162 }
163 Err(err) => {
164 *tx.lock().unwrap() = ResourceAsyncState::Err(err);
165 }
166 }
167 }
168
169 Err(err) => {
170 *tx.lock().unwrap() = ResourceAsyncState::Err(err);
171 }
172 });
173
174 match result {
175 Ok(_) => {
176 self.requests.insert(handle, rx);
177 Ok(handle)
178 }
179 Err(err) => {
180 self.delete(handle);
181 Err(err)
182 }
183 }
184 }
185
186 pub fn delete(&mut self, handle: H) {
188 let disposed = self
189 .items
190 .get_mut(handle)
191 .map(|e| {
192 e.rc -= 1;
193 e.rc == 0
194 })
195 .unwrap_or(false);
196
197 if disposed {
198 let e = self.items.free(handle).unwrap();
199
200 if let Some(uuid) = e.uuid {
201 self.registry.remove(&uuid);
202 }
203
204 if let Some(resource) = e.resource {
205 self.loader.delete(handle, resource);
206 }
207 }
208 }
209
210 #[inline]
212 pub fn state(&self, handle: H) -> ResourceState {
213 self.items
214 .get(handle)
215 .map(|e| {
216 if e.resource.is_some() {
217 ResourceState::Ok
218 } else if e.error.is_some() {
219 ResourceState::Err
220 } else {
221 ResourceState::NotReady
222 }
223 })
224 .unwrap_or(ResourceState::NotReady)
225 }
226
227 #[inline]
229 pub fn contains(&self, handle: H) -> bool {
230 self.items.contains(handle)
231 }
232
233 #[inline]
235 pub fn resource(&self, handle: H) -> Option<&Loader::Resource> {
236 self.items.get(handle).and_then(|e| e.resource.as_ref())
237 }
238
239 #[inline]
241 pub fn resource_mut(&mut self, handle: H) -> Option<&mut Loader::Resource> {
242 self.items.get_mut(handle).and_then(|e| e.resource.as_mut())
243 }
244
245 #[inline]
246 fn alloc(&mut self, uuid: Option<Uuid>) -> H {
247 let entry = Item {
248 rc: 1,
249 uuid,
250 resource: None,
251 error: None,
252 };
253
254 let handle = self.items.create(entry);
255
256 if let Some(uuid) = uuid {
257 self.registry.insert(uuid, handle);
258 }
259
260 handle
261 }
262}
263
264struct Item<T> {
265 rc: u32,
266 uuid: Option<Uuid>,
267 resource: Option<T>,
268 error: Option<Error>,
269}
270
271enum ResourceAsyncState<T> {
272 Ok(T),
273 Err(Error),
274 NotReady,
275}