1use std::alloc::Layout;
11use std::cmp::{Ord, Ordering};
12use std::fmt::{Debug, Formatter};
13use std::sync::{RwLock, Arc};
14
15use once_cell::sync::{Lazy, OnceCell};
16
17use crate::EntityID;
18use std::fmt;
19use std::any::type_name;
20
21#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
23pub struct ComponentTypeID(usize);
24
25struct ComponentRegistry {
26 component_types: Vec<Arc<ComponentRegistration>>,
27}
28
29static mut COMPONENT_REGISTRY: Lazy<RwLock<ComponentRegistry>> = Lazy::new(|| {
30 RwLock::new(ComponentRegistry {
31 component_types: vec![
32 Arc::new(ComponentRegistration::new::<EntityID>(ComponentTypeID(0))),
33 ],
34 })
35});
36
37impl ComponentTypeID {
38 pub(crate) fn new(inner: usize) -> ComponentTypeID {
40 ComponentTypeID(inner)
41 }
42
43 pub fn register<T: Component>() -> ComponentTypeID {
45 unsafe {
46 let mut r = COMPONENT_REGISTRY.write().unwrap();
47 let id = ComponentTypeID(r.component_types.len());
48 r.component_types.push(Arc::new(ComponentRegistration::new::<T>(id)));
49 id
50 }
51 }
52
53 fn safe_registration(&self) -> Option<Arc<ComponentRegistration>> {
56 unsafe {
57 let r = COMPONENT_REGISTRY.read().unwrap();
58 r.component_types.get(self.0).cloned()
59 }
60 }
61
62 pub fn registration(&self) -> Arc<ComponentRegistration> {
64 self.safe_registration().unwrap()
65 }
66
67 pub fn id(&self) -> usize {
69 self.0
70 }
71
72 pub fn layout(&self) -> Layout {
74 self.registration().layout()
75 }
76
77 pub fn name(&self) -> &'static str {
79 self.registration().name()
80 }
81}
82
83impl Debug for ComponentTypeID {
84 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
85 match self.safe_registration() {
86 Some(reg) => write!(f, "{}", reg.name()),
87 None => write!(f, "ComponentTypeID(#{} missing)", self.0),
88 }
89 }
90}
91
92pub struct AutoComponentTypeID(OnceCell<ComponentTypeID>);
94
95impl AutoComponentTypeID {
96 pub const fn new() -> AutoComponentTypeID {
98 AutoComponentTypeID(OnceCell::new())
99 }
100
101 pub fn get<T: Component>(&self) -> ComponentTypeID {
103 self.0.get_or_init(ComponentTypeID::register::<T>).clone()
104 }
105}
106
107pub unsafe trait Component: Debug + Default + Copy {
113 fn type_id() -> ComponentTypeID;
115
116 fn layout() -> Layout;
118}
119
120#[derive(Clone, Copy)]
122pub struct ComponentRegistration {
123 type_id: ComponentTypeID,
124 layout: Layout,
125 set_default: fn(&mut [u8]),
126 name: &'static str,
127}
128
129impl ComponentRegistration {
130 pub fn new<T: Component>(type_id: ComponentTypeID) -> ComponentRegistration {
132 fn default<T: Component>(ptr: &mut [u8]) {
133 assert_eq!(ptr.len(), std::mem::size_of::<T>());
134 let ptr: &mut T = unsafe { std::mem::transmute(ptr.as_ptr()) };
135 let d = T::default();
136 *ptr = d;
137 }
138
139 ComponentRegistration {
140 type_id,
141 layout: T::layout(),
142 set_default: default::<T>,
143 name: type_name::<T>(),
144 }
145 }
146
147 pub fn type_id(&self) -> ComponentTypeID {
149 self.type_id
150 }
151
152 pub fn layout(&self) -> Layout {
154 self.layout
155 }
156
157 pub fn name(&self) -> &'static str {
159 self.name
160 }
161
162 pub fn set_default(&self, ptr: &mut [u8]) {
165 (self.set_default)(ptr)
166 }
167}
168
169impl PartialEq for ComponentRegistration {
170 fn eq(&self, other: &ComponentRegistration) -> bool {
171 self.type_id.eq(&other.type_id)
172 }
173}
174
175impl Eq for ComponentRegistration {}
176
177impl PartialOrd for ComponentRegistration {
178 fn partial_cmp(&self, other: &ComponentRegistration) -> Option<Ordering> {
179 self.type_id.partial_cmp(&other.type_id)
180 }
181}
182
183impl Ord for ComponentRegistration {
184 fn cmp(&self, other: &ComponentRegistration) -> Ordering {
185 self.type_id.cmp(&other.type_id)
186 }
187}
188
189impl Debug for ComponentRegistration {
190 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
191 write!(f, "<ComponentRegistration {:?}>", self.type_id.id())
192 }
193}
194
195#[macro_export]
199macro_rules! component {
200 ($i:ident) => {
201 const _: () = {
202 static INIT_TYPE: $crate::component::AutoComponentTypeID = $crate::component::AutoComponentTypeID::new();
203
204 unsafe impl $crate::component::Component for $i {
205 fn type_id() -> $crate::component::ComponentTypeID {
206 INIT_TYPE.get::<$i>()
207 }
208
209 fn layout() -> ::core::alloc::Layout {
210 ::core::alloc::Layout::new::<$i>()
211 }
212 }
213
214 ()
215 };
216 };
217}
218
219#[cfg(test)]
220mod test {
221 use super::*;
222
223 #[test]
224 fn test_uniqueness() {
225 #[derive(Debug, Clone, Copy, Default)]
226 struct A;
227 #[derive(Debug, Clone, Copy, Default)]
228 struct B;
229
230 component!(A);
231 component!(B);
232
233 assert_ne!(ComponentTypeID(0), A::type_id());
234 assert_ne!(ComponentTypeID(0), B::type_id());
235 assert_ne!(A::type_id(), B::type_id());
236 }
237
238 #[test]
239 fn test_default() {
240 #[derive(Debug, Clone, Copy)]
241 struct A(u8);
242
243 component!(A);
244
245 impl Default for A {
246 fn default() -> A {
247 A(42)
248 }
249 }
250
251 let component_type = ComponentRegistration::new::<A>(ComponentTypeID(12));
252 assert_eq!(component_type.type_id(), A::type_id());
253 assert_eq!(component_type.layout(), Layout::new::<A>());
254
255 let raw = &mut [0];
256 component_type.set_default(raw);
257 assert_eq!(raw[0], 42);
258 }
259}