chunked/
component.rs

1//! Base definitions for components.
2//! 
3//! All entities in this library are built out of components. There is no intrinsic
4//! value to an entity. This module provides means of defining and managing
5//! components.
6//!
7//! Each component type is allocated a unique ID. There is a macro (`component`)
8//! to help you assign this unique ID.
9
10use 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/// A component type ID which is unique for a specific component type.
22#[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    /// Construct a new `ComponentTypeID` from the inner value.
39    pub(crate) fn new(inner: usize) -> ComponentTypeID {
40        ComponentTypeID(inner)
41    }
42
43    /// Create a new globally unique `ComponentTypeID`.
44    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    /// Fetch the registration for this `ComponentTypeID` returning None if it is
54    /// missing from the registry.
55    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    /// Fetch the registration information for a component type.
63    pub fn registration(&self) -> Arc<ComponentRegistration> {
64        self.safe_registration().unwrap()
65    }
66
67    /// Return the inner unique ID.
68    pub fn id(&self) -> usize {
69        self.0
70    }
71
72    /// Fetch the memory layout of this component type.
73    pub fn layout(&self) -> Layout {
74        self.registration().layout()
75    }
76
77    /// Return the name of this registration.
78    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
92/// A struct for lazily assigning unique `ComponentTypeID`s.
93pub struct AutoComponentTypeID(OnceCell<ComponentTypeID>);
94
95impl AutoComponentTypeID {
96    /// Create a new `AutoComponentTypeID`.
97    pub const fn new() -> AutoComponentTypeID {
98        AutoComponentTypeID(OnceCell::new())
99    }
100
101    /// Get the `ComponentTypeID` this struct wraps.
102    pub fn get<T: Component>(&self) -> ComponentTypeID {
103        self.0.get_or_init(ComponentTypeID::register::<T>).clone()
104    }
105}
106
107/// The component trait is implemented on all component types.
108/// 
109/// This trait is unsafe, because implementing it and not returning a unique
110/// `type_id` can result in other safe functions on `Chunks` performing illegal
111/// casts.
112pub unsafe trait Component: Debug + Default + Copy {
113    /// Get the unique type ID of this component.
114    fn type_id() -> ComponentTypeID;
115
116    /// Get the memory layout of an instance of this component.
117    fn layout() -> Layout;
118}
119
120/// A ComponentRegistration is the dynamic version of a type implementing Component.
121#[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    /// Create a ComponentRegistration for a static type.
131    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    /// Return the unique type ID for this `ComponentRegistration`.
148    pub fn type_id(&self) -> ComponentTypeID {
149        self.type_id
150    }
151
152    /// Return the memory layout of a single instance of this component.
153    pub fn layout(&self) -> Layout {
154        self.layout
155    }
156
157    /// Get the name of this component type.
158    pub fn name(&self) -> &'static str {
159        self.name
160    }
161
162    /// Given the storage buffer of a component instance, fill in the default
163    /// value.
164    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/// Implement the `Component` trait on a type.
196///
197/// Component types must implement Copy and Default.
198#[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}