1use std::{
2 any::TypeId,
3 fmt,
4 ops::{Deref, DerefMut},
5};
6
7use rt_map::{BorrowFail, Cell, RtMap};
8
9use crate::{Entry, Ref, RefMut, Resource, ResourceFetchError};
10
11#[derive(Default)]
13pub struct Resources(RtMap<TypeId, Box<dyn Resource>>);
14
15impl Resources {
27 pub fn new() -> Self {
39 Self::default()
40 }
41
42 pub fn with_capacity(capacity: usize) -> Self {
54 Self(RtMap::with_capacity(capacity))
55 }
56
57 pub fn into_inner(self) -> RtMap<TypeId, Box<dyn Resource>> {
59 self.0
60 }
61
62 pub fn capacity(&self) -> usize {
75 self.0.capacity()
76 }
77
78 pub fn entry<R>(&mut self) -> Entry<R>
80 where
81 R: Resource,
82 {
83 Entry::new(self.0.entry(TypeId::of::<R>()))
84 }
85
86 pub fn insert<R>(&mut self, r: R)
110 where
111 R: Resource,
112 {
113 self.0.insert(TypeId::of::<R>(), Box::new(r));
114 }
115
116 pub fn insert_raw(&mut self, type_id: TypeId, resource: Box<dyn Resource>) {
118 if type_id != Resource::type_id(&*resource) {
119 let type_name = Resource::type_name(&*resource);
120 panic!("`Resources::insert_raw` type_id does not match `{type_name:?}.type_id()`.");
121 }
122 self.0.insert(type_id, resource);
123 }
124
125 pub fn remove<R>(&mut self) -> R
138 where
139 R: Resource,
140 {
141 self.try_remove::<R>().unwrap()
142 }
143
144 pub fn try_remove<R>(&mut self) -> Result<R, ResourceFetchError>
153 where
154 R: Resource,
155 {
156 self.0
157 .remove(&TypeId::of::<R>())
158 .map(|x: Box<dyn Resource>| x.downcast())
159 .map(|x: Result<Box<R>, _>| x.ok().unwrap())
160 .map(|x| *x)
161 .ok_or_else(ResourceFetchError::new::<R>)
162 }
163
164 pub fn contains<R>(&self) -> bool
166 where
167 R: Resource,
168 {
169 self.0.contains_key(&TypeId::of::<R>())
170 }
171
172 pub fn borrow<R>(&self) -> Ref<R>
183 where
184 R: Resource,
185 {
186 self.try_borrow::<R>()
187 .unwrap_or_else(Self::borrow_panic::<R, _>)
188 }
189
190 pub fn try_borrow<R>(&self) -> Result<Ref<R>, BorrowFail>
192 where
193 R: Resource,
194 {
195 self.0.try_borrow(&TypeId::of::<R>()).map(Ref::new)
196 }
197
198 pub fn borrow_mut<R>(&self) -> RefMut<R>
205 where
206 R: Resource,
207 {
208 self.try_borrow_mut::<R>()
209 .unwrap_or_else(Self::borrow_panic::<R, _>)
210 }
211
212 pub fn try_borrow_mut<R>(&self) -> Result<RefMut<R>, BorrowFail>
214 where
215 R: Resource,
216 {
217 self.0.try_borrow_mut(&TypeId::of::<R>()).map(RefMut::new)
218 }
219
220 pub fn get_mut<R: Resource>(&mut self) -> Option<&mut R> {
223 self.get_resource_mut(TypeId::of::<R>())
224 .map(|res| res.downcast_mut().unwrap())
225 }
226
227 pub fn get_resource_mut(&mut self, id: TypeId) -> Option<&mut dyn Resource> {
230 self.0.get_resource_mut(&id).map(|resource| &mut **resource)
231 }
232
233 pub fn get_raw(&self, id: &TypeId) -> Option<&Cell<Box<dyn Resource>>> {
235 self.0.get_raw(id)
236 }
237
238 fn borrow_panic<R, Ret>(borrow_fail: BorrowFail) -> Ret {
239 let type_name = std::any::type_name::<R>();
240 match borrow_fail {
241 BorrowFail::ValueNotFound => {
242 panic!("Expected to borrow `{type_name}`, but it does not exist.")
243 }
244 BorrowFail::BorrowConflictImm => panic!(
245 "Expected to borrow `{type_name}` immutably, but it was already borrowed mutably."
246 ),
247 BorrowFail::BorrowConflictMut => panic!(
248 "Expected to borrow `{type_name}` mutably, but it was already borrowed mutably."
249 ),
250 }
251 }
252
253 pub fn merge(&mut self, other: Resources) {
255 self.0.extend(other.into_inner().into_inner())
256 }
257}
258
259#[cfg(not(feature = "debug"))]
260impl fmt::Debug for Resources {
261 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
262 let mut debug_map = f.debug_map();
263
264 self.0.keys().for_each(|type_id| {
265 let resource = &*self.0.borrow(type_id);
266 let type_name = resource.as_ref().type_name();
267
268 debug_map.entry(&type_name, &"..");
270 });
271
272 debug_map.finish()
273 }
274}
275
276#[cfg(feature = "debug")]
277impl fmt::Debug for Resources {
278 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
279 let mut debug_map = f.debug_map();
280
281 self.0.keys().for_each(|type_id| {
282 let resource = &*self.0.borrow(type_id);
283 let type_name = resource.as_ref().type_name();
284
285 debug_map.entry(&type_name, resource);
286 });
287
288 debug_map.finish()
289 }
290}
291
292impl Deref for Resources {
293 type Target = RtMap<TypeId, Box<dyn Resource>>;
294
295 fn deref(&self) -> &Self::Target {
296 &self.0
297 }
298}
299
300impl DerefMut for Resources {
301 fn deref_mut(&mut self) -> &mut Self::Target {
302 &mut self.0
303 }
304}
305
306#[cfg(test)]
307mod tests {
308 use std::any::TypeId;
309
310 use super::Resources;
311 use crate::{BorrowFail, ResourceFetchError};
312
313 #[test]
314 fn entry_or_insert_inserts_value() {
315 #[derive(Debug, PartialEq)]
316 struct A(usize);
317
318 let mut resources = Resources::new();
319 let mut a_ref = resources.entry::<A>().or_insert(A(1));
320
321 assert_eq!(&A(1), &*a_ref);
322
323 *a_ref = A(2);
324
325 drop(a_ref);
326
327 assert_eq!(&A(2), &*resources.borrow::<A>());
328 }
329
330 #[cfg(not(feature = "debug"))]
331 #[test]
332 fn debug_uses_placeholder_for_values() {
333 let mut resources = Resources::new();
334
335 resources.insert(1u32);
336 resources.insert(2u64);
337
338 let resources_dbg = format!("{:?}", resources);
339 assert!(
340 resources_dbg.contains(r#"u32: "..""#),
341 r#"Expected `{}` to contain `u32: ".."`"#,
342 resources_dbg
343 );
344 assert!(
345 resources_dbg.contains(r#"u64: "..""#),
346 r#"Expected `{}` to contain `u64: ".."`"#,
347 resources_dbg
348 );
349 }
350
351 #[cfg(feature = "debug")]
352 #[test]
353 fn debug_uses_debug_implementation_for_values() {
354 let mut resources = Resources::new();
355
356 resources.insert(1u32);
357 resources.insert(2u64);
358
359 let resources_dbg = format!("{:?}", resources);
360 assert!(
361 resources_dbg.contains(r#"u32: 1"#),
362 r#"Expected `{}` to contain `u32: 1`"#,
363 resources_dbg
364 );
365 assert!(
366 resources_dbg.contains(r#"u64: 2"#),
367 r#"Expected `{}` to contain `u64: 2`"#,
368 resources_dbg
369 );
370 }
371
372 #[test]
373 fn with_capacity_reserves_enough_capacity() {
374 let map = Resources::with_capacity(100);
375 assert!(map.capacity() >= 100);
376 }
377
378 #[test]
379 fn into_inner() {
380 let mut resources = Resources::default();
381 resources.insert(Res);
382
383 let rt_map = resources.into_inner();
384
385 assert!(rt_map.contains_key(&TypeId::of::<Res>()));
386 }
387
388 #[test]
389 fn insert() {
390 #[cfg_attr(feature = "debug", derive(Debug))]
391 struct Foo;
392
393 let mut resources = Resources::default();
394 resources.insert(Res);
395
396 assert!(resources.contains::<Res>());
397 assert!(!resources.contains::<Foo>());
398 }
399
400 #[test]
401 fn insert_raw() {
402 #[cfg_attr(feature = "debug", derive(Debug))]
403 struct Foo;
404
405 let mut resources = Resources::default();
406 resources.insert_raw(TypeId::of::<Res>(), Box::new(Res));
407
408 assert!(resources.contains::<Res>());
409 assert!(!resources.contains::<Foo>());
410 }
411
412 #[test]
413 #[should_panic(
414 expected = "`Resources::insert_raw` type_id does not match `resman::resources::tests::Res.type_id()`."
415 )]
416 fn insert_raw_panics_when_boxed_resource_does_not_match_key() {
417 #[cfg_attr(feature = "debug", derive(Debug))]
418 struct Foo;
419
420 let mut resources = Resources::default();
421 resources.insert_raw(TypeId::of::<Foo>(), Box::new(Res));
422
423 assert!(resources.contains::<Res>());
424 }
425
426 #[test]
427 #[should_panic(
428 expected = "Expected to borrow `resman::resources::tests::Res` mutably, but it was already borrowed mutably."
429 )]
430 fn read_write_fails() {
431 let mut resources = Resources::default();
432 resources.insert(Res);
433
434 let _read = resources.borrow::<Res>();
435 let _write = resources.borrow_mut::<Res>();
436 }
437
438 #[test]
439 #[should_panic(expected = "but it was already borrowed mutably")]
440 fn write_read_fails() {
441 let mut resources = Resources::default();
442 resources.insert(Res);
443
444 let _write = resources.borrow_mut::<Res>();
445 let _read = resources.borrow::<Res>();
446 }
447
448 #[test]
449 fn remove_insert() {
450 let mut resources = Resources::default();
451 resources.insert(Res);
452
453 assert!(resources.contains::<Res>());
454
455 resources.remove::<Res>();
456
457 assert!(!resources.contains::<Res>());
458
459 resources.insert(Res);
460
461 assert!(resources.contains::<Res>());
462 }
463
464 #[test]
465 fn try_remove() {
466 let mut resources = Resources::default();
467 resources.insert(Res);
468
469 assert!(resources.contains::<Res>());
470
471 assert_eq!(Ok(Res), resources.try_remove::<Res>());
472 assert!(matches!(
473 resources.try_remove::<Res>(),
474 Err(ResourceFetchError {
475 resource_name_short,
476 resource_name_full,
477 }) if resource_name_short == "Res"
478 && resource_name_full == "resman::resources::tests::Res"
479 ));
480 }
481
482 #[test]
483 #[should_panic(
484 expected = "Expected to borrow `resman::resources::tests::Res`, but it does not exist."
485 )]
486 fn borrow_before_insert_panics() {
487 let resources = Resources::default();
488
489 resources.borrow::<Res>();
490 }
491
492 #[test]
493 #[should_panic(
494 expected = "Expected to borrow `resman::resources::tests::Res`, but it does not exist."
495 )]
496 fn borrow_mut_before_insert_panics() {
497 let resources = Resources::default();
498
499 resources.borrow_mut::<Res>();
500 }
501
502 #[test]
503 fn borrow_mut_try_borrow_returns_err() {
504 let mut resources = Resources::default();
505 resources.insert(Res);
506
507 let _res = resources.borrow_mut::<Res>();
508
509 assert_eq!(
510 Err(BorrowFail::BorrowConflictImm),
511 resources.try_borrow::<Res>()
512 );
513 }
514
515 #[test]
516 fn borrow_try_borrow_mut_returns_err() {
517 let mut resources = Resources::default();
518 resources.insert(Res);
519
520 let _res = resources.borrow::<Res>();
521
522 assert_eq!(
523 Err(BorrowFail::BorrowConflictMut),
524 resources.try_borrow_mut::<Res>()
525 );
526 }
527
528 #[test]
529 fn borrow_mut_borrow_mut_returns_err() {
530 let mut resources = Resources::default();
531 resources.insert(Res);
532
533 let _res = resources.borrow_mut::<Res>();
534
535 assert_eq!(
536 Err(BorrowFail::BorrowConflictMut),
537 resources.try_borrow_mut::<Res>()
538 );
539 }
540
541 #[test]
542 fn get_mut_returns_ok() {
543 let mut resources = Resources::default();
544 resources.insert(Res);
545
546 let _res = resources.get_mut::<Res>();
547
548 assert!(resources.try_borrow_mut::<Res>().is_ok());
549 }
550
551 #[test]
552 fn get_resource_mut_returns_some() {
553 let mut resources = Resources::default();
554 resources.insert(Res);
555
556 assert!(resources.get_resource_mut(TypeId::of::<Res>()).is_some());
557 }
558
559 #[test]
560 fn get_raw_returns_some() {
561 let mut resources = Resources::default();
562 resources.insert(Res);
563
564 assert!(resources.get_raw(&TypeId::of::<Res>()).is_some());
565 }
566
567 #[test]
568 fn merge() {
569 let mut resources_0 = Resources::default();
570 resources_0.insert(1u8);
571 resources_0.insert(2u16);
572
573 let mut resources_1 = Resources::default();
574 resources_1.insert(3u8);
575 resources_1.insert(4u32);
576
577 resources_0.merge(resources_1);
578
579 assert_eq!(3u8, *resources_0.borrow::<u8>());
580 assert_eq!(4u32, *resources_0.borrow::<u32>());
581 }
582
583 #[derive(Debug, Default, PartialEq)]
584 struct Res;
585}