1use crate::{
2 ds::{
3 ATypeId, BorrowError, BorrowResult, ManagedConstPtr, ManagedMutPtr, NonNullExt, OptVec,
4 SimpleHolder,
5 },
6 ecs::EcsError,
7 util::{macros::debug_format, Or, With},
8};
9use std::{
10 any::Any,
11 collections::HashMap,
12 fmt,
13 hash::{BuildHasher, Hash},
14 ptr::NonNull,
15};
16
17pub mod prelude {
18 pub use super::{Resource, ResourceDesc, ResourceId, ResourceIndex};
19}
20
21#[allow(private_interfaces)]
23pub trait Resource: Send + 'static {
24 #[doc(hidden)]
25 fn key() -> ResourceKey {
26 ResourceKey::of::<Self>()
27 }
28}
29
30#[derive(Debug)]
36pub(super) struct ResourceStorage<S> {
37 owned: HashMap<ResourceKey, Box<dyn Any>, S>,
39
40 ptrs: OptVec<SimpleHolder<NonNullExt<u8>>, S>,
45
46 imap: HashMap<ResourceKey, ResourceIndex, S>,
48
49 is_dedi: Vec<bool>,
55
56 res_gens: Vec<u64>,
59
60 generation: u64,
62}
63
64impl<S> ResourceStorage<S>
65where
66 S: Default,
67{
68 pub(super) fn new() -> Self {
69 Self {
70 owned: HashMap::default(),
71 ptrs: OptVec::new(),
72 imap: HashMap::default(),
73 is_dedi: Vec::new(),
74 res_gens: Vec::new(),
75 generation: 1,
76 }
77 }
78}
79
80impl<S> ResourceStorage<S>
81where
82 S: BuildHasher + Default,
83{
84 pub(super) fn add(
89 &mut self,
90 desc: ResourceDesc,
91 ) -> Result<ResourceIndex, EcsError<ResourceDesc>> {
92 if self.imap.contains_key(&desc.key) {
93 let reason = debug_format!("detected duplicated resource `{:?}`", desc.key);
94 return Err(EcsError::DupResource(reason, desc));
95 }
96
97 let ResourceDesc {
98 dedicated,
99 key,
100 data,
101 } = desc;
102
103 let ptr = match data {
104 Or::A(mut owned) => {
105 let ptr = unsafe { NonNull::new_unchecked(&mut *owned as *mut dyn Any as *mut u8) };
107 let must_none = self.owned.insert(key, owned);
108 debug_assert!(must_none.is_none());
109 ptr
110 }
111 Or::B(ptr) => ptr,
112 };
113
114 let ptr = NonNullExt::from_nonnull(ptr).with_type(*key.get_inner());
117
118 let holder = SimpleHolder::new(ptr);
120 let index = self.ptrs.add(holder);
121 let ri = ResourceIndex::new(index, self.generation);
122 self.generation += 1;
123 while self.res_gens.len() <= index {
124 self.res_gens.push(0);
125 }
126 self.res_gens[index] = ri.generation();
127
128 self.imap.insert(key, ri);
130
131 if self.is_dedi.len() < index + 1 {
133 self.is_dedi.resize(index + 1, false);
134 }
135 self.is_dedi[index] = dedicated;
136
137 Ok(ri)
138 }
139
140 pub(super) fn remove(&mut self, rkey: &ResourceKey) -> Option<Or<Box<dyn Any>, NonNull<u8>>> {
141 if let Some(ri) = self.imap.remove(rkey) {
144 let data = self.owned.remove(rkey);
145 let ptr = self.ptrs.take(ri.index());
146
147 debug_assert!(ptr.is_some());
149 let holder = unsafe { ptr.unwrap_unchecked() };
150 let ptr = *holder.into_value();
151
152 Some(if let Some(data) = data {
153 Or::A(data)
154 } else {
155 Or::B(ptr)
156 })
157 } else {
158 None
159 }
160 }
161
162 pub(super) fn contains<Q>(&self, key: &Q) -> bool
163 where
164 ResourceKey: std::borrow::Borrow<Q>,
165 Q: Hash + Eq + ?Sized,
166 {
167 self.imap.contains_key(key)
168 }
169
170 pub(super) fn index<Q>(&self, key: &Q) -> Option<ResourceIndex>
171 where
172 ResourceKey: std::borrow::Borrow<Q>,
173 Q: Hash + Eq + ?Sized,
174 {
175 self.imap.get(key).cloned()
176 }
177
178 #[allow(dead_code)]
180 pub(super) fn is_dedicated(&self, ri: ResourceIndex) -> Option<bool> {
181 if self.is_valid_index(&ri) {
182 Some(self.is_dedi[ri.index()])
183 } else {
184 None
185 }
186 }
187
188 pub(super) fn is_dedicated2<Q>(&self, key: &Q) -> Option<bool>
189 where
190 ResourceKey: std::borrow::Borrow<Q>,
191 Q: Hash + Eq + ?Sized,
192 {
193 self.imap.get(key).map(|ri| self.is_dedi[ri.index()])
194 }
195
196 pub(super) fn borrow(&self, ri: ResourceIndex) -> BorrowResult<ManagedConstPtr<u8>> {
197 if self.is_valid_index(&ri) {
198 if let Some(holder) = self.ptrs.get(ri.index()) {
199 return holder
200 .borrow()
201 .map(|borrowed| borrowed.map(|ptr| unsafe { ManagedConstPtr::new(ptr) }));
202 }
203 }
204 Err(BorrowError::OutOfBound)
205 }
206
207 pub(super) fn borrow2<Q>(&self, key: &Q) -> BorrowResult<ManagedConstPtr<u8>>
208 where
209 ResourceKey: std::borrow::Borrow<Q>,
210 Q: Hash + Eq + ?Sized,
211 {
212 if let Some(index) = self.index(key) {
213 self.borrow(index)
214 } else {
215 Err(BorrowError::NotFound)
216 }
217 }
218
219 pub(super) fn borrow_mut(&mut self, ri: ResourceIndex) -> BorrowResult<ManagedMutPtr<u8>> {
220 if self.is_valid_index(&ri) {
221 if let Some(holder) = self.ptrs.get_mut(ri.index()) {
222 return holder
223 .borrow_mut()
224 .map(|borrowed| borrowed.map(|ptr| unsafe { ManagedMutPtr::new(ptr) }));
225 }
226 }
227 Err(BorrowError::OutOfBound)
228 }
229
230 pub(super) fn borrow_mut2<Q>(&mut self, key: &Q) -> BorrowResult<ManagedMutPtr<u8>>
231 where
232 ResourceKey: std::borrow::Borrow<Q>,
233 Q: Hash + Eq + ?Sized,
234 {
235 if let Some(index) = self.index(key) {
236 self.borrow_mut(index)
237 } else {
238 Err(BorrowError::NotFound)
239 }
240 }
241
242 #[cfg(test)]
248 pub(super) unsafe fn get_ptr(&self, ri: ResourceIndex) -> Option<NonNullExt<u8>> {
249 if self.is_valid_index(&ri) {
250 self.ptrs
251 .get(ri.index())
252 .map(|holder| *holder.get_unchecked())
253 } else {
254 None
255 }
256 }
257
258 fn is_valid_index(&self, ri: &ResourceIndex) -> bool {
259 if let Some(generation) = self.res_gens.get(ri.index()).cloned() {
260 generation == ri.generation()
261 } else {
262 false
263 }
264 }
265}
266
267impl<S> Default for ResourceStorage<S>
268where
269 S: Default,
270{
271 fn default() -> Self {
272 Self::new()
273 }
274}
275
276#[derive(Debug)]
283pub struct ResourceDesc {
284 pub dedicated: bool,
285 pub(crate) key: ResourceKey,
286 pub data: Or<Box<dyn Any>, NonNull<u8>>,
287}
288
289impl ResourceDesc {
290 pub fn new() -> Self {
300 struct Dummy;
301 impl Resource for Dummy {}
302
303 Self {
304 dedicated: false,
305 key: Dummy::key(),
306 data: Or::B(NonNull::dangling()),
307 }
308 }
309
310 pub fn with_dedicated(mut self, is_dedicated: bool) -> Self {
323 self.dedicated = is_dedicated;
324 self
325 }
326
327 pub fn with_owned<R: Resource>(mut self, data: R) -> Self {
339 self.key = R::key();
340 self.data = Or::A(Box::new(data));
341 self
342 }
343
344 pub unsafe fn with_ptr<R: Resource>(mut self, data: *mut R) -> Self {
364 self.key = R::key();
365 self.data = Or::B(NonNull::new(data as *mut u8).unwrap());
366 self
367 }
368}
369
370impl Default for ResourceDesc {
371 fn default() -> Self {
372 Self::new()
373 }
374}
375
376impl<R: Resource> From<R> for ResourceDesc {
377 fn from(value: R) -> Self {
378 ResourceDesc::new().with_owned(value)
379 }
380}
381
382pub(crate) type ResourceKey = ATypeId<ResourceKey_>;
384pub(crate) struct ResourceKey_;
385
386#[derive(Clone, Copy, PartialEq, Eq, Hash)]
395pub struct ResourceId {
396 ri: ResourceIndex,
400
401 ii: With<usize, u64>,
403}
404
405impl ResourceId {
406 pub const fn new(ri: ResourceIndex, ii: With<usize, u64>) -> Self {
409 Self { ri, ii }
410 }
411
412 pub const fn resource_index(&self) -> ResourceIndex {
414 self.ri
415 }
416
417 pub const fn item_index(&self) -> With<usize, u64> {
422 self.ii
423 }
424}
425
426#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Debug)]
432#[repr(transparent)]
433pub struct ResourceIndex(With<usize, u64>);
434
435impl ResourceIndex {
436 const DUMMY: Self = Self(With::new(usize::MAX, u64::MAX));
437
438 pub const fn new(index: usize, generation: u64) -> Self {
440 Self(With::new(index, generation))
441 }
442
443 pub const fn dummy() -> Self {
445 Self::DUMMY
446 }
447
448 pub fn is_dummy(&self) -> bool {
450 *self == Self::dummy()
451 }
452
453 pub fn index(&self) -> usize {
455 self.0.value
456 }
457
458 pub fn generation(&self) -> u64 {
460 self.0.with
461 }
462}
463
464impl Default for ResourceIndex {
465 fn default() -> Self {
466 Self::dummy()
467 }
468}
469
470impl fmt::Display for ResourceIndex {
471 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472 self.0.fmt(f)
473 }
474}