async_ecs/resource/
resources.rs1use std::marker::PhantomData;
2use std::ops::{Deref, DerefMut};
3
4use hashbrown::HashMap;
5use mopa::Any;
6
7pub use super::cell::Cell;
8
9use super::{
10 cell::{Ref as CellRef, RefMut as CellRefMut},
11 entry::Entry,
12 Resource, ResourceId,
13};
14
15#[derive(Default)]
16pub struct Resources {
17 resources: HashMap<ResourceId, Cell<Box<dyn Resource>>>,
18}
19
20pub struct Ref<'a, R: 'a> {
21 inner: CellRef<'a, dyn Resource>,
22 phantom: PhantomData<&'a R>,
23}
24
25pub struct RefMut<'a, R: 'a> {
26 inner: CellRefMut<'a, dyn Resource>,
27 phantom: PhantomData<&'a R>,
28}
29
30macro_rules! fetch_panic {
31 () => {{
32 panic!(
33 "\
34 Tried to fetch resource from the resources map, but the resource does not exist.\n\
35\n\
36 Resource: `{resource_name_full}`\n\
37\n\
38 You may ensure the resource exists!\
39 ",
40 resource_name_full = std::any::type_name::<R>(),
41 )
42 }};
43}
44
45impl Resources {
57 pub fn entry<R>(&mut self) -> Entry<R>
59 where
60 R: Resource,
61 {
62 Entry::new(self.resources.entry(ResourceId::new::<R>()))
63 }
64
65 pub fn insert<R>(&mut self, r: R)
88 where
89 R: Resource,
90 {
91 self.resources
92 .insert(ResourceId::new::<R>(), Cell::new(Box::new(r)));
93 }
94
95 pub fn remove<R>(&mut self) -> Option<R>
104 where
105 R: Resource,
106 {
107 self.resources
108 .remove(&ResourceId::new::<R>())
109 .map(Cell::into_inner)
110 .map(|x: Box<dyn Resource>| x.downcast())
111 .map(|x: Result<Box<R>, _>| x.ok().unwrap())
112 .map(|x| *x)
113 }
114
115 pub fn contains<R>(&self) -> bool
117 where
118 R: Resource,
119 {
120 self.resources.contains_key(&ResourceId::new::<R>())
121 }
122
123 pub fn borrow<R>(&self) -> Ref<R>
131 where
132 R: Resource,
133 {
134 self.try_borrow().unwrap_or_else(|| fetch_panic!())
135 }
136
137 pub fn try_borrow<R>(&self) -> Option<Ref<R>>
140 where
141 R: Resource,
142 {
143 self.resources.get(&ResourceId::new::<R>()).map(|r| Ref {
144 inner: CellRef::map(r.borrow(), Box::as_ref),
145 phantom: PhantomData,
146 })
147 }
148
149 pub fn borrow_mut<R>(&self) -> RefMut<R>
158 where
159 R: Resource,
160 {
161 self.try_borrow_mut().unwrap_or_else(|| fetch_panic!())
162 }
163
164 pub fn try_borrow_mut<R>(&self) -> Option<RefMut<R>>
167 where
168 R: Resource,
169 {
170 self.resources.get(&ResourceId::new::<R>()).map(|r| RefMut {
171 inner: r.borrow_mut().map(Box::as_mut),
172 phantom: PhantomData,
173 })
174 }
175
176 pub fn get_mut<R: Resource>(&mut self) -> Option<&mut R> {
179 self.get_resource_mut(ResourceId::new::<R>())
180 .map(|res| res.downcast_mut().unwrap())
181 }
182
183 pub fn get_resource_mut(&mut self, id: ResourceId) -> Option<&mut dyn Resource> {
186 self.resources
187 .get_mut(&id)
188 .map(Cell::get_mut)
189 .map(Box::as_mut)
190 }
191
192 pub fn get_raw(&self, id: &ResourceId) -> Option<&Cell<Box<dyn Resource>>> {
194 self.resources.get(id)
195 }
196}
197
198impl<T> Resource for T where T: Any + Send + Sync {}
201
202mod __resource_mopafy_scope {
203 #![allow(clippy::all)]
204
205 use mopa::mopafy;
206
207 use super::super::Resource;
208
209 mopafy!(Resource);
210}
211
212impl<'a, R> Ref<'a, R> {
215 pub fn new(inner: CellRef<'a, dyn Resource>) -> Self {
216 Self {
217 inner,
218 phantom: PhantomData,
219 }
220 }
221}
222
223impl<'a, R> Deref for Ref<'a, R>
224where
225 R: Resource,
226{
227 type Target = R;
228
229 fn deref(&self) -> &R {
230 unsafe { self.inner.downcast_ref_unchecked() }
231 }
232}
233
234impl<'a, R> Clone for Ref<'a, R> {
235 fn clone(&self) -> Self {
236 Ref {
237 inner: self.inner.clone(),
238 phantom: PhantomData,
239 }
240 }
241}
242
243impl<'a, R> RefMut<'a, R> {
246 pub fn new(inner: CellRefMut<'a, dyn Resource>) -> Self {
247 Self {
248 inner,
249 phantom: PhantomData,
250 }
251 }
252}
253
254impl<'a, R> Deref for RefMut<'a, R>
255where
256 R: Resource,
257{
258 type Target = R;
259
260 fn deref(&self) -> &R {
261 unsafe { self.inner.downcast_ref_unchecked() }
262 }
263}
264
265impl<'a, R> DerefMut for RefMut<'a, R>
266where
267 R: Resource,
268{
269 fn deref_mut(&mut self) -> &mut R {
270 unsafe { self.inner.downcast_mut_unchecked() }
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use super::*;
277
278 #[derive(Default)]
279 struct Res;
280
281 #[test]
282 fn insert() {
283 struct Foo;
284
285 let mut resources = Resources::default();
286 resources.insert(Res);
287
288 assert!(resources.contains::<Res>());
289 assert!(!resources.contains::<Foo>());
290 }
291
292 #[test]
293 #[should_panic(expected = "but it was already borrowed")]
294 fn read_write_fails() {
295 let mut resources = Resources::default();
296 resources.insert(Res);
297
298 let _read = resources.borrow::<Res>();
299 let _write = resources.borrow_mut::<Res>();
300 }
301
302 #[test]
303 #[should_panic(expected = "but it was already borrowed mutably")]
304 fn write_read_fails() {
305 let mut resources = Resources::default();
306 resources.insert(Res);
307
308 let _write = resources.borrow_mut::<Res>();
309 let _read = resources.borrow::<Res>();
310 }
311
312 #[test]
313 fn remove_insert() {
314 let mut resources = Resources::default();
315 resources.insert(Res);
316
317 assert!(resources.contains::<Res>());
318
319 resources.remove::<Res>().unwrap();
320
321 assert!(!resources.contains::<Res>());
322
323 resources.insert(Res);
324
325 assert!(resources.contains::<Res>());
326 }
327}