asmkit_core/entity.rs
1use std::{fmt::Debug, hash::Hash, marker::PhantomData};
2
3/// An opaque reference to an entity.
4///
5/// Entity references are intended to be created *only internally*, and using manually constructed entity references (using [`EntityRef::new`]) may cause issues if you do
6/// not know what you are doing.
7pub trait EntityRef: Clone + Copy + Debug + Hash + PartialEq + PartialOrd {
8 /// Creates an opaque reference to an entity.
9 ///
10 /// Manually creating an entity reference may cause issues if you do not know what you are doing. Entity references are unchecked for performance reasons, and your
11 /// program may panic if you create an invalid entity reference.
12 fn new(value: usize) -> Self;
13
14 /// Returns the raw ID of this entity reference.
15 ///
16 /// Used internally to index an entity list.
17 fn as_u32(&self) -> u32;
18
19 /// Returns the raw ID of this entity reference, as a Rust `usize`.
20 ///
21 /// Used internally to index an entity list.
22 fn as_usize(&self) -> usize;
23}
24
25/// A list of entities.
26///
27/// This implementation is essentially a glorified [`Vec<T>`], which returns a `Ref` when pushed to. Of course, since it is indexed by [`EntityRef`]s, it can only index
28/// [`u32::MAX`] items. It can hold more items than this (if there is enough space in memory), but the items past the limit will be un-indexable by [`EntityRef`]s.
29#[derive(Clone, PartialEq)]
30pub struct EntityList<T, Ref: EntityRef> {
31 /// The raw [`Vec`] that this list wraps.
32 private: Vec<T>,
33
34 /// Phantom data so the compiler isn't mad about `Ref` being unused.
35 phantom: PhantomData<Ref>,
36}
37
38impl<T, Ref: EntityRef> EntityList<T, Ref> {
39 /// Creates a new empty entity list.
40 #[inline(always)]
41 pub fn new() -> Self {
42 Self { private: Vec::new(), phantom: PhantomData }
43 }
44
45 /// Pushes an item onto the end of the entity list, and returns a reference to it.
46 pub fn push(&mut self, item: T) -> Ref {
47 let r = Ref::new(self.private.len());
48 self.private.push(item);
49 r
50 }
51
52 /// Returns the item associated with the given reference. Will panic if `item` is an invalid reference, or out of bounds.
53 pub fn get(&self, item: Ref) -> &T {
54 &self.private[item.as_usize()]
55 }
56
57 /// Returns a mutable reference to the provided item.
58 pub fn get_mut(&mut self, item: Ref) -> &mut T {
59 &mut self.private[item.as_usize()]
60 }
61
62 /// Returns the amount of items in the entity list.
63 pub fn len(&self) -> usize {
64 self.private.len()
65 }
66
67 /// Returns the entities which are currently stored in this entity list.
68 pub fn entities(&self) -> &Vec<T> {
69 &self.private
70 }
71
72 /// Returns a mutable reference to the entities which are stored in this entity list.
73 pub fn entities_mut(&mut self) -> &mut Vec<T> {
74 &mut self.private
75 }
76}
77
78impl<T: Debug, Ref: EntityRef> Debug for EntityList<T, Ref> {
79 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
80 self.private.fmt(f)
81 }
82}
83
84/// An opaque reference to a [`Label`] in an instruction stream.
85#[derive(Clone, Copy, Debug, Hash, PartialEq, PartialOrd)]
86pub struct LabelRef(u32);
87
88impl EntityRef for LabelRef {
89 #[inline(always)]
90 fn new(value: usize) -> Self {
91 Self(value as u32)
92 }
93
94 #[inline(always)]
95 fn as_u32(&self) -> u32 {
96 self.0
97 }
98
99 #[inline(always)]
100 fn as_usize(&self) -> usize {
101 self.0 as usize
102 }
103}
104
105/// A label in an instruction stream.
106#[derive(Clone, Copy, Debug, PartialEq)]
107pub enum Label {
108 /// A label attached to the provided index.
109 Attached(usize),
110
111 /// A label attached to no index yet.
112 Unattached,
113}