1use std::any::{type_name, Any, TypeId};
2use std::cell::{Ref, RefCell, RefMut};
3use std::collections::hash_map::{Entry, HashMap};
4use std::hash::{BuildHasherDefault, Hasher};
5use std::ops::{Deref, DerefMut};
6
7pub struct Resources(TypeIdMap<RefCell<Box<dyn Any>>>);
31
32impl Default for Resources {
33 fn default() -> Self {
35 Self::new()
36 }
37}
38
39impl Resources {
40 pub fn new() -> Self {
42 Self(Default::default())
43 }
44}
45
46impl Resources {
47 pub fn insert<R>(&mut self, res: R)
53 where
54 R: 'static,
55 {
56 match self.0.entry(TypeId::of::<R>()) {
57 Entry::Vacant(entry) => entry.insert(RefCell::new(Box::new(res))),
58 Entry::Occupied(_) => panic!("Resource {} already present", type_name::<R>()),
59 };
60 }
61
62 pub fn clear(&mut self) {
64 self.0.clear();
65 }
66}
67
68impl Resources {
69 pub fn get<R>(&self) -> Res<'_, R>
75 where
76 R: 'static,
77 {
78 let ref_ = self
79 .0
80 .get(&TypeId::of::<R>())
81 .unwrap_or_else(|| panic!("Resource {} not present", type_name::<R>()))
82 .try_borrow()
83 .unwrap_or_else(|_err| panic!("Resource {} already borrwed", type_name::<R>()));
84
85 Res(Ref::map(ref_, |ref_| unsafe {
86 &*(ref_.deref() as *const dyn Any as *const R)
87 }))
88 }
89
90 pub fn get_mut<R>(&self) -> ResMut<'_, R>
96 where
97 R: 'static,
98 {
99 let ref_ = self
100 .0
101 .get(&TypeId::of::<R>())
102 .unwrap_or_else(|| panic!("Resource {} not present", type_name::<R>()))
103 .try_borrow_mut()
104 .unwrap_or_else(|_err| panic!("Resource {} already borrwed", type_name::<R>()));
105
106 ResMut(RefMut::map(ref_, |ref_| unsafe {
107 &mut *(ref_.deref_mut() as *mut dyn Any as *mut R)
108 }))
109 }
110}
111
112pub struct Res<'a, R>(Ref<'a, R>);
114
115impl<R> Deref for Res<'_, R> {
116 type Target = R;
117
118 fn deref(&self) -> &R {
119 self.0.deref()
120 }
121}
122
123pub struct ResMut<'a, R>(RefMut<'a, R>);
125
126impl<R> Deref for ResMut<'_, R> {
127 type Target = R;
128
129 fn deref(&self) -> &R {
130 self.0.deref()
131 }
132}
133
134impl<R> DerefMut for ResMut<'_, R> {
135 fn deref_mut(&mut self) -> &mut R {
136 self.0.deref_mut()
137 }
138}
139
140pub type TypeIdMap<V> = HashMap<TypeId, V, BuildHasherDefault<TypeIdHasher>>;
141
142#[derive(Default)]
143pub struct TypeIdHasher(u64);
144
145impl Hasher for TypeIdHasher {
146 fn write_u64(&mut self, val: u64) {
147 self.0 = val;
148 }
149
150 fn write(&mut self, _val: &[u8]) {
151 unreachable!();
152 }
153
154 fn finish(&self) -> u64 {
155 self.0
156 }
157}
158
159#[cfg(test)]
160mod tests {
161 use super::*;
162
163 #[test]
164 fn insert_then_get() {
165 let mut resources = Resources::new();
166
167 resources.insert(42_u64);
168
169 let res = resources.get::<u64>();
170 assert_eq!(*res, 42);
171 }
172
173 #[test]
174 fn get_mut_then_get() {
175 let mut resources = Resources::new();
176
177 resources.insert(42_u64);
178
179 {
180 let mut res = resources.get_mut::<u64>();
181 *res = 23;
182 }
183
184 let res = resources.get::<u64>();
185 assert_eq!(*res, 23);
186 }
187
188 #[test]
189 #[should_panic]
190 fn insert_does_not_replace() {
191 let mut resources = Resources::new();
192
193 resources.insert(23_i32);
194 resources.insert(42_i32);
195 }
196
197 #[test]
198 fn borrows_can_be_shared() {
199 let mut resources = Resources::new();
200
201 resources.insert(23_i32);
202
203 let _res = resources.get::<i32>();
204 let _res = resources.get::<i32>();
205 }
206
207 #[test]
208 #[should_panic]
209 fn mutable_borrows_are_exclusive() {
210 let mut resources = Resources::new();
211
212 resources.insert(23_i32);
213
214 let _res = resources.get_mut::<i32>();
215 let _res = resources.get_mut::<i32>();
216 }
217}