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}