swamp_resource/
lib.rs

1/*
2 * Copyright (c) Peter Bjorklund. All rights reserved. https://github.com/swamp/swamp
3 * Licensed under the MIT License. See LICENSE in the project root for license information.
4 */
5pub mod prelude;
6
7use std::any::{type_name, Any, TypeId};
8use std::collections::HashMap;
9use std::fmt::Debug;
10
11/// A trait representing a resource. It extends `Any` to allow for downcasting.
12pub trait Resource: Any + Debug + Send + Sync + 'static {}
13
14/// Storage for various resources identified by their `TypeId`.
15#[derive(Debug)]
16pub struct ResourceStorage {
17    resources: HashMap<TypeId, Box<dyn Any + 'static>>,
18}
19
20impl Default for ResourceStorage {
21    fn default() -> Self {
22        Self::new()
23    }
24}
25
26impl ResourceStorage {
27    /// Creates a new, empty `ResourceStorage`.
28    #[must_use]
29    pub fn new() -> Self {
30        Self {
31            resources: HashMap::new(),
32        }
33    }
34
35    /// Inserts a new resource into the storage.
36    ///
37    /// If a resource of the same type already exists, it will be replaced.
38    pub fn insert<R: Resource>(&mut self, resource: R) {
39        self.resources.insert(TypeId::of::<R>(), Box::new(resource));
40    }
41
42    /// Retrieves a reference to a resource of type `R`.
43    ///
44    /// # Panics
45    ///
46    /// Panics if the resource does not exist.
47    #[must_use]
48    pub fn fetch<R: Resource>(&self) -> &R {
49        self.resources
50            .get(&TypeId::of::<R>())
51            .unwrap_or_else(|| panic!("Resource of type '{}' not found.", type_name::<R>()))
52            .downcast_ref::<R>()
53            .expect("Failed to downcast resource to the expected type.")
54    }
55
56    /// Retrieves a mutable reference to a resource of type `R`.
57    ///
58    /// # Panics
59    ///
60    /// Panics if the resource does not exist.
61    #[must_use]
62    pub fn fetch_mut<R: Resource>(&mut self) -> &mut R {
63        self.resources
64            .get_mut(&TypeId::of::<R>())
65            .unwrap_or_else(|| panic!("Resource of type '{}' not found.", type_name::<R>()))
66            .downcast_mut::<R>()
67            .expect("Failed to downcast resource to the expected type.")
68    }
69
70    /// Retrieves an immutable reference to a resource of type `R`.
71    ///
72    /// Returns `Some(&R)` if the resource exists, otherwise returns `None`.
73    #[must_use]
74    pub fn get<R: Resource + 'static>(&self) -> Option<&R> {
75        self.resources
76            .get(&TypeId::of::<R>())
77            .and_then(|boxed_any| boxed_any.downcast_ref::<R>())
78    }
79
80    /// Retrieves a mutable reference to a resource of type `R`.
81    ///
82    /// Returns `Some(&mut R)` if the resource exists, otherwise returns `None`.
83    #[must_use]
84    pub fn get_mut<R: Resource + 'static>(&mut self) -> Option<&mut R> {
85        self.resources
86            .get_mut(&TypeId::of::<R>())
87            .and_then(|boxed_any| boxed_any.downcast_mut::<R>())
88    }
89
90    /// Removes a resource of type `R` from the storage.
91    ///
92    /// Returns `Some(R)` if the resource was present, otherwise `None`.
93    ///
94    /// # Panics
95    ///
96    /// Panics if the resource stored is not of the expected type `R`. Should be very unlikely.
97    pub fn remove<R: Resource>(&mut self) -> Option<R> {
98        self.resources.remove(&TypeId::of::<R>()).map(|boxed_any| {
99            *boxed_any
100                .downcast::<R>()
101                .expect("Failed to downcast resource to the expected type.")
102        })
103    }
104
105    /// Checks if a resource of type `R` exists in the storage.
106    #[must_use]
107    pub fn contains<R: Resource>(&self) -> bool {
108        self.resources.contains_key(&TypeId::of::<R>())
109    }
110}