Skip to main content

termite/storage/
resource.rs

1use std::cell::UnsafeCell;
2
3use crate::{ChangeTicks, ComponentId, SparseArray};
4
5pub trait Resource: Send + Sync + 'static {}
6
7impl<T> Resource for T where T: Send + Sync + 'static {}
8
9impl dyn Resource {
10    #[inline]
11    pub unsafe fn downcast_ref<T: Resource>(&self) -> &T {
12        unsafe { &*(self as *const dyn Resource as *const T) }
13    }
14
15    #[inline]
16    pub unsafe fn downcast_mut<T: Resource>(&mut self) -> &mut T {
17        unsafe { &mut *(self as *mut dyn Resource as *mut T) }
18    }
19}
20
21pub struct ResourceData {
22    data: *mut dyn Resource,
23    change_ticks: UnsafeCell<ChangeTicks>,
24}
25
26impl ResourceData {
27    #[inline]
28    pub fn new<T: Resource>(data: T, change_tick: u32) -> Self {
29        Self {
30            data: Box::into_raw(Box::new(data)),
31            change_ticks: UnsafeCell::new(ChangeTicks::new(change_tick)),
32        }
33    }
34
35    #[inline]
36    pub fn from_boxed(data: Box<dyn Resource>, change_tick: u32) -> Self {
37        Self {
38            data: Box::into_raw(data),
39            change_ticks: UnsafeCell::new(ChangeTicks::new(change_tick)),
40        }
41    }
42
43    #[inline]
44    pub fn as_ptr(&self) -> *mut dyn Resource {
45        self.data
46    }
47
48    #[inline]
49    pub fn change_ticks(&self) -> &UnsafeCell<ChangeTicks> {
50        &self.change_ticks
51    }
52
53    #[inline]
54    pub fn change_ticks_mut(&mut self) -> &mut ChangeTicks {
55        self.change_ticks.get_mut()
56    }
57}
58
59impl Drop for ResourceData {
60    #[inline]
61    fn drop(&mut self) {
62        // SAFETY: `self.data` was crated from a Box.
63        unsafe { Box::from_raw(self.data) };
64    }
65}
66
67#[derive(Default)]
68pub struct Resources {
69    resources: SparseArray<ResourceData>,
70}
71
72impl Resources {
73    #[inline]
74    pub fn contains(&self, id: ComponentId) -> bool {
75        self.resources.contains(id.index())
76    }
77
78    #[inline]
79    pub unsafe fn insert(
80        &mut self,
81        id: ComponentId,
82        resource: Box<dyn Resource>,
83        change_tick: u32,
84    ) {
85        let data = ResourceData::from_boxed(resource, change_tick);
86        self.resources.insert(id.index(), data);
87    }
88
89    #[inline]
90    pub fn remove(&mut self, id: ComponentId) -> Option<*mut dyn Resource> {
91        Some(self.resources.remove(id.index())?.as_ptr())
92    }
93
94    #[inline]
95    pub fn get(&self, id: ComponentId) -> Option<*mut dyn Resource> {
96        Some(self.resources.get(id.index())?.as_ptr())
97    }
98
99    #[inline]
100    pub fn get_with_ticks(&self, id: ComponentId) -> Option<(*mut dyn Resource, *mut ChangeTicks)> {
101        let data = self.resources.get(id.index())?;
102        Some((data.as_ptr(), data.change_ticks.get()))
103    }
104}