mewo_ecs/galaxy/
resource.rs

1use super::{Galaxy, ResourceId, ResourceTypeId};
2use crate::data::{
3    data_drop, hash_type, hash_type_and_val, TVal, TypeEntry, ValueDrop, ValueDuplicate,
4};
5use std::{
6    hash::Hash,
7    ops::{Deref, DerefMut},
8};
9
10fn hash_resource_id<RH: Hash + 'static>(rh: RH) -> ResourceId {
11    ResourceId::from_hash(hash_type_and_val(rh))
12}
13
14fn hash_resource_type_id<R: 'static>() -> ResourceTypeId {
15    ResourceTypeId::from_hash(hash_type::<R>())
16}
17
18pub trait Resource {
19    fn mewo_resource_type_entry() -> TypeEntry
20    where
21        Self: Sized,
22    {
23        TypeEntry {
24            size: Self::mewo_resource_size(),
25            name: String::from(std::any::type_name::<Self>()),
26            drop: Self::mewo_resource_drop(),
27            dup: Self::mewo_resource_dup(),
28        }
29    }
30
31    fn mewo_resource_size() -> usize
32    where
33        Self: Sized,
34    {
35        std::mem::size_of::<Self>()
36    }
37
38    fn mewo_resource_drop() -> ValueDrop
39    where
40        Self: Sized,
41    {
42        data_drop::<Self>()
43    }
44
45    fn mewo_resource_dup() -> ValueDuplicate {
46        //  Resource cloning is never used.
47        ValueDuplicate::None
48    }
49}
50
51pub struct ResourceReadGuard<'gal, R> {
52    r: &'gal R,
53    galaxy: &'gal Galaxy,
54    id: ResourceId,
55    tid: ResourceTypeId,
56}
57
58impl<'gal, R> Drop for ResourceReadGuard<'gal, R> {
59    fn drop(&mut self) {
60        self.galaxy
61            .rcp
62            .read()
63            .get_read_unlock(self.tid, self.id)
64            .unwrap();
65    }
66}
67
68impl<'gal, R> Deref for ResourceReadGuard<'gal, R> {
69    type Target = R;
70    fn deref(&self) -> &Self::Target {
71        self.r
72    }
73}
74
75pub struct ResourceWriteGuard<'gal, R> {
76    r: &'gal mut R,
77    galaxy: &'gal Galaxy,
78    id: ResourceId,
79    tid: ResourceTypeId,
80}
81
82impl<'gal, R> Drop for ResourceWriteGuard<'gal, R> {
83    fn drop(&mut self) {
84        self.galaxy
85            .rcp
86            .read()
87            .get_write_unlock(self.tid, self.id)
88            .unwrap();
89    }
90}
91
92impl<'gal, R> Deref for ResourceWriteGuard<'gal, R> {
93    type Target = &'gal mut R;
94    fn deref(&self) -> &Self::Target {
95        &self.r
96    }
97}
98
99impl<'gal, R> DerefMut for ResourceWriteGuard<'gal, R> {
100    fn deref_mut(&mut self) -> &mut Self::Target {
101        &mut self.r
102    }
103}
104
105//  TODO FIX: Validate Resource type to prevent unsafe usage.
106
107impl Galaxy {
108    pub fn insert_resource<R: Resource + 'static, RH: Clone + Hash + 'static>(
109        &self,
110        rh: RH,
111        r: R,
112    ) -> &Self {
113        let id = hash_resource_id(rh);
114        let tid = hash_resource_type_id::<R>();
115        self.resource_maybe_insert::<R>(tid, id);
116        let rcp = self.rcp.write();
117        {
118            let val = rcp.get_write_lock(tid, id).unwrap();
119            *val = Some(unsafe {
120                TVal::new(
121                    R::mewo_resource_size(),
122                    &r as *const R as *const u8,
123                    R::mewo_resource_drop(),
124                )
125            });
126            std::mem::forget(r);
127            rcp.get_write_unlock(tid, id).unwrap();
128        }
129        self
130    }
131
132    pub fn remove_resource<R: Resource + 'static, RH: Clone + Hash + 'static>(
133        &self,
134        rh: RH,
135    ) -> &Self {
136        let id = hash_resource_id(rh);
137        let tid = hash_resource_type_id::<R>();
138        self.resource_maybe_insert::<R>(tid, id);
139        let rcp = self.rcp.write();
140        {
141            let val = rcp.get_write_lock(tid, id).unwrap();
142            *val = None;
143            rcp.get_write_unlock(tid, id).unwrap();
144        }
145        self
146    }
147
148    pub fn get_resource<R: Resource + 'static, RH: Hash + 'static>(
149        &self,
150        rh: RH,
151    ) -> Option<ResourceReadGuard<R>> {
152        let id = hash_resource_id(rh);
153        let tid = hash_resource_type_id::<R>();
154        let rcp = self.rcp.read();
155        let rc = rcp.get_read_lock(tid, id).unwrap();
156        if rc.is_none() {
157            None?
158        }
159        Some(ResourceReadGuard {
160            r: rc
161                .as_ref()
162                .map(|val| unsafe { &*(val.get() as *const R) })
163                .unwrap(),
164            id,
165            tid,
166            galaxy: self,
167        })
168    }
169
170    pub fn get_mut_resource<R: Resource + 'static, RH: Hash + 'static>(
171        &self,
172        rh: RH,
173    ) -> Option<ResourceWriteGuard<R>> {
174        let id = hash_resource_id(rh);
175        let tid = hash_resource_type_id::<R>();
176        let rcp = self.rcp.read();
177        let rc = rcp.get_read_lock(tid, id).unwrap();
178        if rc.is_none() {
179            None?
180        }
181        Some(ResourceWriteGuard {
182            r: rc
183                .as_ref()
184                .map(|val| unsafe { &mut *(val.get() as *const R as *mut R) })
185                .unwrap(),
186            id,
187            tid,
188            galaxy: self,
189        })
190    }
191
192    fn resource_maybe_insert<R: Resource + 'static>(&self, tid: ResourceTypeId, id: ResourceId) {
193        let rcp = self.rcp.read();
194        if rcp.get_type(tid).is_none() {
195            drop(rcp);
196            let mut rcp = self.rcp.write();
197            rcp.insert_id(tid, id, R::mewo_resource_type_entry())
198                .unwrap();
199        }
200    }
201}