mewo_ecs/galaxy/
resource.rs1use 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 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
105impl 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}