telepath_server/
resource.rs1use core::any::TypeId;
2use core::cell::UnsafeCell;
3use core::mem::{self, MaybeUninit};
4
5const MAX_RESOURCES: usize = 8;
6const STORAGE_SIZE: usize = 128;
7
8struct Entry {
9 type_id: TypeId,
10 offset: usize,
11 drop_fn: unsafe fn(*mut u8),
12}
13
14#[repr(align(8))]
18struct AlignedStorage([MaybeUninit<u8>; STORAGE_SIZE]);
19
20pub struct ResourceRegistry {
21 entries: [MaybeUninit<Entry>; MAX_RESOURCES],
22 count: usize,
23 storage: UnsafeCell<AlignedStorage>,
24 used: usize,
25}
26
27impl Default for ResourceRegistry {
28 fn default() -> Self {
29 Self::new()
30 }
31}
32
33unsafe fn drop_in_place_erased<T>(ptr: *mut u8) {
37 unsafe { core::ptr::drop_in_place(ptr as *mut T) }
40}
41
42impl ResourceRegistry {
43 pub const fn new() -> Self {
44 Self {
45 entries: [const { MaybeUninit::uninit() }; MAX_RESOURCES],
46 count: 0,
47 storage: UnsafeCell::new(AlignedStorage(
48 [const { MaybeUninit::uninit() }; STORAGE_SIZE],
49 )),
50 used: 0,
51 }
52 }
53
54 pub fn insert<T: 'static>(&mut self, val: T) {
72 let id = TypeId::of::<T>();
76 for i in 0..self.count {
77 let entry = unsafe { self.entries[i].assume_init_ref() };
79 if entry.type_id == id {
80 panic!("duplicate resource type: each resource type may appear at most once");
81 }
82 }
83
84 let align = mem::align_of::<T>();
85 let size = mem::size_of::<T>();
86
87 assert!(
90 align <= 8,
91 "resource type alignment {} exceeds AlignedStorage alignment (8)",
92 align,
93 );
94
95 let offset = (self.used + align - 1) & !(align - 1);
96
97 assert!(
98 offset + size <= STORAGE_SIZE,
99 "resource storage full ({} + {} > {})",
100 offset,
101 size,
102 STORAGE_SIZE,
103 );
104 assert!(
105 self.count < MAX_RESOURCES,
106 "too many resources (max {})",
107 MAX_RESOURCES,
108 );
109
110 unsafe {
114 let base = (*self.storage.get()).0.as_mut_ptr();
115 let dst = base.add(offset) as *mut T;
116 core::ptr::write(dst, val);
117 }
118
119 self.entries[self.count].write(Entry {
120 type_id: TypeId::of::<T>(),
121 offset,
122 drop_fn: drop_in_place_erased::<T>,
123 });
124 self.count += 1;
125 self.used = offset + size;
126 }
127
128 pub fn get_ptr<T: 'static>(&self) -> Option<*mut T> {
138 let id = TypeId::of::<T>();
139 for i in 0..self.count {
140 let entry = unsafe { self.entries[i].assume_init_ref() };
142 if entry.type_id == id {
143 let ptr = unsafe {
146 let base = (*self.storage.get()).0.as_mut_ptr();
147 base.add(entry.offset) as *mut T
148 };
149 return Some(ptr);
150 }
151 }
152 None
153 }
154}
155
156impl Drop for ResourceRegistry {
157 fn drop(&mut self) {
158 for i in (0..self.count).rev() {
162 let entry = unsafe { self.entries[i].assume_init_ref() };
164 unsafe {
169 let base = (*self.storage.get()).0.as_mut_ptr() as *mut u8;
170 (entry.drop_fn)(base.add(entry.offset));
171 }
172 }
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use super::*;
179 use core::sync::atomic::{AtomicUsize, Ordering};
180
181 #[test]
182 fn insert_and_get_ptr() {
183 let mut reg = ResourceRegistry::new();
184 reg.insert(42u32);
185 let ptr = reg.get_ptr::<u32>().expect("u32 must be found");
186 assert_eq!(unsafe { *ptr }, 42);
187 }
188
189 #[test]
190 fn get_ptr_returns_none_for_unregistered() {
191 let reg = ResourceRegistry::new();
192 assert!(reg.get_ptr::<u64>().is_none());
193 }
194
195 #[test]
196 fn mutation_through_ptr() {
197 let mut reg = ResourceRegistry::new();
198 reg.insert(0u32);
199 let ptr = reg.get_ptr::<u32>().unwrap();
200 unsafe { *ptr = 99 };
201 let ptr2 = reg.get_ptr::<u32>().unwrap();
202 assert_eq!(unsafe { *ptr2 }, 99);
203 }
204
205 #[test]
206 fn multiple_types() {
207 let mut reg = ResourceRegistry::new();
208 reg.insert(1u8);
209 reg.insert(2u16);
210 reg.insert(3u32);
211 assert_eq!(unsafe { *reg.get_ptr::<u8>().unwrap() }, 1);
212 assert_eq!(unsafe { *reg.get_ptr::<u16>().unwrap() }, 2);
213 assert_eq!(unsafe { *reg.get_ptr::<u32>().unwrap() }, 3);
214 }
215
216 #[test]
217 fn alignment_respected() {
218 let mut reg = ResourceRegistry::new();
219 reg.insert(1u8);
220 reg.insert(2u64); let ptr = reg.get_ptr::<u64>().unwrap();
222 assert_eq!(ptr as usize % mem::align_of::<u64>(), 0);
223 assert_eq!(unsafe { *ptr }, 2);
224 }
225
226 #[test]
227 #[should_panic(expected = "too many resources")]
228 fn panics_on_overflow() {
229 let mut reg = ResourceRegistry::new();
230 reg.insert(0u8);
231 reg.insert(0u16);
232 reg.insert(0u32);
233 reg.insert(0u64);
234 reg.insert(0i8);
235 reg.insert(0i16);
236 reg.insert(0i32);
237 reg.insert(0i64);
238 reg.insert(0f32); }
240
241 #[test]
242 #[should_panic(expected = "duplicate")]
243 fn panics_on_duplicate_typeid() {
244 let mut reg = ResourceRegistry::new();
245 reg.insert(0u32);
246 reg.insert(1u32); }
248
249 static DROP_SEQ: AtomicUsize = AtomicUsize::new(0);
254 static DROP_POS_A: AtomicUsize = AtomicUsize::new(0);
255 static DROP_POS_B: AtomicUsize = AtomicUsize::new(0);
256 static DROP_POS_C: AtomicUsize = AtomicUsize::new(0);
257
258 struct CounterA;
259 struct CounterB;
260 struct CounterC;
261
262 impl Drop for CounterA {
263 fn drop(&mut self) {
264 DROP_POS_A.store(
265 DROP_SEQ.fetch_add(1, Ordering::SeqCst) + 1,
266 Ordering::SeqCst,
267 );
268 }
269 }
270 impl Drop for CounterB {
271 fn drop(&mut self) {
272 DROP_POS_B.store(
273 DROP_SEQ.fetch_add(1, Ordering::SeqCst) + 1,
274 Ordering::SeqCst,
275 );
276 }
277 }
278 impl Drop for CounterC {
279 fn drop(&mut self) {
280 DROP_POS_C.store(
281 DROP_SEQ.fetch_add(1, Ordering::SeqCst) + 1,
282 Ordering::SeqCst,
283 );
284 }
285 }
286
287 #[test]
288 fn drops_in_reverse_insertion_order() {
289 DROP_SEQ.store(0, Ordering::SeqCst);
291 DROP_POS_A.store(0, Ordering::SeqCst);
292 DROP_POS_B.store(0, Ordering::SeqCst);
293 DROP_POS_C.store(0, Ordering::SeqCst);
294
295 {
296 let mut reg = ResourceRegistry::new();
297 reg.insert(CounterA); reg.insert(CounterB); reg.insert(CounterC); } let pos_a = DROP_POS_A.load(Ordering::SeqCst);
304 let pos_b = DROP_POS_B.load(Ordering::SeqCst);
305 let pos_c = DROP_POS_C.load(Ordering::SeqCst);
306 assert!(pos_c < pos_b, "C must be dropped before B");
307 assert!(pos_b < pos_a, "B must be dropped before A");
308 }
309
310 static DROP_RAN: AtomicUsize = AtomicUsize::new(0);
311
312 struct DropWitness;
313 impl Drop for DropWitness {
314 fn drop(&mut self) {
315 DROP_RAN.fetch_add(1, Ordering::SeqCst);
316 }
317 }
318
319 #[test]
320 fn drop_runs_for_single_entry() {
321 DROP_RAN.store(0, Ordering::SeqCst);
322 {
323 let mut reg = ResourceRegistry::new();
324 reg.insert(DropWitness);
325 }
326 assert_eq!(DROP_RAN.load(Ordering::SeqCst), 1);
327 }
328
329 #[test]
330 fn empty_registry_drop_is_noop() {
331 drop(ResourceRegistry::new());
333 }
334
335 #[test]
336 #[should_panic(expected = "alignment")]
337 fn panics_on_overalign() {
338 #[repr(align(16))]
339 #[allow(dead_code)]
340 struct OverAligned(u64);
341
342 let mut reg = ResourceRegistry::new();
343 reg.insert(OverAligned(0));
344 }
345}