1use std::{
2 fmt::{Debug, Formatter, LowerHex, Pointer, UpperHex},
3 hash::{Hash, Hasher},
4 marker::PhantomData,
5 ptr::NonNull,
6};
7
8use crate::{EntityAlloc, IAllocPolicy, chunk::Unit, gen_index::GenIndex};
9
10pub trait IPoliciedID: Copy + Eq + Debug {
25 type ObjectT: Sized;
27 type PolicyT: IAllocPolicy;
29 type BackID: IEntityAllocID<Self::ObjectT, Self::PolicyT>;
31
32 fn from_backend(ptr: Self::BackID) -> Self;
34 fn into_backend(self) -> Self::BackID;
36
37 fn try_deref_alloc(self, alloc: &IDBoundAlloc<Self>) -> Option<&Self::ObjectT> {
39 self.into_backend().try_deref(alloc)
40 }
41 fn try_deref_alloc_mut(self, alloc: &mut IDBoundAlloc<Self>) -> Option<&mut Self::ObjectT> {
43 self.into_backend().try_deref_mut(alloc)
44 }
45
46 fn deref_alloc(self, alloc: &IDBoundAlloc<Self>) -> &Self::ObjectT {
48 self.into_backend().deref(alloc)
49 }
50 fn deref_alloc_mut(self, alloc: &mut IDBoundAlloc<Self>) -> &mut Self::ObjectT {
52 self.into_backend().deref_mut(alloc)
53 }
54}
55
56pub type IDBoundAlloc<I> = EntityAlloc<<I as IPoliciedID>::ObjectT, <I as IPoliciedID>::PolicyT>;
60
61pub trait IEntityAllocID<E, P: IAllocPolicy>: Sized + Copy {
73 fn from_ptr(alloc: &EntityAlloc<E, P>, ptr: PtrID<E, P>) -> Option<Self>;
75
76 fn from_index(alloc: &EntityAlloc<E, P>, indexed: IndexedID<E, P>) -> Option<Self>;
78
79 fn try_deref(self, alloc: &EntityAlloc<E, P>) -> Option<&E>;
81
82 fn try_deref_mut(self, alloc: &mut EntityAlloc<E, P>) -> Option<&mut E>;
84
85 fn to_index(self, alloc: &EntityAlloc<E, P>) -> Option<IndexedID<E, P>>;
87
88 fn to_ptr(self, alloc: &EntityAlloc<E, P>) -> Option<PtrID<E, P>>;
90
91 #[inline]
93 fn deref(self, alloc: &EntityAlloc<E, P>) -> &E {
94 self.try_deref(alloc).expect("UAF detected!")
95 }
96 #[inline]
98 fn deref_mut(self, alloc: &mut EntityAlloc<E, P>) -> &mut E {
99 self.try_deref_mut(alloc).expect("UAF detected!")
100 }
101
102 fn allocate_from(alloc: &EntityAlloc<E, P>, val: E) -> Self;
106
107 fn free(self, alloc: &mut EntityAlloc<E, P>) -> Option<E>;
111}
112
113pub struct PtrID<E, P> {
125 pub(crate) ptr: NonNull<Unit<E>>,
126 _marker: PhantomData<P>,
127}
128impl<E, P> From<NonNull<Unit<E>>> for PtrID<E, P> {
129 fn from(ptr: NonNull<Unit<E>>) -> Self {
130 Self {
131 ptr,
132 _marker: PhantomData,
133 }
134 }
135}
136impl<E, P> From<&Unit<E>> for PtrID<E, P> {
137 fn from(unit: &Unit<E>) -> Self {
138 Self {
139 ptr: NonNull::from(unit),
140 _marker: PhantomData,
141 }
142 }
143}
144impl<E, P> Copy for PtrID<E, P> {}
145impl<E, P> Clone for PtrID<E, P> {
146 fn clone(&self) -> Self {
147 *self
148 }
149}
150impl<E, P> Debug for PtrID<E, P> {
151 #[inline]
152 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
153 Debug::fmt(&self.ptr, f)
154 }
155}
156impl<E, P> Pointer for PtrID<E, P> {
157 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
158 Pointer::fmt(&self.ptr, f)
159 }
160}
161
162impl<E, P> PartialEq for PtrID<E, P> {
163 #[inline]
164 fn eq(&self, other: &Self) -> bool {
165 self.ptr == other.ptr
166 }
167}
168impl<E, P> Eq for PtrID<E, P> {}
169impl<E, P> PartialOrd for PtrID<E, P> {
170 #[inline]
171 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
172 Some(self.cmp(other))
173 }
174}
175impl<E, P> Ord for PtrID<E, P> {
176 #[inline]
177 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
178 self.ptr.cmp(&other.ptr)
179 }
180}
181impl<E, P> Hash for PtrID<E, P> {
182 #[inline]
183 fn hash<H: Hasher>(&self, state: &mut H) {
184 self.ptr.hash(state);
185 }
186}
187unsafe impl<E: Send, P> Send for PtrID<E, P> {}
188unsafe impl<E: Sync, P> Sync for PtrID<E, P> {}
189impl<E, P: IAllocPolicy> IEntityAllocID<E, P> for PtrID<E, P> {
190 fn from_ptr(_: &EntityAlloc<E, P>, ptr: PtrID<E, P>) -> Option<Self> {
191 Some(ptr)
192 }
193 fn from_index(alloc: &EntityAlloc<E, P>, indexed: IndexedID<E, P>) -> Option<Self> {
194 let unit_ptr = alloc.unit_ptr_of_indexed(indexed.indexed).ok()?;
195 Some(Self::from(unit_ptr))
196 }
197 fn try_deref(self, alloc: &EntityAlloc<E, P>) -> Option<&E> {
198 if cfg!(debug_assertions) {
199 alloc.check_unit_validity(self.ptr.as_ptr()).ok()?;
201 }
202 unsafe { self.ptr.as_ref().as_init_ref() }
203 }
204 fn try_deref_mut(mut self, alloc: &mut EntityAlloc<E, P>) -> Option<&mut E> {
205 if cfg!(debug_assertions) {
206 alloc.check_unit_validity(self.ptr.as_ptr()).ok()?;
208 }
209 unsafe { self.ptr.as_mut().as_init_mut() }
210 }
211 fn to_index(self, alloc: &EntityAlloc<E, P>) -> Option<IndexedID<E, P>> {
212 let gen_index = alloc.index_of_unit_ptr(self.ptr.as_ptr()).ok()?;
213 Some(IndexedID::from(gen_index))
214 }
215 fn to_ptr(self, _alloc: &EntityAlloc<E, P>) -> Option<PtrID<E, P>> {
216 Some(self)
217 }
218
219 fn allocate_from(alloc: &EntityAlloc<E, P>, val: E) -> Self {
220 let ptr = match alloc.try_allocate_unit(val) {
221 Ok(ptr) => NonNull::new(ptr as *mut _).unwrap(),
222 Err(..) => panic!("Allocation failed in IEntityAllocID::allocate_from"),
223 };
224 PtrID {
225 ptr,
226 _marker: PhantomData,
227 }
228 }
229 fn free(self, alloc: &mut EntityAlloc<E, P>) -> Option<E> {
230 alloc.free_unit_ptr(self.ptr.as_ptr())
231 }
232}
233impl<E, P: IAllocPolicy> IPoliciedID for PtrID<E, P> {
234 type ObjectT = E;
235 type PolicyT = P;
236 type BackID = PtrID<E, P>;
237
238 fn from_backend(ptr: Self::BackID) -> Self {
239 ptr
240 }
241 fn into_backend(self) -> Self::BackID {
242 self
243 }
244}
245impl<E, P: IAllocPolicy> PtrID<E, P> {
246 pub fn check_validity(&self, alloc: &EntityAlloc<E, P>) -> bool {
254 alloc.index_of_unit_ptr(self.ptr.as_ptr()).is_ok()
255 }
256
257 pub unsafe fn direct_deref<'a>(self) -> Option<&'a E> {
263 unsafe { self.ptr.as_ref().as_init_ref() }
264 }
265
266 pub unsafe fn direct_deref_mut<'a>(mut self) -> Option<&'a mut E> {
272 unsafe { self.ptr.as_mut().as_init_mut() }
273 }
274}
275
276#[repr(C)]
284pub struct IndexedID<E, P> {
285 pub indexed: GenIndex,
287 _marker: PhantomData<(E, P)>,
288}
289impl<E, P> From<GenIndex> for IndexedID<E, P> {
290 fn from(indexed: GenIndex) -> Self {
291 Self {
292 indexed,
293 _marker: PhantomData,
294 }
295 }
296}
297impl<E, P> Copy for IndexedID<E, P> {}
298impl<E, P> Clone for IndexedID<E, P> {
299 fn clone(&self) -> Self {
300 *self
301 }
302}
303impl<E, P> Debug for IndexedID<E, P> {
304 #[inline]
305 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
306 let (real, gene) = self.indexed.tear();
307 write!(f, "IndexedID({real:x} gen {gene})")
308 }
309}
310impl<E, P> Pointer for IndexedID<E, P> {
311 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
312 write!(f, "{:#x}", u64::from(self.indexed))
313 }
314}
315impl<E, P> LowerHex for IndexedID<E, P> {
316 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
317 LowerHex::fmt(&u64::from(self.indexed), f)
318 }
319}
320impl<E, P> UpperHex for IndexedID<E, P> {
321 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
322 UpperHex::fmt(&u64::from(self.indexed), f)
323 }
324}
325impl<E, P> PartialEq for IndexedID<E, P> {
326 #[inline]
327 fn eq(&self, other: &Self) -> bool {
328 self.indexed == other.indexed
329 }
330}
331impl<E, P> Eq for IndexedID<E, P> {}
332impl<E, P> PartialOrd for IndexedID<E, P> {
333 #[inline]
334 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
335 Some(self.cmp(other))
336 }
337}
338impl<E, P> Ord for IndexedID<E, P> {
339 #[inline]
340 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
341 self.indexed.cmp(&other.indexed)
342 }
343}
344impl<E, P> Hash for IndexedID<E, P> {
345 #[inline]
346 fn hash<H: Hasher>(&self, state: &mut H) {
347 self.indexed.hash(state);
348 }
349}
350#[cfg(feature = "serde")]
351impl<E, P> serde_core::Serialize for IndexedID<E, P> {
353 fn serialize<S: serde_core::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
354 use std::fmt::Write;
355 #[derive(Default)]
356 struct Buffer {
357 buf: [u8; 32],
358 len: usize,
359 }
360 impl Buffer {
361 fn as_str(&self) -> &str {
362 unsafe { std::str::from_utf8_unchecked(&self.buf[..self.len]) }
364 }
365 }
366 impl Write for Buffer {
367 fn write_str(&mut self, s: &str) -> std::fmt::Result {
368 let bytes = s.as_bytes();
369 let avail = self.buf.len().saturating_sub(self.len);
370 if bytes.len() > avail {
371 return Err(std::fmt::Error);
372 }
373 let dst = &mut self.buf[self.len..self.len + bytes.len()];
374 dst.copy_from_slice(bytes);
375 self.len += bytes.len();
376 Ok(())
377 }
378 }
379
380 let (real, gene) = self.indexed.tear();
381 let mut buf = Buffer::default();
382 write!(&mut buf, "{real:x}:{gene:x}").unwrap();
383 serializer.serialize_str(buf.as_str())
384 }
385}
386#[cfg(feature = "serde")]
387impl<'de, E, P> serde_core::Deserialize<'de> for IndexedID<E, P> {
388 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
389 where
390 D: serde_core::Deserializer<'de>,
391 {
392 use serde_core::de::Error as _;
393
394 let s = <&str>::deserialize(deserializer)?;
395 let mut parts = s.splitn(2, ':');
396 let real_str = parts
397 .next()
398 .ok_or_else(|| D::Error::custom("missing real index"))?;
399 let gen_str = parts
400 .next()
401 .ok_or_else(|| D::Error::custom("missing generation"))?;
402
403 let real_u64 = u64::from_str_radix(real_str, 16)
404 .map_err(|e| D::Error::custom(format!("invalid real index: {e}")))?;
405 let gen_u64 = u64::from_str_radix(gen_str, 16)
406 .map_err(|e| D::Error::custom(format!("invalid generation: {e}")))?;
407
408 if gen_u64 > u16::MAX as u64 {
409 return Err(D::Error::custom("generation out of range"));
410 }
411
412 let real_usize = real_u64 as usize;
413 let generation = gen_u64 as u16;
414
415 Ok(IndexedID::from(GenIndex::compose(real_usize, generation)))
416 }
417}
418
419impl<E, P: IAllocPolicy> IEntityAllocID<E, P> for IndexedID<E, P> {
420 fn from_ptr(alloc: &EntityAlloc<E, P>, ptr: PtrID<E, P>) -> Option<Self> {
421 let gen_index = alloc.index_of_unit_ptr(ptr.ptr.as_ptr()).ok()?;
422 Some(IndexedID::from(gen_index))
423 }
424 fn from_index(_: &EntityAlloc<E, P>, indexed: IndexedID<E, P>) -> Option<Self> {
425 Some(indexed)
426 }
427
428 fn try_deref(self, alloc: &EntityAlloc<E, P>) -> Option<&E> {
429 let unit_ptr = alloc.unit_ptr_of_indexed(self.indexed).ok()?;
430 unsafe { unit_ptr.as_ref().as_init_ref() }
431 }
432 fn try_deref_mut(self, alloc: &mut EntityAlloc<E, P>) -> Option<&mut E> {
433 let mut unit_ptr = alloc.unit_ptr_of_indexed(self.indexed).ok()?;
434 unsafe { unit_ptr.as_mut().as_init_mut() }
435 }
436 fn to_index(self, _: &EntityAlloc<E, P>) -> Option<IndexedID<E, P>> {
437 Some(self)
438 }
439 fn to_ptr(self, alloc: &EntityAlloc<E, P>) -> Option<PtrID<E, P>> {
440 let unit_ptr = alloc.unit_ptr_of_indexed(self.indexed).ok()?;
441 Some(PtrID::from(unit_ptr))
442 }
443
444 fn allocate_from(alloc: &EntityAlloc<E, P>, val: E) -> Self {
445 let Ok(unit) = alloc.try_allocate_unit(val) else {
446 panic!("Allocation failed in IEntityAllocID::allocate_from");
447 };
448 unsafe { Self::from(unit.as_ref().unwrap().indexed) }
449 }
450 fn free(self, alloc: &mut EntityAlloc<E, P>) -> Option<E> {
451 alloc.free_gen_index(self.indexed)
452 }
453}
454impl<E, P: IAllocPolicy> IPoliciedID for IndexedID<E, P> {
455 type ObjectT = E;
456 type PolicyT = P;
457 type BackID = IndexedID<E, P>;
458
459 fn from_backend(ptr: Self::BackID) -> Self {
460 ptr
461 }
462 fn into_backend(self) -> Self::BackID {
463 self
464 }
465}
466impl<E, P: IAllocPolicy> IndexedID<E, P> {
467 pub fn next_to_alloc(alloc: &EntityAlloc<E, P>) -> Self {
471 Self::from(alloc.next_index())
472 }
473
474 pub fn get_generation(self) -> u16 {
478 self.indexed.generation()
479 }
480
481 pub fn get_order(self) -> usize {
485 self.indexed.real_index()
486 }
487}