├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.toml ├── README.md ├── benches └── ecs.rs ├── examples ├── add_remove_components.rs ├── create_destroy_entity.rs ├── define_component.rs └── iterations.rs ├── shard_ecs_derive ├── Cargo.toml └── src │ └── lib.rs └── src ├── archetype ├── data_access.rs ├── mod.rs └── tests.rs ├── archetype_registry ├── iterators │ ├── archetype_iter.rs │ ├── archetype_iter_mut.rs │ ├── filter_archetype_iter.rs │ ├── filter_archetype_iter_mut.rs │ ├── filter_matching_iter.rs │ ├── filter_matching_iter_mut.rs │ ├── matching_iter.rs │ ├── matching_iter_mut.rs │ └── mod.rs ├── mod.rs ├── sorted_archetype_key.rs └── tests.rs ├── constants.rs ├── descriptors ├── archetype_descriptor.rs ├── archetype_id.rs ├── component.rs ├── component_descriptor.rs ├── component_group.rs ├── component_group_descriptor.rs ├── component_type_id.rs └── mod.rs ├── entity_registry ├── archetype_index.rs ├── entity.rs ├── entry.rs ├── index_in_archetype.rs ├── iterator.rs └── mod.rs ├── fnv1a.rs ├── lib.rs ├── registry ├── mod.rs ├── registry.rs └── tests.rs └── test_components.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ "master" ] 6 | pull_request: 7 | branches: [ "master" ] 8 | 9 | env: 10 | CARGO_TERM_COLOR: always 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v3 19 | - name: Build 20 | run: cargo build --verbose 21 | - name: Run tests 22 | run: cargo test --verbose 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | /**/.vscode 4 | /**/.idea -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shard-ecs" 3 | version = "0.2.7" 4 | edition = "2021" 5 | authors = ["Hindrik Stegenga "] 6 | description = "The Shard Entity Component System." 7 | license = "MIT" 8 | homepage = "https://github.com/HindrikStegenga/Shard" 9 | repository = "https://github.com/HindrikStegenga/Shard" 10 | 11 | [features] 12 | derive = ["shard_ecs_derive"] 13 | 14 | [dependencies] 15 | shard_ecs_derive = { version = "0.1.0", optional = true} 16 | 17 | [dev-dependencies] 18 | rand = "0.8" 19 | criterion = "0.3" 20 | 21 | [[bench]] 22 | name = "ecs" 23 | harness = false -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Shard 2 | 3 | Shard is an Archetype-based Entity Component System implemented in Rust. 4 | 5 | # Features 6 | - Systems are (currently) implicit. 7 | - Supports #![no_std] environments. (Requires alloc however) 8 | - Up to 14 components per entity. 9 | - Up to 65K archetypes. 10 | - Up to 16.7 million entities. 11 | - Dependency free. 12 | - (Mostly) unit tested. 13 | 14 | # Usage 15 | 16 | See the examples directory for details, but in short: 17 | 18 | 1. Implement Component trait for types which you wish to use as components. 19 | 2. Create a Registry. 20 | 3. Use the Registry to construct entities. 21 | 4. Add or remove components from entities. 22 | 5. Iterate over entities matching certain subsets of components. 23 | 24 | # TODO: 25 | - Query support 26 | - ~~Filter iterators~~ => done as of 0.2.3. 27 | - Procedural derive macro for Components. => done as of 0.2.6. 28 | - Allow replacing components. 29 | - Allow adding/removing multiple components at once. 30 | - Faster archetype lookups (using a graph). 31 | - Component dependencies/exclusions. 32 | -------------------------------------------------------------------------------- /benches/ecs.rs: -------------------------------------------------------------------------------- 1 | use criterion::*; 2 | use shard_ecs::*; 3 | use rand::{*, seq::SliceRandom}; 4 | 5 | const COUNT: usize = 1_000_000; 6 | 7 | fn criterion_benchmark(c: &mut Criterion) { 8 | let mut registry = Registry::default(); 9 | 10 | let entities = (0..COUNT).into_iter().map(|_|{ 11 | let p = P { 12 | x: rand::random(), 13 | y: rand::random(), 14 | z: rand::random(), 15 | }; 16 | let r = R { 17 | x: rand::random(), 18 | y: rand::random(), 19 | z: rand::random(), 20 | }; 21 | let s = S { 22 | x: rand::random(), 23 | y: rand::random(), 24 | z: rand::random(), 25 | }; 26 | 27 | if rand::random() { 28 | registry.create_entity((p, s)).unwrap() 29 | } else if rand::random() { 30 | registry.create_entity(p).unwrap() 31 | } else { 32 | registry.create_entity((p, r, s)).unwrap() 33 | } 34 | }).collect::>(); 35 | 36 | c.bench_function("random_lookup", |b|{ 37 | b.iter_batched(||{ 38 | entities.choose(&mut thread_rng()).unwrap().clone() 39 | }, |entity| { 40 | registry.get_component::

(black_box(entity)).unwrap(); 41 | }, BatchSize::SmallInput) 42 | }); 43 | c.bench_function("iterate_entities", |b|{ 44 | b.iter(||{ 45 | for entity in registry.iter_entities() { 46 | black_box(entity); 47 | } 48 | }); 49 | }); 50 | c.bench_function("iterate_p_components", |b|{ 51 | b.iter(||{ 52 | for p in registry.iter_components_matching::

() { 53 | for p in p { 54 | black_box(p); 55 | } 56 | } 57 | }); 58 | }); 59 | let p_components = (0..COUNT).into_iter().map(|_|{ 60 | P { 61 | x: rand::random(), 62 | y: rand::random(), 63 | z: rand::random() 64 | } 65 | }).collect::>(); 66 | c.bench_function("iterate_array_of_p_components", |b|{ 67 | b.iter(||{ 68 | for p in &p_components { 69 | black_box(p); 70 | } 71 | }) 72 | }); 73 | 74 | } 75 | 76 | criterion_group!(ecs, criterion_benchmark); 77 | criterion_main!(ecs); 78 | 79 | 80 | #[derive(Debug)] 81 | struct P { 82 | x: f32, 83 | y: f32, 84 | z: f32, 85 | } 86 | #[derive(Debug)] 87 | struct R { 88 | x: f32, 89 | y: f32, 90 | z: f32, 91 | } 92 | #[derive(Debug)] 93 | struct S { 94 | x: f32, 95 | y: f32, 96 | z: f32, 97 | } 98 | 99 | impl Component for P { 100 | const NAME: &'static str = "P"; 101 | } 102 | impl Component for R { 103 | const NAME: &'static str = "R"; 104 | } 105 | impl Component for S { 106 | const NAME: &'static str = "S"; 107 | } 108 | -------------------------------------------------------------------------------- /examples/add_remove_components.rs: -------------------------------------------------------------------------------- 1 | use shard_ecs::*; 2 | #[allow(unused)] 3 | #[derive(Debug, Clone)] 4 | struct Position { 5 | x: f32, 6 | y: f32, 7 | z: f32, 8 | } 9 | impl Component for Position { 10 | const NAME: &'static str = "Position"; 11 | } 12 | #[allow(unused)] 13 | #[derive(Debug, Clone)] 14 | struct Rotation { 15 | x: f32, 16 | y: f32, 17 | z: f32, 18 | w: f32, 19 | } 20 | impl Component for Rotation { 21 | const NAME: &'static str = "Position"; 22 | } 23 | 24 | #[allow(unused)] 25 | fn main() { 26 | let position = Position { 27 | x: 2.0, 28 | y: 9.1, 29 | z: -2.0, 30 | }; 31 | let rotation = Rotation { 32 | x: 3.0, 33 | y: 5.0, 34 | z: 1.0, 35 | w: 7.0, 36 | }; 37 | 38 | let mut registry = Registry::default(); 39 | // Entities cannot exist without them having components. 40 | // As such, you create an entity by giving it an initial set of components. 41 | let result = registry.create_entity(position); 42 | // Keep in mind, it returns a Result, as it could fail, returning the component instance. 43 | let entity = result.unwrap(); 44 | 45 | // We can add a component to the entity: 46 | let result = registry.add_component(entity, rotation); 47 | // In case of failure, for example the entity already has a component of the specific type, an Err(component) is returned. 48 | 49 | // The can also be removed. This will remove the component returning it if successful. 50 | // If the entity doesn't have the specified component, it returns an Err(). 51 | let result = registry.remove_component::(entity); 52 | } 53 | -------------------------------------------------------------------------------- /examples/create_destroy_entity.rs: -------------------------------------------------------------------------------- 1 | use shard_ecs::*; 2 | #[allow(unused)] 3 | #[derive(Debug, Clone)] 4 | struct Position { 5 | x: f32, 6 | y: f32, 7 | z: f32, 8 | } 9 | impl Component for Position { 10 | const NAME: &'static str = "Position"; 11 | } 12 | #[allow(unused)] 13 | #[derive(Debug, Clone)] 14 | struct Rotation { 15 | x: f32, 16 | y: f32, 17 | z: f32, 18 | w: f32, 19 | } 20 | impl Component for Rotation { 21 | const NAME: &'static str = "Position"; 22 | } 23 | 24 | #[allow(unused)] 25 | fn main() { 26 | let position = Position { 27 | x: 2.0, 28 | y: 9.1, 29 | z: -2.0, 30 | }; 31 | let rotation = Rotation { 32 | x: 3.0, 33 | y: 5.0, 34 | z: 1.0, 35 | w: 7.0, 36 | }; 37 | 38 | let mut registry = Registry::default(); 39 | // Entities cannot exist without them having components. 40 | // As such, you create an entity by giving it an initial set of components. 41 | let result = registry.create_entity(position.clone()); 42 | // Keep in mind, it returns a Result, as it could fail, returning the component instance. 43 | let entity = result.unwrap(); 44 | // Use entity for various things. 45 | 46 | // Multiple components can be added to the entity by using a tuple of them. 47 | // Order is irrelevant, the result is the same. 48 | let result = registry.create_entity((position, rotation)); 49 | 50 | // Entities can also be destroyed, returning true if the entity was destroyed. 51 | let result = registry.destroy_entity(entity); 52 | // The entity handle is now free for re-use. The old entity handle is now invalid. 53 | // This means it cannot be used anymore and doing so will fail any operation on the registry. 54 | // Therefore, you can freely copy around the entity handle to refer to an entity and when it gets destroyed, 55 | // the handle will not refer to a valid entity anymore and operations on the registry will thus fail. 56 | // Internally, each entity handle contains a version segment which rolls over until a specific 57 | // internal entity slot is re-used 256 times. Under normal circumstances you won't run into issues with this. 58 | } 59 | -------------------------------------------------------------------------------- /examples/define_component.rs: -------------------------------------------------------------------------------- 1 | use shard_ecs::*; 2 | #[allow(unused)] 3 | 4 | // Some random struct. 5 | struct Position { 6 | x: f32, 7 | y: f32, 8 | z: f32, 9 | } 10 | 11 | // Implement the Component trait for it like this. 12 | // You usually should not implement any of it's other associated const's otherwise. 13 | impl Component for Position { 14 | const NAME: &'static str = "Position"; 15 | } 16 | 17 | // You can also use a derive macro if the "derive" feature is enabled: 18 | #[cfg(feature = "derive")] 19 | #[derive(Component)] 20 | struct DeriveExample { 21 | foo: f32, 22 | } 23 | 24 | fn main() { 25 | // code .. 26 | } 27 | -------------------------------------------------------------------------------- /examples/iterations.rs: -------------------------------------------------------------------------------- 1 | use shard_ecs::*; 2 | #[allow(unused)] 3 | #[derive(Clone)] 4 | struct Position { 5 | x: f32, 6 | y: f32, 7 | z: f32, 8 | } 9 | impl Component for Position { 10 | const NAME: &'static str = "Position"; 11 | } 12 | 13 | #[allow(unused)] 14 | #[derive(Clone)] 15 | struct Rotation { 16 | x: f32, 17 | y: f32, 18 | z: f32, 19 | w: f32, 20 | } 21 | impl Component for Rotation { 22 | const NAME: &'static str = "Position"; 23 | } 24 | 25 | #[allow(unused)] 26 | fn main() { 27 | let position = Position { 28 | x: 2.0, 29 | y: 9.1, 30 | z: -2.0, 31 | }; 32 | let rotation = Rotation { 33 | x: 3.0, 34 | y: 5.0, 35 | z: 1.0, 36 | w: 7.0, 37 | }; 38 | 39 | let mut registry = Registry::default(); 40 | 41 | (0..10000).into_iter().for_each(|_| { 42 | // Add a bunch of entities to the registry. 43 | registry.create_entity((position.clone(), rotation.clone())); 44 | }); 45 | 46 | // Iteration over all entity handles in the system is possible: 47 | registry.iter_entities().for_each(|entity| { 48 | // Do stuff here with the entity handle. 49 | }); 50 | 51 | // Iteration for entities exclusively matching a set of components: 52 | let (position_slice, rotation_slice) = registry.iter_components_exact::<(Position, Rotation)>(); 53 | // This will match entities which have exactly the specified set of components. 54 | 55 | // Iterate over the slices. 56 | position_slice 57 | .iter() 58 | .zip(rotation_slice) 59 | .for_each(|(rotation, position)| { 60 | // Do something with the rotation nand iteration. 61 | }); 62 | 63 | // You can also match all entities with specified components. This means that it will also 64 | // entities which contain more than the specified components. 65 | registry 66 | .iter_components_matching::() 67 | .for_each(|position_slice| { 68 | // For example, the above match will match entities with (Position) but also with (Position, Rotation). 69 | position_slice.iter().for_each(|position| { 70 | // Do something with the position object, like compute a new position it. 71 | }) 72 | }); 73 | 74 | // Arbitrary filtering is also supported. As an example, archetypes including a specific component can be excluded. 75 | registry 76 | .iter_filtered_components_matching::(|a| { 77 | !a.has_component::() // All archetypes with a position match, except those which also have a rotation. 78 | // This closure must return true for everything that needs to be included, false otherwise. 79 | }) 80 | .for_each(|position_slice| { 81 | // For example, the above match will match entities with (Position) but also with (Position, Rotation). 82 | position_slice.iter().for_each(|position| { 83 | // Do something with the position object, like compute a new position it. 84 | }) 85 | }); 86 | 87 | // You can also iterate over component slices with their associated entity handles: 88 | registry 89 | .iter_entity_components_matching::() 90 | .for_each(|(entities_slice, rotation_slice)| { 91 | entities_slice 92 | .iter() 93 | .zip(rotation_slice) 94 | .for_each(|(entity, rotation)| { 95 | // You have access to the entity handle here as well. 96 | }) 97 | }) 98 | } 99 | -------------------------------------------------------------------------------- /shard_ecs_derive/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "shard_ecs_derive" 3 | version = "0.1.0" 4 | edition = "2021" 5 | authors = ["Hindrik Stegenga "] 6 | description = "Contains derive macros for the Shard Entity Component System." 7 | license = "MIT" 8 | homepage = "https://github.com/HindrikStegenga/Shard" 9 | repository = "https://github.com/HindrikStegenga/Shard" 10 | 11 | [lib] 12 | proc-macro = true 13 | 14 | [dependencies] 15 | syn = "1.0" 16 | quote = "1.0" -------------------------------------------------------------------------------- /shard_ecs_derive/src/lib.rs: -------------------------------------------------------------------------------- 1 | use proc_macro::*; 2 | use syn::{DeriveInput, parse_macro_input}; 3 | use quote::quote; 4 | 5 | #[proc_macro_derive(Component)] 6 | pub fn derive_component(input: TokenStream) -> TokenStream { 7 | let input = parse_macro_input!(input as DeriveInput); 8 | let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); 9 | let name = input.ident; 10 | let expanded = quote! { 11 | impl #impl_generics Component for #name #ty_generics #where_clause { 12 | const NAME: &'static str = stringify!(#name); 13 | } 14 | }; 15 | proc_macro::TokenStream::from(expanded) 16 | } -------------------------------------------------------------------------------- /src/archetype/data_access.rs: -------------------------------------------------------------------------------- 1 | use super::Archetype; 2 | use crate::*; 3 | 4 | use crate::constants::DEFAULT_ARCHETYPE_ALLOCATION_SIZE; 5 | use alloc::alloc::{dealloc, realloc, Layout}; 6 | use core::mem::{align_of, size_of}; 7 | use core::ptr::{slice_from_raw_parts, slice_from_raw_parts_mut}; 8 | 9 | impl Archetype { 10 | /// Returns a reference to a specific component. 11 | /// # Safety: 12 | /// - Component type [`C`] must be present in the archetype 13 | /// - panics otherwise. 14 | pub unsafe fn get_component_unchecked(&self, index: u32) -> &C { 15 | match self 16 | .descriptor 17 | .components() 18 | .binary_search_by_key(&C::ID, |e| e.component_type_id) 19 | { 20 | Ok(idx) => &*(self.pointers[idx] as *mut C).offset(index as isize), 21 | Err(_) => unreachable!(), 22 | } 23 | } 24 | 25 | /// Returns a mutable reference to a specific component. 26 | /// # Safety: 27 | /// - Component type [`C`] must be present in the archetype 28 | /// - panics otherwise. 29 | pub unsafe fn get_component_unchecked_mut(&mut self, index: u32) -> &mut C { 30 | match self 31 | .descriptor 32 | .components() 33 | .binary_search_by_key(&C::ID, |e| e.component_type_id) 34 | { 35 | Ok(idx) => &mut *(self.pointers[idx] as *mut C).offset(index as isize), 36 | Err(_) => unreachable!(), 37 | } 38 | } 39 | 40 | /// Returns a reference to a specific component. 41 | /// # Safety: 42 | /// - Component group type [`G`] must be a subset of the types in the archetype 43 | /// - panics otherwise. 44 | pub unsafe fn get_fuzzy_components_unchecked<'a, G: ComponentGroup>( 45 | &'a self, 46 | index: u32, 47 | ) -> G::RefTuple<'a> { 48 | debug_assert!(G::DESCRIPTOR.is_valid()); 49 | let pointers = self.get_fuzzy_pointers_unchecked::(index); 50 | G::pointers_as_ref_tuple(&pointers) 51 | } 52 | 53 | /// Returns a reference to a specific component. 54 | /// # Safety: 55 | /// - Component group type [`G`] must be a subset of the types in the archetype 56 | /// - panics otherwise. 57 | pub unsafe fn get_fuzzy_components_unchecked_mut<'a, G: ComponentGroup>( 58 | &'a mut self, 59 | index: u32, 60 | ) -> G::MutRefTuple<'a> { 61 | debug_assert!(G::DESCRIPTOR.is_valid()); 62 | let pointers = self.get_fuzzy_pointers_unchecked::(index); 63 | G::pointers_as_mut_ref_tuple(&pointers) 64 | } 65 | 66 | /// Reads a specific component from the archetype at the given index. 67 | /// # Safety: 68 | /// - Component type [`C`] must be present in the archetype 69 | /// - panics otherwise. 70 | pub unsafe fn read_component_unchecked(&mut self, index: u32) -> C { 71 | match self 72 | .descriptor 73 | .components() 74 | .binary_search_by_key(&C::ID, |e| e.component_type_id) 75 | { 76 | Ok(idx) => { 77 | core::ptr::read::((self.pointers[idx] as *const C).offset(index as isize)) 78 | } 79 | Err(_) => unreachable!(), 80 | } 81 | } 82 | 83 | /// Returns a tuple of mutable component slices to the archetype's data. 84 | /// # Safety: 85 | /// - Must be called exactly with the component group contained in the archetype. 86 | /// - a compatible group type is also accepted. 87 | /// - [`G`] must have a valid archetype descriptor. 88 | pub unsafe fn get_slices_unchecked_exact_mut<'a, G: ComponentGroup>( 89 | &'a mut self, 90 | ) -> G::SliceMutRefTuple<'a> { 91 | debug_assert_eq!( 92 | G::DESCRIPTOR.archetype().archetype_id(), 93 | self.descriptor.archetype_id() 94 | ); 95 | 96 | G::slice_unchecked_mut(&self.pointers, self.len() as usize) 97 | } 98 | 99 | /// Returns a tuple of component slices to the archetype's data. 100 | /// # Safety: 101 | /// - Must be called exactly with the component group contained in the archetype. 102 | /// - a compatible group type is also accepted. 103 | /// - [`G`] must have a valid archetype descriptor. 104 | pub unsafe fn get_slices_unchecked_exact<'a, G: ComponentGroup>( 105 | &'a self, 106 | ) -> G::SliceRefTuple<'a> { 107 | debug_assert_eq!( 108 | G::DESCRIPTOR.archetype().archetype_id(), 109 | self.descriptor.archetype_id() 110 | ); 111 | 112 | G::slice_unchecked(&self.pointers, self.len() as usize) 113 | } 114 | 115 | /// Returns the slices for the components in [`G`], provided that archetype itself contains a superset of G. 116 | /// This function is slower than the exact version, use that if an exact type match is known. 117 | /// # Safety: 118 | /// - Only call this with subsets of the types stored in the archetype. 119 | /// - [`G`] must have a valid archetype descriptor. 120 | pub unsafe fn get_fuzzy_slices_unchecked<'s, G: ComponentGroup>( 121 | &'s self, 122 | ) -> G::SliceRefTuple<'s> { 123 | debug_assert!(G::DESCRIPTOR.is_valid()); 124 | let pointers = self.get_fuzzy_pointers_unchecked::(0); 125 | G::slice_unchecked(&pointers, self.len() as usize) 126 | } 127 | 128 | /// Returns the mutable slices for the components in [`G`], provided that archetype itself contains a superset of G. 129 | /// This function is slower than the exact version, use that if an exact type match is known. 130 | /// # Safety: 131 | /// - Only call this with subsets of the types stored in the archetype. 132 | /// - [`G`] must have a valid archetype descriptor. 133 | pub unsafe fn get_fuzzy_slices_unchecked_mut<'s, G: ComponentGroup>( 134 | &'s mut self, 135 | ) -> G::SliceMutRefTuple<'s> { 136 | debug_assert!(G::DESCRIPTOR.is_valid()); 137 | let pointers = self.get_fuzzy_pointers_unchecked::(0); 138 | G::slice_unchecked_mut(&pointers, self.len() as usize) 139 | } 140 | 141 | /// Returns the entity slice and the slices for the components in [`G`], provided that archetype 142 | /// itself contains a superset of G. 143 | /// This function is slower than the exact version, use that if an exact type match is known. 144 | /// # Safety: 145 | /// - Only call this with subsets of the types stored in the archetype. 146 | /// - [`G`] must have a valid archetype descriptor. 147 | pub unsafe fn get_entity_fuzzy_slices_unchecked<'s, G: ComponentGroup>( 148 | &'s self, 149 | ) -> (&'s [Entity], G::SliceRefTuple<'s>) { 150 | debug_assert!(G::DESCRIPTOR.is_valid()); 151 | let pointers = self.get_fuzzy_pointers_unchecked::(0); 152 | ( 153 | self.entities(), 154 | G::slice_unchecked(&pointers, self.len() as usize), 155 | ) 156 | } 157 | 158 | /// Returns the entity slice and the mutable slices for the components in [`G`], provided that 159 | /// archetype itself contains a superset of G. 160 | /// This function is slower than the exact version, use that if an exact type match is known. 161 | /// # Safety: 162 | /// - Only call this with subsets of the types stored in the archetype. 163 | /// - [`G`] must have a valid archetype descriptor. 164 | pub unsafe fn get_entity_fuzzy_slices_unchecked_mut<'s, G: ComponentGroup>( 165 | &'s mut self, 166 | ) -> (&'s [Entity], G::SliceMutRefTuple<'s>) { 167 | debug_assert!(G::DESCRIPTOR.is_valid()); 168 | let pointers = self.get_fuzzy_pointers_unchecked::(0); 169 | ( 170 | self.entities(), 171 | G::slice_unchecked_mut(&pointers, self.len() as usize), 172 | ) 173 | } 174 | } 175 | 176 | impl Archetype { 177 | /// Returns the amount of entities currently stored in the archetype. 178 | pub fn len(&self) -> u32 { 179 | self.entity_count 180 | } 181 | 182 | /// Returns the current capacity of the archetype. 183 | pub fn capacity(&self) -> u32 { 184 | self.capacity 185 | } 186 | 187 | /// Returns whether the archetype is full or not. 188 | pub fn is_full(&self) -> bool { 189 | self.entity_count == self.capacity() 190 | } 191 | 192 | /// Returns a reference to the internal slice storing entity associations. 193 | pub fn entities(&self) -> &[Entity] { 194 | unsafe { &*slice_from_raw_parts(self.entity_associations, self.len() as usize) } 195 | } 196 | 197 | /// Returns a mutable reference to the internal slice storing entity associations. 198 | pub fn entities_mut(&mut self) -> &mut [Entity] { 199 | unsafe { &mut *slice_from_raw_parts_mut(self.entity_associations, self.len() as usize) } 200 | } 201 | 202 | /// Pushes a given entity/component-tuple into the archetype's backing memory. 203 | /// # Safety: 204 | /// - Must be called exactly with the component group contained in the archetype. 205 | /// - a compatible group type is also accepted. 206 | /// - Does not call drop on the given entity. 207 | /// - Increases the size of the archetype's memory allocations if required. 208 | /// - If resizing fails, this function will panic. 209 | pub unsafe fn push_entity_unchecked<'a, G: ComponentGroup>( 210 | &mut self, 211 | entity_handle: Entity, 212 | entity: G, 213 | ) -> u32 { 214 | debug_assert!(G::DESCRIPTOR.is_valid()); 215 | debug_assert_eq!( 216 | G::DESCRIPTOR.archetype().archetype_id(), 217 | self.descriptor.archetype_id() 218 | ); 219 | self.resize_if_necessary(); 220 | let entity_index = self.len(); 221 | self.entity_count += 1; 222 | self.write_entity_unchecked(entity_index, entity_handle, entity); 223 | entity_index 224 | } 225 | 226 | /// Identical to push_entity_unchecked but does not actually write the entity's component data. 227 | /// The memory at the the returned index MUST be written with valid component data. 228 | /// The metadata is not set either. 229 | pub unsafe fn push_uninitialized_entity(&mut self) -> u32 { 230 | self.resize_if_necessary(); 231 | let entity_index = self.len(); 232 | self.entity_count += 1; 233 | entity_index 234 | } 235 | 236 | /// Decrements archetype size by 1, therefore assuming the last entity is moved elsewhere. 237 | /// As such, it does not call drop on the last entity. 238 | pub unsafe fn decrement_len_unchecked(&mut self) { 239 | self.entity_count -= 1; 240 | } 241 | 242 | /// Writes a single component into a specific position. 243 | /// Does not call drop on the existing component at index. 244 | /// Panics if called on an archetype that does not contain [`C`]. 245 | pub unsafe fn write_single_component_unchecked( 246 | &mut self, 247 | index: u32, 248 | component: C, 249 | ) { 250 | match self 251 | .descriptor 252 | .components() 253 | .binary_search_by_key(&C::ID, |e| e.component_type_id) 254 | { 255 | Ok(idx) => { 256 | let pointer = (self.pointers[idx] as *mut C).offset(index as isize); 257 | core::ptr::write(pointer, component); 258 | } 259 | Err(_) => unreachable!(), 260 | } 261 | } 262 | 263 | /// Writes a given entity/component-tuple into the archetype's backing memory. 264 | /// # Safety: 265 | /// - Must be called exactly with the component group contained in the archetype. 266 | /// - a compatible group type is also accepted. 267 | /// - Does not call drop on the given entity. 268 | /// - Does not call drop on the entity that already exists at [`index`]. 269 | /// - Assumes the underlying backing memory is sized accordingly to fit the data. 270 | /// - Does not increase the entity counter. 271 | /// - Does not check if [`index`] is out of bounds or not. 272 | pub unsafe fn write_entity_unchecked( 273 | &mut self, 274 | index: u32, 275 | entity_handle: Entity, 276 | mut entity: G, 277 | ) { 278 | debug_assert!(index < self.capacity()); 279 | debug_assert!(G::DESCRIPTOR.is_valid()); 280 | debug_assert_eq!( 281 | G::DESCRIPTOR.archetype().archetype_id(), 282 | self.descriptor.archetype_id() 283 | ); 284 | let mut pointers = [core::ptr::null_mut(); MAX_COMPONENTS_PER_ENTITY]; 285 | entity.as_sorted_pointers(&mut pointers); 286 | for i in 0..G::DESCRIPTOR.len() as usize { 287 | let component = G::DESCRIPTOR 288 | .archetype() 289 | .components_unchecked() 290 | .get_unchecked(i); 291 | let dst_pointer = self 292 | .pointers 293 | .get_unchecked(i) 294 | .offset(component.size as isize * index as isize); 295 | 296 | core::ptr::copy_nonoverlapping::( 297 | *pointers.get_unchecked(i), 298 | dst_pointer, 299 | component.size as usize, 300 | ); 301 | } 302 | self.entities_mut()[index as usize] = entity_handle; 303 | core::mem::forget(entity); 304 | } 305 | 306 | /// Swaps the entity at [`index`] and the last entity and drops the now-last entity. 307 | /// This effectively reduces the size of the archetype by 1, dropping the entity at index. 308 | /// And moving the previously last entity to the position at index. 309 | /// If [`index`] is the last element, simply drops it instead without any swaps occurring. 310 | /// Returns true if a swap occurred, or false if not. 311 | /// # Safety: 312 | /// - [`index`] must be smaller than the amount of entities in the archetype. 313 | pub unsafe fn swap_drop_unchecked(&mut self, index: u32) -> bool { 314 | debug_assert!(index < self.len()); 315 | if index == self.len() - 1 { 316 | // Is the last one, so just drop it. 317 | self.drop_entity(index); 318 | self.entity_count -= 1; 319 | false 320 | } else { 321 | self.swap_entities(index, self.len() - 1); 322 | self.drop_entity(self.len() - 1); 323 | self.entity_count -= 1; 324 | true 325 | } 326 | } 327 | 328 | /// Swaps the entity at [`index`] and the last entity. 329 | /// Makes sure the entity at [`index`] is at the end of the archetype. 330 | /// If [`index`] is the last element, does nothing. 331 | /// Returns true if a swap occurred, or false if not. 332 | /// # Safety: 333 | /// - [`index`] must be smaller than the amount of entities in the archetype. 334 | pub unsafe fn swap_to_last_unchecked(&mut self, index: u32) -> bool { 335 | debug_assert!(index < self.len()); 336 | if index == self.len() - 1 { 337 | false 338 | } else { 339 | self.swap_entities(index, self.len() - 1); 340 | true 341 | } 342 | } 343 | 344 | /// Swaps the entity at [`index`] and the last entity and returns the now-last entity. 345 | /// This effectively reduces the size of the archetype by 1, returning the entity at index. 346 | /// And moving the previously last entity to the position at index. 347 | /// If [`index`] is the last element, simply returns it instead without any swaps occurring. 348 | /// Returns true if a swap occurred, or false if not. 349 | /// # Safety: 350 | /// - [`index`] must be smaller than the amount of entities in the archetype. 351 | /// - [`G`] must exactly match the type store in the archetype. 352 | /// - Ordering of component in [`G`] may be different. 353 | pub unsafe fn swap_remove_unchecked(&mut self, index: u32) -> (G, bool) { 354 | debug_assert!(index < self.len()); 355 | if index == self.len() - 1 { 356 | // Is the last one, so just drop it. 357 | let data: G = self.read_components_exact_unchecked::(index); 358 | self.entity_count -= 1; 359 | (data, false) 360 | } else { 361 | self.swap_entities(index, self.len() - 1); 362 | let data: G = self.read_components_exact_unchecked(self.len() - 1); 363 | self.entity_count -= 1; 364 | (data, true) 365 | } 366 | } 367 | 368 | /// Swaps the entities at the provided positions. 369 | /// # Safety: 370 | /// - [`first`] must be smaller than the amount of entities in the archetype. 371 | /// - [`second`] must be smaller than the amount of entities in the archetype. 372 | /// - [`first`] must not be equal to [`last`]. 373 | pub unsafe fn swap_entities(&mut self, first: u32, second: u32) { 374 | for (idx, descriptor) in self.descriptor.components().iter().enumerate() { 375 | let ptr_first = self.pointers[idx].offset(first as isize * descriptor.size as isize); 376 | let ptr_second = self.pointers[idx].offset(second as isize * descriptor.size as isize); 377 | core::ptr::swap_nonoverlapping(ptr_first, ptr_second, descriptor.size as usize); 378 | } 379 | self.entities_mut().swap(first as usize, second as usize); 380 | } 381 | 382 | /// Calls drop on the entity at [`index`]. 383 | /// # Safety: 384 | /// - [`index`] must be smaller than the amount of entities in the archetype. 385 | pub unsafe fn drop_entity(&mut self, index: u32) { 386 | for (idx, descriptor) in self.descriptor.components().iter().enumerate() { 387 | (descriptor.fns.drop_handler)( 388 | self.pointers[idx].offset(index as isize * descriptor.size as isize), 389 | 1, 390 | ); 391 | } 392 | } 393 | 394 | /// Drops all the entities in the archetype. 395 | /// Does not deallocate the memory. 396 | pub unsafe fn drop_entities(&mut self) { 397 | for (idx, descriptor) in self.descriptor.components().iter().enumerate() { 398 | (descriptor.fns.drop_handler)(self.pointers[idx], self.len() as usize); 399 | } 400 | } 401 | 402 | /// Reads the component data at [`index`] and returns it. 403 | /// # Safety: 404 | /// - [`G`] must be exactly the type stored in the archetype. 405 | /// - a compatible one also works. (i.e. same archetype, different ordering) 406 | pub unsafe fn read_components_exact_unchecked(&self, index: u32) -> G { 407 | let pointers = self.offset_sorted_pointers_unchecked(index); 408 | G::read_from_sorted_pointers(&pointers) 409 | } 410 | } 411 | 412 | impl Archetype { 413 | /// Resizes the backing memory by some amount. If this becomes less than or equal to zero, 414 | /// deallocates all memory. 415 | /// # Safety: 416 | /// - Does not call drop on the entities in the backing storage. 417 | /// - Panics if resizing fails for whatever reason. This leaves the archetype in an undefined state. 418 | /// - Deallocates if the new capacity is smaller or equal to zero. 419 | /// - Deallocates if the new capacity exceeds [`MAX_ENTITIES_PER_ARCHETYPE`]. TODO: This is weird? 420 | pub(super) unsafe fn resize_capacity(&mut self, change_in_entity_count: isize) { 421 | let old_capacity = self.capacity(); 422 | let new_capacity = old_capacity as isize + change_in_entity_count; 423 | if new_capacity <= 0 || new_capacity >= MAX_ENTITIES_PER_ARCHETYPE as isize { 424 | self.dealloc(); 425 | return; 426 | } 427 | let new_capacity = new_capacity as usize; 428 | 429 | let layout = Layout::from_size_align_unchecked( 430 | size_of::() * old_capacity as usize, 431 | align_of::(), 432 | ); 433 | self.entity_associations = realloc( 434 | self.entity_associations as *mut u8, 435 | layout, 436 | size_of::() * new_capacity, 437 | ) as *mut Entity; 438 | assert_ne!(self.entity_associations, core::ptr::null_mut()); 439 | for (index, pointer) in self.pointers[0..self.descriptor.len() as usize] 440 | .iter_mut() 441 | .enumerate() 442 | { 443 | let component_type = &self.descriptor.components()[index]; 444 | let layout = Layout::from_size_align_unchecked( 445 | component_type.size as usize * old_capacity as usize, 446 | component_type.align as usize, 447 | ); 448 | *pointer = realloc( 449 | *pointer, 450 | layout, 451 | component_type.size as usize * new_capacity, 452 | ); 453 | assert_ne!(*pointer, core::ptr::null_mut()); 454 | } 455 | self.capacity = new_capacity as u32; 456 | } 457 | 458 | /// Deallocates the backing memory and sets capacity to zero. 459 | /// # Safety: 460 | /// - Does not call drop on the entities in the backing storage. 461 | pub(super) unsafe fn dealloc(&mut self) { 462 | for (index, pointer) in self.pointers[0..self.descriptor.len() as usize] 463 | .iter_mut() 464 | .enumerate() 465 | { 466 | if pointer.is_null() { 467 | return; 468 | } 469 | let component_type = &self.descriptor.components()[index]; 470 | let layout = Layout::from_size_align_unchecked( 471 | component_type.size as usize * self.capacity as usize, 472 | component_type.align as usize, 473 | ); 474 | dealloc(*pointer, layout); 475 | *pointer = core::ptr::null_mut(); 476 | } 477 | let layout = Layout::from_size_align_unchecked( 478 | size_of::() * self.capacity() as usize, 479 | align_of::(), 480 | ); 481 | dealloc(self.entity_associations as *mut u8, layout); 482 | self.entity_associations = core::ptr::null_mut(); 483 | self.capacity = 0; 484 | } 485 | 486 | /// Returns the pointers, offset by [`index`] elements. 487 | unsafe fn offset_sorted_pointers_unchecked( 488 | &self, 489 | index: u32, 490 | ) -> [*mut u8; MAX_COMPONENTS_PER_ENTITY] { 491 | let mut pointers = [core::ptr::null_mut(); MAX_COMPONENTS_PER_ENTITY]; 492 | for (c_idx, pointer) in self.pointers[0..self.descriptor.len() as usize] 493 | .iter() 494 | .enumerate() 495 | { 496 | pointers[c_idx] = 497 | pointer.offset(self.descriptor.components()[c_idx].size as isize * index as isize); 498 | } 499 | pointers 500 | } 501 | 502 | /// Resizes the backing memory by the default amount if necessary. 503 | unsafe fn resize_if_necessary(&mut self) { 504 | if self.is_full() { 505 | let additional_capacity = if self.capacity() == 0 { 506 | DEFAULT_ARCHETYPE_ALLOCATION_SIZE 507 | } else { 508 | self.capacity() as usize 509 | }; 510 | self.resize_capacity(additional_capacity as isize); 511 | } 512 | } 513 | 514 | /// Copies common components between two archetypes. 515 | pub unsafe fn copy_common_components_between_archetypes_unchecked( 516 | source: &Archetype, 517 | source_index: u32, 518 | destination: &mut Archetype, 519 | destination_index: u32, 520 | ) { 521 | for (source_c_idx, source_component) in source.descriptor.components().iter().enumerate() { 522 | for (destination_c_idx, destination_component) in 523 | destination.descriptor.components().iter().enumerate() 524 | { 525 | if source_component.component_type_id != destination_component.component_type_id { 526 | continue; 527 | } 528 | core::ptr::copy_nonoverlapping( 529 | source.pointers[source_c_idx] 530 | .offset(source_component.size as isize * source_index as isize), 531 | destination.pointers[destination_c_idx] 532 | .offset(destination_component.size as isize * destination_index as isize), 533 | source_component.size as usize, 534 | ); 535 | } 536 | } 537 | } 538 | 539 | /// Returns the pointers for the components in [`G`], provided that archetype itself contains a superset of G. 540 | /// This function is slower than the exact version, use that if an exact type match is known. 541 | /// # Safety: 542 | /// - offset must be smaller than self.capacity. 543 | /// - Only call this with subsets of the types stored in the shard. 544 | unsafe fn get_fuzzy_pointers_unchecked<'a, G: ComponentGroup>( 545 | &'a self, 546 | offset: u32, 547 | ) -> [*mut u8; MAX_COMPONENTS_PER_ENTITY] { 548 | let mut pointers = [core::ptr::null_mut(); MAX_COMPONENTS_PER_ENTITY]; 549 | for (index, descriptor) in G::DESCRIPTOR.archetype().components().iter().enumerate() { 550 | 'inner_loop: for check_index in index..self.descriptor.len() as usize { 551 | if self 552 | .descriptor 553 | .components_unchecked() 554 | .get_unchecked(check_index) 555 | .component_type_id 556 | .into_u16() 557 | == descriptor.component_type_id.into_u16() 558 | { 559 | *pointers.get_unchecked_mut(index) = self 560 | .pointers 561 | .get_unchecked(check_index) 562 | .offset(descriptor.size() as isize * offset as isize); 563 | break 'inner_loop; 564 | } 565 | } 566 | } 567 | pointers 568 | } 569 | } 570 | -------------------------------------------------------------------------------- /src/archetype/mod.rs: -------------------------------------------------------------------------------- 1 | use crate::constants::DEFAULT_ARCHETYPE_ALLOCATION_SIZE; 2 | use crate::descriptors::archetype_descriptor::ArchetypeDescriptor; 3 | use crate::*; 4 | use alloc::alloc::{alloc, Layout}; 5 | use core::mem::{align_of, size_of}; 6 | 7 | mod data_access; 8 | #[cfg(test)] 9 | mod tests; 10 | 11 | #[derive(Debug)] 12 | pub struct Archetype { 13 | descriptor: ArchetypeDescriptor, 14 | pointers: [*mut u8; MAX_COMPONENTS_PER_ENTITY], 15 | entity_associations: *mut Entity, 16 | entity_count: u32, 17 | capacity: u32, 18 | } 19 | 20 | unsafe impl Send for Archetype {} 21 | unsafe impl Sync for Archetype {} 22 | 23 | impl Archetype { 24 | /// Creates an archetype with the default amount of memory allocated for it. 25 | /// Panics if the provided archetype descriptor is invalid. 26 | #[allow(dead_code)] 27 | pub fn new(archetype_descriptor: &ArchetypeDescriptor) -> Archetype { 28 | assert!(archetype_descriptor.is_valid()); 29 | Self::with_capacity( 30 | archetype_descriptor, 31 | DEFAULT_ARCHETYPE_ALLOCATION_SIZE as u32, 32 | ) 33 | } 34 | 35 | /// Allocates an archetype with a given capacity for storing data into it. 36 | /// Panics if the provided archetype descriptor is invalid. 37 | /// Does not allocate if [`capacity`] exceeds [`MAX_ENTITIES_PER_ARCHETYPE`]. 38 | /// Does not allocate if [`capacity`] is 0. 39 | /// Panics in case of allocation failures. 40 | pub fn with_capacity(archetype_descriptor: &ArchetypeDescriptor, capacity: u32) -> Archetype { 41 | assert!(archetype_descriptor.is_valid()); 42 | let mut archetype = Self { 43 | descriptor: archetype_descriptor.clone(), 44 | pointers: [core::ptr::null_mut(); MAX_COMPONENTS_PER_ENTITY], 45 | entity_associations: core::ptr::null_mut(), 46 | entity_count: 0, 47 | capacity: 0, 48 | }; 49 | // Allocate 50 | if capacity > 0 && capacity <= MAX_ENTITIES_PER_ARCHETYPE { 51 | unsafe { 52 | let layout = Layout::from_size_align_unchecked( 53 | size_of::() * capacity as usize, 54 | align_of::(), 55 | ); 56 | archetype.entity_associations = alloc(layout) as *mut Entity; 57 | assert_ne!(archetype.entity_associations, core::ptr::null_mut()); 58 | 59 | for (index, component) in archetype.descriptor.components().iter().enumerate() { 60 | let layout = Layout::from_size_align_unchecked( 61 | component.size as usize * capacity as usize, 62 | component.align as usize, 63 | ); 64 | archetype.pointers[index] = alloc(layout); 65 | assert_ne!(archetype.pointers[index], core::ptr::null_mut()); 66 | } 67 | archetype.capacity = capacity; 68 | } 69 | } 70 | archetype 71 | } 72 | 73 | pub fn descriptor(&self) -> &ArchetypeDescriptor { 74 | &self.descriptor 75 | } 76 | } 77 | 78 | impl Drop for Archetype { 79 | fn drop(&mut self) { 80 | // Archetype is empty if there is no capacity. 81 | if self.capacity == 0 { 82 | return; 83 | } 84 | unsafe { 85 | self.drop_entities(); 86 | self.dealloc(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /src/archetype/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::archetype::Archetype; 2 | use crate::descriptors::archetype_descriptor::ArchetypeDescriptor; 3 | use crate::descriptors::component_group::ComponentGroup; 4 | use crate::test_components::*; 5 | use crate::{Entity, MAX_ENTITIES_PER_ARCHETYPE}; 6 | 7 | #[test] 8 | fn test_archetype_constructors() { 9 | let descriptor: &ArchetypeDescriptor = <(A, B) as ComponentGroup>::DESCRIPTOR.archetype(); 10 | // Empty constructor should not panic 11 | let _ = Archetype::new(descriptor); 12 | Archetype::with_capacity(descriptor, 0); 13 | Archetype::with_capacity(descriptor, MAX_ENTITIES_PER_ARCHETYPE); 14 | Archetype::with_capacity(descriptor, MAX_ENTITIES_PER_ARCHETYPE + 1); 15 | } 16 | 17 | #[test] 18 | fn test_archetype_slices() { 19 | unsafe { 20 | let descriptor = <(A, B, C) as ComponentGroup>::DESCRIPTOR.archetype(); 21 | 22 | let mut archetype = Archetype::new(descriptor); 23 | let meta = Entity::INVALID; 24 | 25 | let _idx = 26 | archetype.push_entity_unchecked(meta, (A::default(), B::default(), C::default())); 27 | assert_eq!(archetype.entity_count, 1); 28 | assert_eq!(meta, archetype.entities().as_ref()[0]); 29 | 30 | let slices: (&[A], &[B], &[C]) = archetype.get_slices_unchecked_exact::<(A, B, C)>(); 31 | assert_eq!(slices.0.len(), 1); 32 | assert_eq!(slices.1.len(), 1); 33 | assert_eq!(slices.0[0], A::default()); 34 | assert_eq!(slices.1[0], B::default()); 35 | assert_eq!(slices.2[0], C::default()); 36 | let slices: (&[B], &[A], &[C]) = archetype.get_slices_unchecked_exact::<(B, A, C)>(); 37 | assert_eq!(slices.0.len(), 1); 38 | assert_eq!(slices.1.len(), 1); 39 | assert_eq!(slices.0[0], B::default()); 40 | assert_eq!(slices.1[0], A::default()); 41 | assert_eq!(slices.2[0], C::default()); 42 | 43 | let slices: (&[B], &[A]) = archetype.get_fuzzy_slices_unchecked::<(B, A)>(); 44 | assert_eq!(slices.0.len(), 1); 45 | assert_eq!(slices.1.len(), 1); 46 | assert_eq!(slices.0[0], B::default()); 47 | assert_eq!(slices.1[0], A::default()); 48 | 49 | let slices: (&[A], &[C]) = archetype.get_fuzzy_slices_unchecked::<(A, C)>(); 50 | assert_eq!(slices.0.len(), 1); 51 | assert_eq!(slices.1.len(), 1); 52 | assert_eq!(slices.0[0], A::default()); 53 | assert_eq!(slices.1[0], C::default()); 54 | } 55 | } 56 | 57 | #[test] 58 | fn test_archetype_get_components() { 59 | unsafe { 60 | let descriptor = <(A, B, C) as ComponentGroup>::DESCRIPTOR.archetype(); 61 | 62 | let mut archetype = Archetype::new(descriptor); 63 | let meta = Entity::INVALID; 64 | 65 | let idx = archetype.push_entity_unchecked(meta, (A::default(), B::default(), C::default())); 66 | assert_eq!(*archetype.get_component_unchecked::(idx), A::default()); 67 | assert_eq!( 68 | *archetype.get_component_unchecked_mut::(idx), 69 | B::default() 70 | ) 71 | } 72 | } 73 | 74 | #[test] 75 | fn test_archetype_swap_entities() { 76 | unsafe { 77 | let descriptor = <(A, B) as ComponentGroup>::DESCRIPTOR.archetype(); 78 | 79 | let mut archetype = Archetype::new(descriptor); 80 | let meta1 = Entity::from_raw(1); 81 | let meta2 = Entity::from_raw(2); 82 | 83 | let idx1 = archetype.push_entity_unchecked(meta1, (A { _data: 1 }, B { _data: 3 })); 84 | let idx2 = archetype.push_entity_unchecked(meta2, (A { _data: 2 }, B { _data: 4 })); 85 | assert_eq!( 86 | *archetype.get_component_unchecked::(idx1), 87 | A { _data: 1 } 88 | ); 89 | assert_eq!( 90 | archetype.read_component_unchecked::(idx1), 91 | A { _data: 1 } 92 | ); 93 | assert_eq!( 94 | *archetype.get_component_unchecked_mut::(idx1), 95 | B { _data: 3 } 96 | ); 97 | assert_eq!( 98 | archetype.read_component_unchecked::(idx1), 99 | B { _data: 3 } 100 | ); 101 | assert_eq!( 102 | *archetype.get_component_unchecked::(idx2), 103 | A { _data: 2 } 104 | ); 105 | assert_eq!( 106 | archetype.read_component_unchecked::(idx2), 107 | A { _data: 2 } 108 | ); 109 | assert_eq!( 110 | *archetype.get_component_unchecked_mut::(idx2), 111 | B { _data: 4 } 112 | ); 113 | assert_eq!( 114 | archetype.read_component_unchecked::(idx2), 115 | B { _data: 4 } 116 | ); 117 | 118 | assert_eq!(archetype.entities()[idx1 as usize], meta1); 119 | assert_eq!(archetype.entities()[idx2 as usize], meta2); 120 | 121 | archetype.swap_entities(idx1, idx2); 122 | assert_eq!( 123 | *archetype.get_component_unchecked::(idx2), 124 | A { _data: 1 } 125 | ); 126 | assert_eq!( 127 | *archetype.get_component_unchecked_mut::(idx2), 128 | B { _data: 3 } 129 | ); 130 | assert_eq!( 131 | *archetype.get_component_unchecked::(idx1), 132 | A { _data: 2 } 133 | ); 134 | assert_eq!( 135 | *archetype.get_component_unchecked_mut::(idx1), 136 | B { _data: 4 } 137 | ); 138 | 139 | assert_eq!(archetype.entities()[idx2 as usize], meta1); 140 | assert_eq!(archetype.entities()[idx1 as usize], meta2); 141 | 142 | archetype.swap_entities(idx1, idx2); 143 | assert_eq!( 144 | *archetype.get_component_unchecked::(idx1), 145 | A { _data: 1 } 146 | ); 147 | assert_eq!( 148 | *archetype.get_component_unchecked_mut::(idx1), 149 | B { _data: 3 } 150 | ); 151 | assert_eq!( 152 | *archetype.get_component_unchecked::(idx2), 153 | A { _data: 2 } 154 | ); 155 | assert_eq!( 156 | *archetype.get_component_unchecked_mut::(idx2), 157 | B { _data: 4 } 158 | ); 159 | 160 | assert_eq!(archetype.entities()[idx1 as usize], meta1); 161 | assert_eq!(archetype.entities()[idx2 as usize], meta2); 162 | } 163 | } 164 | 165 | #[test] 166 | fn test_archetype_read_components() { 167 | unsafe { 168 | let descriptor = <(A, B) as ComponentGroup>::DESCRIPTOR.archetype(); 169 | 170 | let mut archetype = Archetype::new(descriptor); 171 | let meta = Entity::INVALID; 172 | 173 | let idx = archetype.push_entity_unchecked(meta, (A::default(), B::default())); 174 | assert_eq!( 175 | archetype.read_components_exact_unchecked::<(A, B)>(idx), 176 | (A::default(), B::default()) 177 | ); 178 | assert_eq!( 179 | archetype.read_components_exact_unchecked::<(B, A)>(idx), 180 | (B::default(), A::default()) 181 | ); 182 | 183 | let descriptor = <(A, B, C) as ComponentGroup>::DESCRIPTOR.archetype(); 184 | 185 | let mut archetype = Archetype::new(descriptor); 186 | let meta = Entity::INVALID; 187 | let idx = archetype.push_entity_unchecked(meta, (A::default(), B::default(), C::default())); 188 | assert_eq!( 189 | archetype.read_components_exact_unchecked::<(A, B, C)>(idx), 190 | (A::default(), B::default(), C::default()) 191 | ); 192 | assert_eq!( 193 | archetype.read_components_exact_unchecked::<(B, C, A)>(idx), 194 | (B::default(), C::default(), A::default()) 195 | ); 196 | } 197 | } 198 | -------------------------------------------------------------------------------- /src/archetype_registry/iterators/archetype_iter.rs: -------------------------------------------------------------------------------- 1 | use super::super::*; 2 | use crate::descriptors::component_group::ComponentGroup; 3 | use alloc::vec::*; 4 | use core::iter::FusedIterator; 5 | use core::marker::PhantomData; 6 | 7 | pub(crate) struct ArchetypeIter<'a, G: ComponentGroup> { 8 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 9 | archetypes: &'a [Archetype], 10 | current_level: u8, 11 | current_index_in_level: usize, 12 | _phantom: PhantomData, 13 | } 14 | 15 | impl<'a, G: ComponentGroup> ArchetypeIter<'a, G> { 16 | pub(in crate::archetype_registry) fn new( 17 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 18 | archetypes: &'a [Archetype], 19 | ) -> Self { 20 | Self { 21 | sorted_mappings, 22 | archetypes, 23 | current_level: G::DESCRIPTOR.len() - 1, 24 | current_index_in_level: 0, 25 | _phantom: Default::default(), 26 | } 27 | } 28 | } 29 | 30 | impl<'a, G: ComponentGroup> Iterator for ArchetypeIter<'a, G> { 31 | type Item = &'a Archetype; 32 | 33 | fn next(&mut self) -> Option { 34 | if !G::DESCRIPTOR.is_valid() { 35 | return None; 36 | } 37 | while (self.current_level as usize) < MAX_COMPONENTS_PER_ENTITY { 38 | unsafe { 39 | let level = &self 40 | .sorted_mappings 41 | .get_unchecked(self.current_level as usize); 42 | while (self.current_index_in_level as usize) < level.len() { 43 | let arch_index = level 44 | .get_unchecked(self.current_index_in_level as usize) 45 | .archetype_index; 46 | self.current_index_in_level += 1; 47 | let archetype = &self.archetypes.get_unchecked(arch_index as usize); 48 | if archetype 49 | .descriptor() 50 | .contains_subset(G::DESCRIPTOR.archetype()) 51 | { 52 | return Some(archetype); 53 | } 54 | } 55 | self.current_index_in_level = 0; 56 | self.current_level += 1; 57 | } 58 | } 59 | None 60 | } 61 | } 62 | 63 | impl<'a, G: ComponentGroup> FusedIterator for ArchetypeIter<'a, G> {} 64 | -------------------------------------------------------------------------------- /src/archetype_registry/iterators/archetype_iter_mut.rs: -------------------------------------------------------------------------------- 1 | use super::super::*; 2 | use crate::descriptors::component_group::ComponentGroup; 3 | use alloc::vec::*; 4 | use core::iter::FusedIterator; 5 | use core::marker::PhantomData; 6 | 7 | pub(crate) struct ArchetypeIterMut<'a, G: ComponentGroup> { 8 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 9 | archetypes: &'a mut [Archetype], 10 | current_level: u8, 11 | current_index_in_level: usize, 12 | _phantom: PhantomData, 13 | } 14 | 15 | impl<'a, G: ComponentGroup> ArchetypeIterMut<'a, G> { 16 | pub(in crate::archetype_registry) fn new( 17 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 18 | archetypes: &'a mut [Archetype], 19 | ) -> Self { 20 | Self { 21 | sorted_mappings, 22 | archetypes, 23 | current_level: G::DESCRIPTOR.len() - 1, 24 | current_index_in_level: 0, 25 | _phantom: Default::default(), 26 | } 27 | } 28 | } 29 | 30 | impl<'a, G: ComponentGroup> Iterator for ArchetypeIterMut<'a, G> { 31 | type Item = &'a mut Archetype; 32 | 33 | fn next(&mut self) -> Option { 34 | if !G::DESCRIPTOR.is_valid() { 35 | return None; 36 | } 37 | unsafe { 38 | while (self.current_level as usize) < MAX_COMPONENTS_PER_ENTITY { 39 | let level = &self 40 | .sorted_mappings 41 | .get_unchecked(self.current_level as usize); 42 | while (self.current_index_in_level as usize) < level.len() { 43 | let arch_index = level 44 | .get_unchecked(self.current_index_in_level as usize) 45 | .archetype_index; 46 | self.current_index_in_level += 1; 47 | // Safety: The problem is that the compiler cannot guarantee we don't mutably borrow 48 | // the same element twice. We don't, so use unsafe to implement this. 49 | let archetype: &mut Archetype = 50 | &mut *self.archetypes.as_mut_ptr().offset(arch_index as isize); 51 | if archetype 52 | .descriptor() 53 | .contains_subset(G::DESCRIPTOR.archetype()) 54 | { 55 | return Some(archetype); 56 | } 57 | } 58 | self.current_index_in_level = 0; 59 | self.current_level += 1; 60 | } 61 | } 62 | None 63 | } 64 | } 65 | 66 | impl<'a, G: ComponentGroup> FusedIterator for ArchetypeIterMut<'a, G> {} 67 | -------------------------------------------------------------------------------- /src/archetype_registry/iterators/filter_archetype_iter.rs: -------------------------------------------------------------------------------- 1 | use super::super::*; 2 | use crate::descriptors::component_group::ComponentGroup; 3 | use alloc::vec::*; 4 | use core::iter::FusedIterator; 5 | use core::marker::PhantomData; 6 | 7 | pub(crate) struct FilterArchetypeIter<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> { 8 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 9 | archetypes: &'a [Archetype], 10 | current_level: u8, 11 | current_index_in_level: usize, 12 | filter_closure: F, 13 | _phantom: PhantomData, 14 | } 15 | 16 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> FilterArchetypeIter<'a, G, F> { 17 | pub(in crate::archetype_registry) fn new( 18 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 19 | archetypes: &'a [Archetype], 20 | filter_closure: F, 21 | ) -> Self { 22 | Self { 23 | sorted_mappings, 24 | archetypes, 25 | current_level: G::DESCRIPTOR.len() - 1, 26 | current_index_in_level: 0, 27 | _phantom: Default::default(), 28 | filter_closure, 29 | } 30 | } 31 | } 32 | 33 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> Iterator 34 | for FilterArchetypeIter<'a, G, F> 35 | { 36 | type Item = &'a Archetype; 37 | 38 | fn next(&mut self) -> Option { 39 | if !G::DESCRIPTOR.is_valid() { 40 | return None; 41 | } 42 | while (self.current_level as usize) < MAX_COMPONENTS_PER_ENTITY { 43 | unsafe { 44 | let level = &self 45 | .sorted_mappings 46 | .get_unchecked(self.current_level as usize); 47 | while (self.current_index_in_level as usize) < level.len() { 48 | let arch_index = level 49 | .get_unchecked(self.current_index_in_level as usize) 50 | .archetype_index; 51 | self.current_index_in_level += 1; 52 | let archetype = &self.archetypes.get_unchecked(arch_index as usize); 53 | if archetype 54 | .descriptor() 55 | .contains_subset(G::DESCRIPTOR.archetype()) 56 | && (self.filter_closure)(archetype.descriptor()) 57 | { 58 | return Some(archetype); 59 | } 60 | } 61 | self.current_index_in_level = 0; 62 | self.current_level += 1; 63 | } 64 | } 65 | None 66 | } 67 | } 68 | 69 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> FusedIterator 70 | for FilterArchetypeIter<'a, G, F> 71 | { 72 | } 73 | -------------------------------------------------------------------------------- /src/archetype_registry/iterators/filter_archetype_iter_mut.rs: -------------------------------------------------------------------------------- 1 | use super::super::*; 2 | use crate::descriptors::component_group::ComponentGroup; 3 | use alloc::vec::*; 4 | use core::iter::FusedIterator; 5 | use core::marker::PhantomData; 6 | 7 | pub(crate) struct FilterArchetypeIterMut<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> 8 | { 9 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 10 | archetypes: &'a mut [Archetype], 11 | current_level: u8, 12 | current_index_in_level: usize, 13 | filter_closure: F, 14 | _phantom: PhantomData, 15 | } 16 | 17 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> FilterArchetypeIterMut<'a, G, F> { 18 | pub(in crate::archetype_registry) fn new( 19 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 20 | archetypes: &'a mut [Archetype], 21 | filter_closure: F, 22 | ) -> Self { 23 | Self { 24 | sorted_mappings, 25 | archetypes, 26 | current_level: G::DESCRIPTOR.len() - 1, 27 | current_index_in_level: 0, 28 | _phantom: Default::default(), 29 | filter_closure, 30 | } 31 | } 32 | } 33 | 34 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> Iterator 35 | for FilterArchetypeIterMut<'a, G, F> 36 | { 37 | type Item = &'a mut Archetype; 38 | 39 | fn next(&mut self) -> Option { 40 | if !G::DESCRIPTOR.is_valid() { 41 | return None; 42 | } 43 | unsafe { 44 | while (self.current_level as usize) < MAX_COMPONENTS_PER_ENTITY { 45 | let level = &self 46 | .sorted_mappings 47 | .get_unchecked(self.current_level as usize); 48 | while (self.current_index_in_level as usize) < level.len() { 49 | let arch_index = level 50 | .get_unchecked(self.current_index_in_level as usize) 51 | .archetype_index; 52 | self.current_index_in_level += 1; 53 | // Safety: The problem is that the compiler cannot guarantee we don't mutably borrow 54 | // the same element twice. We don't, so use unsafe to implement this. 55 | let archetype: &mut Archetype = 56 | &mut *self.archetypes.as_mut_ptr().offset(arch_index as isize); 57 | if archetype 58 | .descriptor() 59 | .contains_subset(G::DESCRIPTOR.archetype()) 60 | && (self.filter_closure)(archetype.descriptor()) 61 | { 62 | return Some(archetype); 63 | } 64 | } 65 | self.current_index_in_level = 0; 66 | self.current_level += 1; 67 | } 68 | } 69 | None 70 | } 71 | } 72 | 73 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> FusedIterator 74 | for FilterArchetypeIterMut<'a, G, F> 75 | { 76 | } 77 | -------------------------------------------------------------------------------- /src/archetype_registry/iterators/filter_matching_iter.rs: -------------------------------------------------------------------------------- 1 | use super::super::*; 2 | use super::*; 3 | use crate::descriptors::component_group::ComponentGroup; 4 | use crate::Entity; 5 | use alloc::vec::*; 6 | use core::iter::FusedIterator; 7 | 8 | pub(crate) struct FilterMatchingIter<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> { 9 | inner_iterator: FilterArchetypeIter<'a, G, F>, 10 | } 11 | 12 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> FilterMatchingIter<'a, G, F> { 13 | pub(in crate::archetype_registry) fn new( 14 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 15 | archetypes: &'a [Archetype], 16 | filter_closure: F, 17 | ) -> Self { 18 | Self { 19 | inner_iterator: FilterArchetypeIter::new(sorted_mappings, archetypes, filter_closure), 20 | } 21 | } 22 | } 23 | 24 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> Iterator 25 | for FilterMatchingIter<'a, G, F> 26 | { 27 | type Item = G::SliceRefTuple<'a>; 28 | 29 | fn next(&mut self) -> Option { 30 | let archetype = self.inner_iterator.next()?; 31 | unsafe { Some(archetype.get_fuzzy_slices_unchecked::()) } 32 | } 33 | } 34 | 35 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> FusedIterator 36 | for FilterMatchingIter<'a, G, F> 37 | { 38 | } 39 | 40 | pub(crate) struct FilterEntityMatchingIter< 41 | 'a, 42 | G: ComponentGroup, 43 | F: Fn(&ArchetypeDescriptor) -> bool, 44 | > { 45 | inner_iterator: FilterArchetypeIter<'a, G, F>, 46 | } 47 | 48 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> 49 | FilterEntityMatchingIter<'a, G, F> 50 | { 51 | pub(in crate::archetype_registry) fn new( 52 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 53 | archetypes: &'a [Archetype], 54 | filter_closure: F, 55 | ) -> Self { 56 | Self { 57 | inner_iterator: FilterArchetypeIter::new(sorted_mappings, archetypes, filter_closure), 58 | } 59 | } 60 | } 61 | 62 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> Iterator 63 | for FilterEntityMatchingIter<'a, G, F> 64 | { 65 | type Item = (&'a [Entity], G::SliceRefTuple<'a>); 66 | 67 | fn next(&mut self) -> Option { 68 | let archetype = self.inner_iterator.next()?; 69 | unsafe { Some(archetype.get_entity_fuzzy_slices_unchecked::()) } 70 | } 71 | } 72 | 73 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> FusedIterator 74 | for FilterEntityMatchingIter<'a, G, F> 75 | { 76 | } 77 | -------------------------------------------------------------------------------- /src/archetype_registry/iterators/filter_matching_iter_mut.rs: -------------------------------------------------------------------------------- 1 | use super::super::*; 2 | use super::*; 3 | use crate::descriptors::component_group::ComponentGroup; 4 | use crate::Entity; 5 | use alloc::vec::*; 6 | use core::iter::FusedIterator; 7 | 8 | pub(crate) struct FilterMatchingIterMut<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> 9 | { 10 | inner_iterator: FilterArchetypeIterMut<'a, G, F>, 11 | } 12 | 13 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> FilterMatchingIterMut<'a, G, F> { 14 | pub(in crate::archetype_registry) fn new( 15 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 16 | archetypes: &'a mut [Archetype], 17 | filter_closure: F, 18 | ) -> Self { 19 | Self { 20 | inner_iterator: FilterArchetypeIterMut::new( 21 | sorted_mappings, 22 | archetypes, 23 | filter_closure, 24 | ), 25 | } 26 | } 27 | } 28 | 29 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> Iterator 30 | for FilterMatchingIterMut<'a, G, F> 31 | { 32 | type Item = G::SliceMutRefTuple<'a>; 33 | 34 | fn next(&mut self) -> Option { 35 | let archetype = self.inner_iterator.next()?; 36 | unsafe { Some(archetype.get_fuzzy_slices_unchecked_mut::()) } 37 | } 38 | } 39 | 40 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> FusedIterator 41 | for FilterMatchingIterMut<'a, G, F> 42 | { 43 | } 44 | 45 | pub(crate) struct FilterEntityMatchingIterMut< 46 | 'a, 47 | G: ComponentGroup, 48 | F: Fn(&ArchetypeDescriptor) -> bool, 49 | > { 50 | inner_iterator: FilterArchetypeIterMut<'a, G, F>, 51 | } 52 | 53 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> 54 | FilterEntityMatchingIterMut<'a, G, F> 55 | { 56 | pub(in crate::archetype_registry) fn new( 57 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 58 | archetypes: &'a mut [Archetype], 59 | filter_closure: F, 60 | ) -> Self { 61 | Self { 62 | inner_iterator: FilterArchetypeIterMut::new( 63 | sorted_mappings, 64 | archetypes, 65 | filter_closure, 66 | ), 67 | } 68 | } 69 | } 70 | 71 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> Iterator 72 | for FilterEntityMatchingIterMut<'a, G, F> 73 | { 74 | type Item = (&'a [Entity], G::SliceMutRefTuple<'a>); 75 | 76 | fn next(&mut self) -> Option { 77 | let archetype = self.inner_iterator.next()?; 78 | unsafe { Some(archetype.get_entity_fuzzy_slices_unchecked_mut::()) } 79 | } 80 | } 81 | 82 | impl<'a, G: ComponentGroup, F: Fn(&ArchetypeDescriptor) -> bool> FusedIterator 83 | for FilterEntityMatchingIterMut<'a, G, F> 84 | { 85 | } 86 | -------------------------------------------------------------------------------- /src/archetype_registry/iterators/matching_iter.rs: -------------------------------------------------------------------------------- 1 | use super::super::*; 2 | use super::*; 3 | use crate::descriptors::component_group::ComponentGroup; 4 | use crate::Entity; 5 | use alloc::vec::*; 6 | use core::iter::FusedIterator; 7 | 8 | pub(crate) struct MatchingIter<'a, G: ComponentGroup> { 9 | inner_iterator: ArchetypeIter<'a, G>, 10 | } 11 | 12 | impl<'a, G: ComponentGroup> MatchingIter<'a, G> { 13 | pub(in crate::archetype_registry) fn new( 14 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 15 | archetypes: &'a [Archetype], 16 | ) -> Self { 17 | Self { 18 | inner_iterator: ArchetypeIter::new(sorted_mappings, archetypes), 19 | } 20 | } 21 | } 22 | 23 | impl<'a, G: ComponentGroup> Iterator for MatchingIter<'a, G> { 24 | type Item = G::SliceRefTuple<'a>; 25 | 26 | fn next(&mut self) -> Option { 27 | let archetype = self.inner_iterator.next()?; 28 | unsafe { Some(archetype.get_fuzzy_slices_unchecked::()) } 29 | } 30 | } 31 | 32 | impl<'a, G: ComponentGroup> FusedIterator for MatchingIter<'a, G> {} 33 | 34 | pub(crate) struct EntityMatchingIter<'a, G: ComponentGroup> { 35 | inner_iterator: ArchetypeIter<'a, G>, 36 | } 37 | 38 | impl<'a, G: ComponentGroup> EntityMatchingIter<'a, G> { 39 | pub(in crate::archetype_registry) fn new( 40 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 41 | archetypes: &'a [Archetype], 42 | ) -> Self { 43 | Self { 44 | inner_iterator: ArchetypeIter::new(sorted_mappings, archetypes), 45 | } 46 | } 47 | } 48 | 49 | impl<'a, G: ComponentGroup> Iterator for EntityMatchingIter<'a, G> { 50 | type Item = (&'a [Entity], G::SliceRefTuple<'a>); 51 | 52 | fn next(&mut self) -> Option { 53 | let archetype = self.inner_iterator.next()?; 54 | unsafe { Some(archetype.get_entity_fuzzy_slices_unchecked::()) } 55 | } 56 | } 57 | 58 | impl<'a, G: ComponentGroup> FusedIterator for EntityMatchingIter<'a, G> {} 59 | -------------------------------------------------------------------------------- /src/archetype_registry/iterators/matching_iter_mut.rs: -------------------------------------------------------------------------------- 1 | use super::super::*; 2 | use super::*; 3 | use crate::descriptors::component_group::ComponentGroup; 4 | use crate::Entity; 5 | use alloc::vec::*; 6 | use core::iter::FusedIterator; 7 | 8 | pub(crate) struct MatchingIterMut<'a, G: ComponentGroup> { 9 | inner_iterator: ArchetypeIterMut<'a, G>, 10 | } 11 | 12 | impl<'a, G: ComponentGroup> MatchingIterMut<'a, G> { 13 | pub(in crate::archetype_registry) fn new( 14 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 15 | archetypes: &'a mut [Archetype], 16 | ) -> Self { 17 | Self { 18 | inner_iterator: ArchetypeIterMut::new(sorted_mappings, archetypes), 19 | } 20 | } 21 | } 22 | 23 | impl<'a, G: ComponentGroup> Iterator for MatchingIterMut<'a, G> { 24 | type Item = G::SliceMutRefTuple<'a>; 25 | 26 | fn next(&mut self) -> Option { 27 | let archetype = self.inner_iterator.next()?; 28 | unsafe { Some(archetype.get_fuzzy_slices_unchecked_mut::()) } 29 | } 30 | } 31 | 32 | impl<'a, G: ComponentGroup> FusedIterator for MatchingIterMut<'a, G> {} 33 | 34 | pub(crate) struct EntityMatchingIterMut<'a, G: ComponentGroup> { 35 | inner_iterator: ArchetypeIterMut<'a, G>, 36 | } 37 | 38 | impl<'a, G: ComponentGroup> EntityMatchingIterMut<'a, G> { 39 | pub(in crate::archetype_registry) fn new( 40 | sorted_mappings: &'a [Vec; MAX_COMPONENTS_PER_ENTITY], 41 | archetypes: &'a mut [Archetype], 42 | ) -> Self { 43 | Self { 44 | inner_iterator: ArchetypeIterMut::new(sorted_mappings, archetypes), 45 | } 46 | } 47 | } 48 | 49 | impl<'a, G: ComponentGroup> Iterator for EntityMatchingIterMut<'a, G> { 50 | type Item = (&'a [Entity], G::SliceMutRefTuple<'a>); 51 | 52 | fn next(&mut self) -> Option { 53 | let archetype = self.inner_iterator.next()?; 54 | unsafe { Some(archetype.get_entity_fuzzy_slices_unchecked_mut::()) } 55 | } 56 | } 57 | 58 | impl<'a, G: ComponentGroup> FusedIterator for EntityMatchingIterMut<'a, G> {} 59 | -------------------------------------------------------------------------------- /src/archetype_registry/iterators/mod.rs: -------------------------------------------------------------------------------- 1 | mod matching_iter; 2 | mod matching_iter_mut; 3 | 4 | mod archetype_iter; 5 | mod archetype_iter_mut; 6 | 7 | mod filter_archetype_iter; 8 | mod filter_archetype_iter_mut; 9 | mod filter_matching_iter; 10 | mod filter_matching_iter_mut; 11 | 12 | pub(crate) use archetype_iter::*; 13 | pub(crate) use archetype_iter_mut::*; 14 | pub(crate) use filter_archetype_iter::*; 15 | pub(crate) use filter_archetype_iter_mut::*; 16 | pub(crate) use filter_matching_iter::*; 17 | pub(crate) use filter_matching_iter_mut::*; 18 | pub(crate) use matching_iter::*; 19 | pub(crate) use matching_iter_mut::*; 20 | -------------------------------------------------------------------------------- /src/archetype_registry/mod.rs: -------------------------------------------------------------------------------- 1 | mod sorted_archetype_key; 2 | 3 | pub(crate) mod iterators; 4 | #[cfg(test)] 5 | mod tests; 6 | 7 | use alloc::vec::*; 8 | use core::ops::{Index, IndexMut}; 9 | use sorted_archetype_key::*; 10 | 11 | use crate::archetype::Archetype; 12 | use crate::archetype_registry::iterators::*; 13 | use crate::constants::*; 14 | use crate::descriptors::archetype_descriptor::ArchetypeDescriptor; 15 | use crate::descriptors::component_descriptor::ComponentDescriptor; 16 | use crate::descriptors::component_group::ComponentGroup; 17 | use crate::Entity; 18 | 19 | const DEFAULT_VECTOR_CAPACITY: usize = 64; 20 | 21 | #[doc(hidden)] 22 | fn disjoint_mut(slice: &mut [T], first: usize, second: usize) -> Option<(&mut T, &mut T)> { 23 | if first == second || first >= slice.len() || second >= slice.len() { 24 | return None; 25 | } 26 | 27 | Some({ 28 | if first < second { 29 | let (head, tail) = slice.split_at_mut(first + 1); 30 | (&mut head[first], &mut tail[second - first - 1]) 31 | } else { 32 | let (head, tail) = slice.split_at_mut(second + 1); 33 | (&mut tail[first - second - 1], &mut head[second]) 34 | } 35 | }) 36 | } 37 | 38 | #[derive(Debug)] 39 | /// Stores all archetypes. 40 | pub struct ArchetypeRegistry { 41 | // TODO: Currently not a great approach, should become a graph 42 | sorted_mappings: [Vec; MAX_COMPONENTS_PER_ENTITY], 43 | archetypes: Vec, 44 | } 45 | 46 | impl Default for ArchetypeRegistry { 47 | fn default() -> Self { 48 | Self { 49 | sorted_mappings: [ 50 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 51 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 52 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 53 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 54 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 55 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 56 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 57 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 58 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 59 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 60 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 61 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 62 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 63 | Vec::with_capacity(DEFAULT_VECTOR_CAPACITY), 64 | ], 65 | archetypes: Vec::with_capacity(128), 66 | } 67 | } 68 | } 69 | 70 | impl ArchetypeRegistry { 71 | #[allow(dead_code)] 72 | pub fn find_archetype(&self, archetype_descriptor: &ArchetypeDescriptor) -> Option<&Archetype> { 73 | let len = archetype_descriptor.len() as usize; 74 | if len > MAX_COMPONENTS_PER_ENTITY || !archetype_descriptor.is_valid() { 75 | return None; 76 | } 77 | match self.sorted_mappings[len - 1] 78 | .binary_search_by_key(&archetype_descriptor.archetype_id(), |e| e.id) 79 | { 80 | Ok(found_index) => Some( 81 | &self.archetypes 82 | [self.sorted_mappings[len - 1][found_index].archetype_index as usize], 83 | ), 84 | Err(_) => None, 85 | } 86 | } 87 | 88 | #[allow(dead_code)] 89 | pub fn find_archetype_mut( 90 | &mut self, 91 | archetype_descriptor: &ArchetypeDescriptor, 92 | ) -> Option<&mut Archetype> { 93 | let len = archetype_descriptor.len() as usize; 94 | if len > MAX_COMPONENTS_PER_ENTITY || !archetype_descriptor.is_valid() { 95 | return None; 96 | } 97 | match self.sorted_mappings[len - 1] 98 | .binary_search_by_key(&archetype_descriptor.archetype_id(), |e| e.id) 99 | { 100 | Ok(found_index) => Some( 101 | &mut self.archetypes 102 | [self.sorted_mappings[len - 1][found_index].archetype_index as usize], 103 | ), 104 | Err(_) => None, 105 | } 106 | } 107 | 108 | /// Returns mutable reference to source archetype and finds or creates a new archetype by adding 109 | /// the given component type as defined by component descriptor. 110 | pub fn find_or_create_archetype_adding_component( 111 | &mut self, 112 | source_archetype_index: u16, 113 | component_descriptor: &ComponentDescriptor, 114 | ) -> Option<(&mut Archetype, u16, &mut Archetype)> { 115 | // Range check 116 | if source_archetype_index as usize > self.archetypes.len() { 117 | return None; 118 | } 119 | // create new archetype 120 | let new_archetype_descriptor = self.archetypes[source_archetype_index as usize] 121 | .descriptor() 122 | .add_component(component_descriptor)?; 123 | 124 | let (destination_archetype_index, _) = 125 | self.find_or_create_archetype(&new_archetype_descriptor)?; 126 | 127 | let (source, destination) = disjoint_mut( 128 | &mut self.archetypes, 129 | source_archetype_index as usize, 130 | destination_archetype_index as usize, 131 | )?; 132 | 133 | Some((source, destination_archetype_index, destination)) 134 | } 135 | 136 | /// Returns mutable reference to source archetype and finds or creates a new archetype by removing 137 | /// the given component type as defined by component descriptor. 138 | pub fn find_or_create_archetype_removing_component( 139 | &mut self, 140 | source_archetype_index: u16, 141 | component_descriptor: &ComponentDescriptor, 142 | ) -> Option<(&mut Archetype, u16, &mut Archetype)> { 143 | // Range check 144 | if source_archetype_index as usize > self.archetypes.len() { 145 | return None; 146 | } 147 | 148 | // create new archetype 149 | let new_archetype_descriptor = self.archetypes[source_archetype_index as usize] 150 | .descriptor() 151 | .remove_component(component_descriptor.component_type_id())?; 152 | 153 | let (destination_archetype_index, _) = 154 | self.find_or_create_archetype(&new_archetype_descriptor)?; 155 | 156 | let (source, destination) = disjoint_mut( 157 | &mut self.archetypes, 158 | source_archetype_index as usize, 159 | destination_archetype_index as usize, 160 | )?; 161 | Some((source, destination_archetype_index, destination)) 162 | } 163 | 164 | pub fn find_or_create_archetype( 165 | &mut self, 166 | archetype_descriptor: &ArchetypeDescriptor, 167 | ) -> Option<(u16, &mut Archetype)> { 168 | let len = archetype_descriptor.len() as usize; 169 | if len > MAX_COMPONENTS_PER_ENTITY || !archetype_descriptor.is_valid() { 170 | return None; 171 | } 172 | return match self.sorted_mappings[len - 1] 173 | .binary_search_by_key(&archetype_descriptor.archetype_id(), |e| e.id) 174 | { 175 | Ok(found_index) => Some(( 176 | self.sorted_mappings[len - 1][found_index].archetype_index, 177 | &mut self.archetypes 178 | [self.sorted_mappings[len - 1][found_index].archetype_index as usize], 179 | )), 180 | Err(insertion_index) => { 181 | if self.archetypes.len() >= MAX_ARCHETYPE_COUNT { 182 | return None; 183 | } 184 | 185 | let archetype = Archetype::with_capacity( 186 | archetype_descriptor, 187 | DEFAULT_ARCHETYPE_ALLOCATION_SIZE as u32, 188 | ); 189 | let key = SortedArchetypeKey { 190 | id: archetype_descriptor.archetype_id(), 191 | archetype_index: self.archetypes.len() as u16, 192 | }; 193 | self.archetypes.push(archetype); 194 | self.sorted_mappings[len - 1].insert(insertion_index, key); 195 | Some(( 196 | self.archetypes.len() as u16 - 1, 197 | self.archetypes.last_mut().unwrap(), 198 | )) 199 | } 200 | }; 201 | } 202 | 203 | /// Returns an archetype reference for the given index. 204 | /// # Safety 205 | /// Index must not be out of bounds. 206 | pub unsafe fn get_unchecked(&self, index: u16) -> &Archetype { 207 | self.archetypes.get_unchecked(index as usize) 208 | } 209 | 210 | /// Returns a mutable archetype reference for the given index. 211 | /// # Safety 212 | /// Index must not be out of bounds. 213 | pub unsafe fn get_unchecked_mut(&mut self, index: u16) -> &mut Archetype { 214 | self.archetypes.get_unchecked_mut(index as usize) 215 | } 216 | 217 | pub fn iter_components_matching<'a, G: ComponentGroup>( 218 | &'a self, 219 | ) -> impl Iterator::SliceRefTuple<'a>> { 220 | MatchingIter::<'a, G>::new(&self.sorted_mappings, &self.archetypes) 221 | } 222 | 223 | pub fn iter_components_matching_mut<'a, G: ComponentGroup>( 224 | &'a mut self, 225 | ) -> impl Iterator::SliceMutRefTuple<'a>> { 226 | MatchingIterMut::<'a, G>::new(&self.sorted_mappings, &mut self.archetypes) 227 | } 228 | 229 | pub fn iter_entity_components_matching<'a, G: ComponentGroup>( 230 | &'a self, 231 | ) -> impl Iterator::SliceRefTuple<'a>)> { 232 | EntityMatchingIter::<'a, G>::new(&self.sorted_mappings, &self.archetypes) 233 | } 234 | 235 | pub fn iter_entity_components_matching_mut<'a, G: ComponentGroup>( 236 | &'a mut self, 237 | ) -> impl Iterator::SliceMutRefTuple<'a>)> { 238 | EntityMatchingIterMut::<'a, G>::new(&self.sorted_mappings, &mut self.archetypes) 239 | } 240 | 241 | pub fn iter_filtered_components_matching< 242 | 'a, 243 | G: ComponentGroup, 244 | F: Fn(&ArchetypeDescriptor) -> bool, 245 | >( 246 | &'a self, 247 | filter_closure: F, 248 | ) -> impl Iterator::SliceRefTuple<'a>> { 249 | FilterMatchingIter::<'a, G, F>::new(&self.sorted_mappings, &self.archetypes, filter_closure) 250 | } 251 | 252 | pub fn iter_filtered_components_matching_mut< 253 | 'a, 254 | G: ComponentGroup, 255 | F: Fn(&ArchetypeDescriptor) -> bool, 256 | >( 257 | &'a mut self, 258 | filter_closure: F, 259 | ) -> impl Iterator::SliceMutRefTuple<'a>> { 260 | FilterMatchingIterMut::<'a, G, F>::new( 261 | &self.sorted_mappings, 262 | &mut self.archetypes, 263 | filter_closure, 264 | ) 265 | } 266 | 267 | pub fn iter_filtered_entity_components_matching< 268 | 'a, 269 | G: ComponentGroup, 270 | F: Fn(&ArchetypeDescriptor) -> bool, 271 | >( 272 | &'a self, 273 | filter_closure: F, 274 | ) -> impl Iterator::SliceRefTuple<'a>)> { 275 | FilterEntityMatchingIter::<'a, G, F>::new( 276 | &self.sorted_mappings, 277 | &self.archetypes, 278 | filter_closure, 279 | ) 280 | } 281 | 282 | pub fn iter_filtered_entity_components_matching_mut< 283 | 'a, 284 | G: ComponentGroup, 285 | F: Fn(&ArchetypeDescriptor) -> bool, 286 | >( 287 | &'a mut self, 288 | filter_closure: F, 289 | ) -> impl Iterator::SliceMutRefTuple<'a>)> { 290 | FilterEntityMatchingIterMut::<'a, G, F>::new( 291 | &self.sorted_mappings, 292 | &mut self.archetypes, 293 | filter_closure, 294 | ) 295 | } 296 | } 297 | 298 | impl Index for ArchetypeRegistry { 299 | type Output = Archetype; 300 | 301 | fn index(&self, index: u16) -> &Self::Output { 302 | &self.archetypes[index as usize] 303 | } 304 | } 305 | 306 | impl IndexMut for ArchetypeRegistry { 307 | fn index_mut(&mut self, index: u16) -> &mut Self::Output { 308 | &mut self.archetypes[index as usize] 309 | } 310 | } 311 | -------------------------------------------------------------------------------- /src/archetype_registry/sorted_archetype_key.rs: -------------------------------------------------------------------------------- 1 | use crate::ArchetypeId; 2 | 3 | #[derive(Debug, PartialEq, Eq, Clone, Copy)] 4 | pub(in crate::archetype_registry) struct SortedArchetypeKey { 5 | pub(crate) id: ArchetypeId, 6 | pub(in crate::archetype_registry) archetype_index: u16, 7 | } 8 | -------------------------------------------------------------------------------- /src/archetype_registry/tests.rs: -------------------------------------------------------------------------------- 1 | use crate::archetype_registry::ArchetypeRegistry; 2 | use crate::descriptors::component_group::ComponentGroup; 3 | use crate::entity_registry::*; 4 | use crate::test_components::*; 5 | 6 | #[test] 7 | fn test_archetype_registry() { 8 | let mut registry = ArchetypeRegistry::default(); 9 | let descriptor = <(A, B) as ComponentGroup>::DESCRIPTOR.archetype(); 10 | let (_, archetype) = registry.find_or_create_archetype(descriptor).unwrap(); 11 | (0..1).for_each(|e| unsafe { 12 | let _ = archetype.push_entity_unchecked( 13 | Entity::new_unchecked(e as u32, 0), 14 | (A { _data: e }, B { _data: 1048576 - e }), 15 | ); 16 | }); 17 | 18 | for v in registry.iter_components_matching::() { 19 | for (idx, elem) in v.iter().enumerate() { 20 | assert_eq!(elem._data, idx) 21 | } 22 | } 23 | for (a, b) in registry.iter_components_matching::<(A, B)>() { 24 | for (idx, elem) in a.iter().enumerate() { 25 | assert_eq!(elem._data, idx) 26 | } 27 | for (idx, elem) in b.iter().enumerate() { 28 | assert_eq!(elem._data, 1048576 - idx) 29 | } 30 | } 31 | 32 | for v in registry.iter_components_matching_mut::() { 33 | for (idx, elem) in v.iter().enumerate() { 34 | assert_eq!(elem._data, idx) 35 | } 36 | } 37 | for (a, b) in registry.iter_components_matching_mut::<(A, B)>() { 38 | for (idx, elem) in a.iter().enumerate() { 39 | assert_eq!(elem._data, idx) 40 | } 41 | for (idx, elem) in b.iter().enumerate() { 42 | assert_eq!(elem._data, 1048576 - idx) 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/constants.rs: -------------------------------------------------------------------------------- 1 | /// Used amount of bits in the entity handle for storing the index. 2 | /// Is defined to be 24 bits. Thus, yielding 2^24 - 1 = 16_777_215 different indices/entities. 3 | pub const ENTITY_HANDLE_BITS: u8 = 24; 4 | 5 | /// The maximum value that an entity can be. 6 | pub const MAX_ENTITY_HANDLE_VALUE: u32 = 16_777_215; 7 | 8 | /// Value indicating that an entity handle is invalid. 9 | /// The null entity is the entity having the handle value being this value, and version is max version value. 10 | /// This corresponds to 2^24. 11 | pub const INVALID_ENTITY_HANDLE_VALUE: u32 = 16_777_216; 12 | 13 | /// Used amount of bits in an entity for storing the version. 14 | /// Is defined to be 8 bits. Thus, yielding 2^8 = 256 different versions. 15 | pub const ENTITY_VERSION_BITS: u8 = 8; 16 | 17 | /// The maximum value that an entity version can be. 18 | pub const MAX_ENTITY_VERSION_VALUE: u8 = 255; 19 | 20 | /// The maximum number of components an entity is allowed to have. 21 | pub const MAX_COMPONENTS_PER_ENTITY: usize = 14; 22 | 23 | /// The maximum amount of unique archetypes that a registry can contain. 24 | pub const MAX_ARCHETYPE_COUNT: usize = (u16::MAX - 1) as usize; 25 | 26 | /// Valid archetype indices can never have this value. 27 | pub const INVALID_ARCHETYPE_INDEX: u16 = u16::MAX; 28 | 29 | /// Maximum amount of entities that can be stored for a given archetype. 30 | pub const MAX_ENTITIES_PER_ARCHETYPE: u32 = MAX_ENTITY_HANDLE_VALUE; 31 | 32 | /// The default amount of elements for which space is reserved if an entity is pushed into an empty archetype. 33 | pub const DEFAULT_ARCHETYPE_ALLOCATION_SIZE: usize = 128; 34 | -------------------------------------------------------------------------------- /src/descriptors/archetype_descriptor.rs: -------------------------------------------------------------------------------- 1 | use crate::descriptors::component_descriptor::ComponentDescriptor; 2 | use crate::fnv1a::fnv1a_hash_32; 3 | use crate::{constants::*, ArchetypeId, Component, ComponentTypeId}; 4 | 5 | /// Represents a combination of components. 6 | /// Each component type MUST be unique (i.e. no duplicate component types). 7 | /// Length must be larger than 0 and lower or equal to [`MAX_COMPONENTS_PER_ENTITY`]. 8 | /// Use the [`ArchetypeDescriptor::is_valid`] function to check for validity. 9 | /// Any use of an invalid archetype descriptor is considered UB. 10 | #[derive(Debug, Clone)] 11 | pub struct ArchetypeDescriptor { 12 | archetype_id: ArchetypeId, 13 | components: [ComponentDescriptor; MAX_COMPONENTS_PER_ENTITY], 14 | len: u8, 15 | } 16 | 17 | impl ArchetypeDescriptor { 18 | /// The invalid archetype descriptor. Has 0 components and an ArchetypeId of 0. 19 | pub const INVALID: ArchetypeDescriptor = ArchetypeDescriptor { 20 | archetype_id: ArchetypeId::INVALID, 21 | len: 0, 22 | components: [ComponentDescriptor::INVALID; MAX_COMPONENTS_PER_ENTITY], 23 | }; 24 | 25 | /// Returns true if it is a valid archetype. 26 | /// A valid archetype has a length larger than 0 and smaller than [`MAX_COMPONENTS_PER_ENTITY`]. 27 | /// It also contains no duplicate components. 28 | pub const fn is_valid(&self) -> bool { 29 | self.archetype_id.is_valid() 30 | } 31 | 32 | /// Creates a new archetype descriptor with the given id, length and components. 33 | pub const fn new( 34 | archetype_id: ArchetypeId, 35 | len: u8, 36 | components: [ComponentDescriptor; MAX_COMPONENTS_PER_ENTITY], 37 | ) -> Self { 38 | if len == 0 || !archetype_id.is_valid() { 39 | return Self::INVALID; 40 | } 41 | Self { 42 | archetype_id, 43 | len, 44 | components, 45 | } 46 | } 47 | 48 | /// Computes an archetype ID, returns [`ArchetypeId::INVALID`] if given an invalid combination of components. 49 | pub const fn compute_archetype_id(descriptors: &[ComponentDescriptor]) -> ArchetypeId { 50 | if descriptors.is_empty() { 51 | return ArchetypeId::INVALID; 52 | } 53 | if descriptors.len() == 1 { 54 | return ArchetypeId::from_u32(descriptors[0].component_type_id().into_u16() as u32); 55 | } 56 | 57 | let mut bytes = [0; MAX_COMPONENTS_PER_ENTITY * core::mem::size_of::()]; 58 | let mut i = 0; 59 | while i < descriptors.len() { 60 | let byte_block = ComponentTypeId::to_ne_bytes(descriptors[i].component_type_id()); 61 | let mut j = 0; 62 | while j < core::mem::size_of::() { 63 | bytes[i * core::mem::size_of::() + j] = byte_block[j]; 64 | j += 1; 65 | } 66 | i += 1; 67 | } 68 | ArchetypeId::from_u32(fnv1a_hash_32(&bytes, Some(bytes.len()))) 69 | } 70 | 71 | /// Returns whether the descriptor provided is contained in self. (i.e. subset inclusion) 72 | /// Do not provide an invalid descriptor to this! 73 | pub const fn contains_subset(&self, descriptor: &ArchetypeDescriptor) -> bool { 74 | if descriptor.len() > self.len() { 75 | return false; 76 | } 77 | let mut i = 0; 78 | 'outer_loop: while i < descriptor.len() { 79 | let mut j = 0; 80 | while j < self.len() { 81 | if self.components[j as usize].component_type_id.into_u16() 82 | == descriptor.components[i as usize] 83 | .component_type_id 84 | .into_u16() 85 | { 86 | i += 1; 87 | continue 'outer_loop; 88 | } 89 | j += 1; 90 | } 91 | return false; 92 | } 93 | true 94 | } 95 | 96 | /// Returns whether the descriptor provided is excluded from self. (i.e. subset exclusion) 97 | /// Do not provide an invalid descriptor to this! 98 | pub const fn excludes_subset(&self, descriptor: &ArchetypeDescriptor) -> bool { 99 | let mut i = 0; 100 | while i < descriptor.len() { 101 | let mut j = 0; 102 | while j < self.len() { 103 | if self.components[j as usize].component_type_id.into_u16() 104 | == descriptor.components[i as usize] 105 | .component_type_id 106 | .into_u16() 107 | { 108 | return false; 109 | } 110 | j += 1; 111 | } 112 | i += 1; 113 | } 114 | true 115 | } 116 | 117 | /// Returns a new archetype with the given component type added to it. 118 | /// Returns none if the current archetype already contains the component type or it is full. 119 | #[allow(dead_code)] 120 | pub fn add_component_from(&self) -> Option { 121 | self.add_component(&C::DESCRIPTOR) 122 | } 123 | 124 | /// Returns a new archetype with the given component type added to it. 125 | /// Returns none if the current archetype already contains the component type or it is full. 126 | pub fn add_component( 127 | &self, 128 | component_descriptor: &ComponentDescriptor, 129 | ) -> Option { 130 | if self.len() as usize == MAX_COMPONENTS_PER_ENTITY { 131 | return None; // Archetype is full. 132 | } 133 | match self.components[0..self.len() as usize] 134 | .binary_search_by_key(&component_descriptor.component_type_id, |e| { 135 | e.component_type_id 136 | }) { 137 | Ok(_) => None, // Current archetype already contains given component. 138 | Err(insertion_index) => { 139 | let mut v = self.clone(); 140 | for i in insertion_index..self.len() as usize + 1 { 141 | v.components[i + 1] = self.components[i].clone(); 142 | } 143 | v.components[insertion_index] = component_descriptor.clone(); 144 | 145 | v.len += 1; 146 | v.archetype_id = 147 | ArchetypeDescriptor::compute_archetype_id(&v.components[0..v.len() as usize]); 148 | Some(v) 149 | } 150 | } 151 | } 152 | 153 | pub fn remove_component(&self, component: ComponentTypeId) -> Option { 154 | if self.len() as usize == 1 { 155 | return None; // Archetype cannot contain zero components. 156 | } 157 | match self.components[0..self.len() as usize] 158 | .binary_search_by_key(&component, |e| e.component_type_id) 159 | { 160 | Ok(found_index) => { 161 | let mut v = self.clone(); 162 | for i in found_index..self.len() as usize { 163 | v.components[i] = self.components[i + 1].clone(); 164 | } 165 | 166 | v.len -= 1; 167 | v.archetype_id = 168 | ArchetypeDescriptor::compute_archetype_id(&v.components[0..v.len() as usize]); 169 | Some(v) 170 | } 171 | Err(_) => None, 172 | } 173 | } 174 | 175 | /// Returns whether the archetype descriptor has a given component type. 176 | pub fn has_component(&self) -> bool { 177 | return self 178 | .components() 179 | .binary_search_by_key(&C::ID, |e| e.component_type_id) 180 | .is_ok(); 181 | } 182 | 183 | /// Get a the archetype descriptor's archetype id. 184 | pub const fn archetype_id(&self) -> ArchetypeId { 185 | self.archetype_id 186 | } 187 | 188 | /// Get the archetype descriptor's component count. 189 | pub const fn len(&self) -> u8 { 190 | self.len 191 | } 192 | 193 | /// Get a reference to the archetype descriptor's components. 194 | /// This version is const but unsafe, as length is NOT accounted for. 195 | /// Therefore any descriptor past the len is considered invalid or garbage data. 196 | /// # Safety 197 | /// Data outside of the valid component descriptor range must not be modified. 198 | pub const unsafe fn components_unchecked( 199 | &self, 200 | ) -> &[ComponentDescriptor; MAX_COMPONENTS_PER_ENTITY] { 201 | &self.components 202 | } 203 | 204 | /// Get a reference to the archetype descriptor's components. 205 | pub fn components(&self) -> &[ComponentDescriptor] { 206 | &self.components[0..self.len as usize] 207 | } 208 | } 209 | 210 | #[cfg(test)] 211 | mod tests { 212 | use crate::descriptors::archetype_descriptor::ArchetypeDescriptor; 213 | use crate::descriptors::component_group::ComponentGroup; 214 | use crate::test_components::*; 215 | use crate::Component; 216 | 217 | #[test] 218 | fn test_archetype_descriptor_add_remove() { 219 | let descriptor: &ArchetypeDescriptor = <(A, B) as ComponentGroup>::DESCRIPTOR.archetype(); 220 | assert!(descriptor.has_component::()); 221 | assert!(descriptor.has_component::()); 222 | let descriptor = descriptor 223 | .add_component(&::DESCRIPTOR) 224 | .unwrap(); 225 | assert!(descriptor.has_component::()); 226 | assert!(descriptor.has_component::()); 227 | assert!(descriptor.has_component::()); 228 | let descriptor = descriptor.remove_component(B::ID).unwrap(); 229 | assert!(!descriptor.has_component::()); 230 | assert!(descriptor.has_component::()); 231 | assert!(descriptor.has_component::()); 232 | assert_eq!(descriptor.len(), 2); 233 | } 234 | 235 | #[test] 236 | fn test_archetype_descriptor_contains() { 237 | assert_eq!( 238 | <(A, B) as ComponentGroup>::DESCRIPTOR 239 | .archetype() 240 | .contains_subset(::DESCRIPTOR.archetype()), 241 | true 242 | ); 243 | assert_eq!( 244 | <(A, B) as ComponentGroup>::DESCRIPTOR 245 | .archetype() 246 | .contains_subset(::DESCRIPTOR.archetype()), 247 | true 248 | ); 249 | assert_eq!( 250 | <(A, B) as ComponentGroup>::DESCRIPTOR 251 | .archetype() 252 | .contains_subset(::DESCRIPTOR.archetype()), 253 | false 254 | ); 255 | } 256 | 257 | #[test] 258 | fn test_archetype_descriptor_excludes() { 259 | assert_eq!( 260 | <(A, B) as ComponentGroup>::DESCRIPTOR 261 | .archetype() 262 | .excludes_subset(::DESCRIPTOR.archetype()), 263 | true 264 | ); 265 | assert_eq!( 266 | <(A, B) as ComponentGroup>::DESCRIPTOR 267 | .archetype() 268 | .excludes_subset(::DESCRIPTOR.archetype()), 269 | false 270 | ); 271 | assert_eq!( 272 | <(A, B) as ComponentGroup>::DESCRIPTOR 273 | .archetype() 274 | .contains_subset(::DESCRIPTOR.archetype()), 275 | true 276 | ); 277 | } 278 | } 279 | -------------------------------------------------------------------------------- /src/descriptors/archetype_id.rs: -------------------------------------------------------------------------------- 1 | /// Represents the unique subset of components as a comparable identifier. 2 | /// See [`ArchetypeDescriptor::compute_archetype_id`] for computing an instance of it. 3 | /// The invalid archetype id is defined to be 0. 4 | #[repr(transparent)] 5 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 6 | pub struct ArchetypeId(u32); 7 | 8 | impl From for ArchetypeId { 9 | fn from(v: u32) -> Self { 10 | Self(v) 11 | } 12 | } 13 | 14 | impl ArchetypeId { 15 | /// The invalid archetype id, defined to be zero. 16 | /// Any archetype with this id must not be used as valid archetype. 17 | pub const INVALID: ArchetypeId = ArchetypeId::from_u32(u32::MAX); 18 | /// Returns true if the archetype id is valid. 19 | pub const fn is_valid(&self) -> bool { 20 | self.0 != Self::INVALID.0 21 | } 22 | /// Construct an archetype id from a u32. 23 | pub const fn from_u32(v: u32) -> Self { 24 | ArchetypeId(v) 25 | } 26 | /// Construct a u32 from an archetype id. 27 | pub const fn into_u32(self) -> u32 { 28 | self.0 29 | } 30 | } 31 | 32 | impl ArchetypeId { 33 | /// Copies the value into an array of ne_bytes. (See [`u32::to_ne_bytes`]). 34 | pub const fn to_ne_bytes(self) -> [u8; 4] { 35 | self.0.to_ne_bytes() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/descriptors/component.rs: -------------------------------------------------------------------------------- 1 | use crate::descriptors::component_descriptor::*; 2 | use crate::descriptors::component_type_id::ComponentTypeId; 3 | use crate::{define_component_descriptor, fnv1a::fnv1a_hash_str_16_xor}; 4 | 5 | /// Implement this trait to use a type as a component in the ECS. 6 | /// Do not override the default implementations for [`Self::ID`] or [`Self::DESCRIPTOR`]. 7 | /// Only implement [`Self::NAME`]. 8 | /// # Safety: 9 | /// - size_of must not exceed u16::MAX. 10 | /// - align_of must not exceed u16::MAX. 11 | pub trait Component: Send + Sync + Sized + 'static { 12 | /// Human readable program unique name used for calculating a stable type identifier. 13 | const NAME: &'static str; 14 | /// Do not implement this manually. (Unless a hash collision occurs). 15 | const ID: ComponentTypeId = ComponentTypeId::from_u16(fnv1a_hash_str_16_xor(Self::NAME)); 16 | /// A descriptor defining the component type. 17 | const DESCRIPTOR: ComponentDescriptor = define_component_descriptor!(Self); 18 | } 19 | -------------------------------------------------------------------------------- /src/descriptors/component_descriptor.rs: -------------------------------------------------------------------------------- 1 | use core::mem::ManuallyDrop; 2 | 3 | use crate::descriptors::archetype_descriptor::ArchetypeDescriptor; 4 | use crate::descriptors::component_type_id::ComponentTypeId; 5 | use crate::Component; 6 | 7 | #[macro_export] 8 | macro_rules! define_component_descriptor { 9 | ($item:ident) => { 10 | ComponentDescriptor { 11 | component_type_id: $item::ID, 12 | size: core::mem::size_of::<$item>() as u16, 13 | align: core::mem::align_of::<$item>() as u16, 14 | fns: ComponentDescriptorFnPointers { 15 | drop_handler: ComponentDescriptor::drop_handler_wrapper::<$item>, 16 | }, 17 | } 18 | }; 19 | } 20 | 21 | #[macro_export] 22 | macro_rules! copy_component_descriptor_from_to { 23 | ($source:expr, $destination:expr) => { 24 | $destination.component_type_id = $source.component_type_id; 25 | $destination.size = $source.size; 26 | $destination.align = $source.align; 27 | $destination.fns = $source.fns; 28 | }; 29 | } 30 | 31 | /// Groups special function pointers used for memory operations on component instances. 32 | #[derive(Debug, Clone, Copy, PartialEq, Eq)] 33 | pub struct ComponentDescriptorFnPointers { 34 | pub drop_handler: unsafe fn(ptr: *mut u8, len: usize), 35 | } 36 | 37 | /// Describes a specific component type. 38 | /// # Safety: 39 | /// - [`size`] must not exceed [`u16::MAX`]. 40 | /// - [`align`] must not exceed [`u16::MAX`]. 41 | #[derive(Debug, Clone, PartialEq)] 42 | pub struct ComponentDescriptor { 43 | pub component_type_id: ComponentTypeId, 44 | pub size: u16, 45 | pub align: u16, 46 | pub fns: ComponentDescriptorFnPointers, 47 | } 48 | 49 | impl Into for &ComponentDescriptor { 50 | fn into(self) -> ArchetypeDescriptor { 51 | ArchetypeDescriptor::new( 52 | self.component_type_id.into(), 53 | 1, 54 | [ 55 | self.clone(), 56 | ComponentDescriptor::INVALID, 57 | ComponentDescriptor::INVALID, 58 | ComponentDescriptor::INVALID, 59 | ComponentDescriptor::INVALID, 60 | ComponentDescriptor::INVALID, 61 | ComponentDescriptor::INVALID, 62 | ComponentDescriptor::INVALID, 63 | ComponentDescriptor::INVALID, 64 | ComponentDescriptor::INVALID, 65 | ComponentDescriptor::INVALID, 66 | ComponentDescriptor::INVALID, 67 | ComponentDescriptor::INVALID, 68 | ComponentDescriptor::INVALID, 69 | ], 70 | ) 71 | } 72 | } 73 | 74 | impl Into for ComponentDescriptor { 75 | fn into(self) -> ArchetypeDescriptor { 76 | ArchetypeDescriptor::new( 77 | self.component_type_id.into(), 78 | 1, 79 | [ 80 | self, 81 | ComponentDescriptor::INVALID, 82 | ComponentDescriptor::INVALID, 83 | ComponentDescriptor::INVALID, 84 | ComponentDescriptor::INVALID, 85 | ComponentDescriptor::INVALID, 86 | ComponentDescriptor::INVALID, 87 | ComponentDescriptor::INVALID, 88 | ComponentDescriptor::INVALID, 89 | ComponentDescriptor::INVALID, 90 | ComponentDescriptor::INVALID, 91 | ComponentDescriptor::INVALID, 92 | ComponentDescriptor::INVALID, 93 | ComponentDescriptor::INVALID, 94 | ], 95 | ) 96 | } 97 | } 98 | 99 | impl ComponentDescriptor { 100 | /// Represents an invalid component descriptor. 101 | /// This descriptor must not be used as a valid descriptor. 102 | pub const INVALID: Self = { 103 | unsafe fn _dummy_drop_(_ptr: *mut u8, _len: usize) {} 104 | ComponentDescriptor { 105 | component_type_id: ComponentTypeId::INVALID, 106 | size: 0, 107 | align: 0, 108 | fns: ComponentDescriptorFnPointers { 109 | drop_handler: _dummy_drop_, 110 | }, 111 | } 112 | }; 113 | 114 | /// Creates a new component descriptor from the provided arguments. 115 | /// Returns [`ComponentDescriptor::INVALID`] if a valid descriptor cannot be constructed. 116 | pub fn new( 117 | component_type_id: ComponentTypeId, 118 | size: u16, 119 | align: u16, 120 | drop_handler: unsafe fn(ptr: *mut u8, len: usize), 121 | ) -> Self { 122 | if !component_type_id.is_valid() { 123 | return Self::INVALID; 124 | } 125 | 126 | Self { 127 | component_type_id, 128 | size, 129 | align, 130 | fns: ComponentDescriptorFnPointers { drop_handler }, 131 | } 132 | } 133 | 134 | /// Do not use this manually. It wraps a type erased drop handler. 135 | /// # Safety 136 | /// The pointer must be properly aligned to an instance of C and the len must be valid for the slice. 137 | pub unsafe fn drop_handler_wrapper(ptr: *mut u8, len: usize) { 138 | let s = core::slice::from_raw_parts_mut(ptr as *mut ManuallyDrop, len); 139 | s.iter_mut().for_each(|e| ManuallyDrop::drop(e)) 140 | } 141 | 142 | /// Get a the component descriptor's component type id. 143 | pub const fn component_type_id(&self) -> ComponentTypeId { 144 | self.component_type_id 145 | } 146 | 147 | /// Get a the component descriptor's size. 148 | pub const fn size(&self) -> u16 { 149 | self.size 150 | } 151 | 152 | /// Get a the component descriptor's align. 153 | pub const fn align(&self) -> u16 { 154 | self.align 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /src/descriptors/component_group.rs: -------------------------------------------------------------------------------- 1 | use crate::descriptors::component_descriptor::{ 2 | ComponentDescriptor, ComponentDescriptorFnPointers, 3 | }; 4 | use crate::{define_component_descriptor, Component, MAX_COMPONENTS_PER_ENTITY}; 5 | 6 | use crate::descriptors::component_group_descriptor::ComponentGroupDescriptor; 7 | use private::SealedComponentGroup; 8 | 9 | #[macro_export] 10 | macro_rules! expr { 11 | ($x:expr) => { 12 | $x 13 | }; 14 | } 15 | 16 | #[macro_export] 17 | macro_rules! tuple_index { 18 | ($tuple:expr, $idx:tt) => { 19 | expr!($tuple.$idx) 20 | }; 21 | } 22 | 23 | /// Represents a group of components. Used for specifying which component types should be matched in query's. 24 | pub trait ComponentGroup: SealedComponentGroup + Sized + 'static { 25 | type RefTuple<'c>: 'c 26 | where 27 | Self: 'c; 28 | type MutRefTuple<'c>: 'c 29 | where 30 | Self: 'c; 31 | type SliceRefTuple<'c>: 'c 32 | where 33 | Self: 'c; 34 | type SliceMutRefTuple<'c>: 'c 35 | where 36 | Self: 'c; 37 | 38 | /// The descriptor which exactly specifies all components of the component group. 39 | const DESCRIPTOR: ComponentGroupDescriptor; 40 | 41 | /// Returns the sorted pointers given a reference to self. 42 | unsafe fn as_sorted_pointers(&mut self, ptrs: &mut [*mut u8; MAX_COMPONENTS_PER_ENTITY]); 43 | 44 | /// Returns an instance of self, read from the sorted pointers. 45 | unsafe fn read_from_sorted_pointers(pointers: &[*mut u8; MAX_COMPONENTS_PER_ENTITY]) -> Self; 46 | 47 | /// Returns a reference tuple of component types given an array of sorted pointers. 48 | unsafe fn pointers_as_ref_tuple<'a, 'b>( 49 | sorted_pointers: &'a [*mut u8; MAX_COMPONENTS_PER_ENTITY], 50 | ) -> Self::RefTuple<'b>; 51 | 52 | /// Returns a mutable reference tuple of component types given an array of sorted pointers. 53 | unsafe fn pointers_as_mut_ref_tuple<'a, 'b>( 54 | sorted_pointers: &'a [*mut u8; MAX_COMPONENTS_PER_ENTITY], 55 | ) -> Self::MutRefTuple<'b>; 56 | 57 | /// Returns a tuple of slices extracted from the given pointers. 58 | /// # Safety: 59 | /// - The pointers must be sorted. 60 | unsafe fn slice_unchecked<'a, 'b>( 61 | sorted_pointers: &'a [*mut u8; MAX_COMPONENTS_PER_ENTITY], 62 | len: usize, 63 | ) -> Self::SliceRefTuple<'b>; 64 | 65 | /// Returns a tuple of mutable slices extracted from the given pointers. 66 | /// # Safety: 67 | /// - The pointers must be sorted. 68 | unsafe fn slice_unchecked_mut<'a, 'b>( 69 | sorted_pointers: &'a [*mut u8; MAX_COMPONENTS_PER_ENTITY], 70 | len: usize, 71 | ) -> Self::SliceMutRefTuple<'b>; 72 | 73 | /// Returns an tuple of empty slices. 74 | fn empty_slice<'a>() -> Self::SliceRefTuple<'a>; 75 | 76 | /// Returns an tuple of empty mutable slices. 77 | fn empty_slice_mut<'a>() -> Self::SliceMutRefTuple<'a>; 78 | } 79 | 80 | impl ComponentGroup for T { 81 | type RefTuple<'c> = &'c T; 82 | type MutRefTuple<'c> = &'c mut T; 83 | 84 | type SliceRefTuple<'c> = &'c [T]; 85 | type SliceMutRefTuple<'c> = &'c mut [T]; 86 | 87 | const DESCRIPTOR: ComponentGroupDescriptor = 88 | ComponentGroupDescriptor::new(&[define_component_descriptor!(T)]); 89 | 90 | unsafe fn as_sorted_pointers(&mut self, ptrs: &mut [*mut u8; MAX_COMPONENTS_PER_ENTITY]) { 91 | ptrs[0] = self as *mut T as *mut u8; 92 | } 93 | 94 | unsafe fn read_from_sorted_pointers(pointers: &[*mut u8; MAX_COMPONENTS_PER_ENTITY]) -> Self { 95 | core::ptr::read(pointers[0] as *mut T) 96 | } 97 | 98 | unsafe fn pointers_as_ref_tuple<'a, 'b>( 99 | sorted_pointers: &'a [*mut u8; MAX_COMPONENTS_PER_ENTITY], 100 | ) -> Self::RefTuple<'b> { 101 | &*(sorted_pointers[0] as *mut T) 102 | } 103 | 104 | unsafe fn pointers_as_mut_ref_tuple<'a, 'b>( 105 | sorted_pointers: &'a [*mut u8; MAX_COMPONENTS_PER_ENTITY], 106 | ) -> Self::MutRefTuple<'b> { 107 | &mut *(sorted_pointers[0] as *mut T) 108 | } 109 | 110 | unsafe fn slice_unchecked<'a, 'b>( 111 | sorted_pointers: &'a [*mut u8; MAX_COMPONENTS_PER_ENTITY], 112 | len: usize, 113 | ) -> Self::SliceRefTuple<'b> { 114 | core::slice::from_raw_parts(sorted_pointers[0] as *const T, len) 115 | } 116 | 117 | unsafe fn slice_unchecked_mut<'a, 'b>( 118 | sorted_pointers: &'a [*mut u8; MAX_COMPONENTS_PER_ENTITY], 119 | len: usize, 120 | ) -> Self::SliceMutRefTuple<'b> { 121 | core::slice::from_raw_parts_mut(sorted_pointers[0] as *mut T, len) 122 | } 123 | 124 | fn empty_slice<'a>() -> Self::SliceRefTuple<'a> { 125 | &[] 126 | } 127 | 128 | fn empty_slice_mut<'a>() -> Self::SliceMutRefTuple<'a> { 129 | &mut [] 130 | } 131 | } 132 | 133 | macro_rules! impl_component_tuple { 134 | ($len:expr, $(($elem:ident, $elem_idx:tt)), *) => { 135 | impl<$($elem),*> ComponentGroup for ($($elem), *) 136 | where $( $elem : Component + SealedComponentGroup ),*, Self : SealedComponentGroup 137 | { 138 | type RefTuple<'s> = ($(&'s $elem),*); 139 | type MutRefTuple<'s> = ($(&'s mut $elem),*); 140 | 141 | type SliceRefTuple<'s> = ($(&'s [$elem]),*); 142 | type SliceMutRefTuple<'s> = ($(&'s mut [$elem]),*); 143 | 144 | fn empty_slice<'a>() -> Self::SliceRefTuple<'a> { 145 | ($(&[] as &[$elem]), *) 146 | } 147 | 148 | fn empty_slice_mut<'a>() -> Self::SliceMutRefTuple<'a> { 149 | ($(&mut [] as &mut [$elem]), *) 150 | } 151 | 152 | const DESCRIPTOR: ComponentGroupDescriptor = 153 | ComponentGroupDescriptor::new(&[$(define_component_descriptor!($elem)), *]); 154 | 155 | unsafe fn as_sorted_pointers(&mut self, ptrs: &mut [*mut u8; MAX_COMPONENTS_PER_ENTITY]) { 156 | $( 157 | ptrs[Self::DESCRIPTOR.unsorted_to_sorted($elem_idx) as usize] = &mut tuple_index!(self, $elem_idx) as *mut $elem as *mut u8; 158 | )* 159 | } 160 | 161 | unsafe fn read_from_sorted_pointers(pointers: &[*mut u8; MAX_COMPONENTS_PER_ENTITY]) -> Self { 162 | ($( 163 | core::ptr::read(pointers[Self::DESCRIPTOR.unsorted_to_sorted($elem_idx) as usize] as *mut $elem) 164 | ),*) 165 | } 166 | 167 | unsafe fn pointers_as_ref_tuple<'a, 'b>( 168 | sorted_pointers: &'a [*mut u8; MAX_COMPONENTS_PER_ENTITY], 169 | ) -> Self::RefTuple<'b> { 170 | ($( 171 | &*((sorted_pointers[Self::DESCRIPTOR.unsorted_to_sorted($elem_idx) as usize]) as *mut $elem), 172 | )*) 173 | } 174 | 175 | unsafe fn pointers_as_mut_ref_tuple<'a, 'b>( 176 | sorted_pointers: &'a [*mut u8; MAX_COMPONENTS_PER_ENTITY], 177 | ) -> Self::MutRefTuple<'b> { 178 | ($( 179 | &mut *((sorted_pointers[Self::DESCRIPTOR.unsorted_to_sorted($elem_idx) as usize]) as *mut $elem), 180 | )*) 181 | } 182 | 183 | unsafe fn slice_unchecked<'a, 'b>( 184 | sorted_pointers: &'a [*mut u8; MAX_COMPONENTS_PER_ENTITY], 185 | len: usize, 186 | ) -> Self::SliceRefTuple<'b> { 187 | ($( 188 | core::slice::from_raw_parts(sorted_pointers[Self::DESCRIPTOR.unsorted_to_sorted($elem_idx) as usize] as *const $elem, len), 189 | )*) 190 | } 191 | 192 | unsafe fn slice_unchecked_mut<'a, 'b>( 193 | sorted_pointers: &'a [*mut u8; MAX_COMPONENTS_PER_ENTITY], 194 | len: usize, 195 | ) -> Self::SliceMutRefTuple<'b> { 196 | ($( 197 | core::slice::from_raw_parts_mut(sorted_pointers[Self::DESCRIPTOR.unsorted_to_sorted($elem_idx) as usize] as *mut $elem, len), 198 | )*) 199 | } 200 | } 201 | } 202 | } 203 | 204 | #[cfg(test)] 205 | mod test { 206 | extern crate std; 207 | use super::*; 208 | use crate::test_components::*; 209 | 210 | #[test] 211 | fn test_component_group_as_sorted_pointers() { 212 | unsafe { 213 | let mut group = (A::default(), B::default(), C::default()); 214 | 215 | let mut ptrs = [core::ptr::null_mut(); MAX_COMPONENTS_PER_ENTITY]; 216 | ComponentGroup::as_sorted_pointers(&mut group, &mut ptrs); 217 | assert_eq!(ptrs[0], &mut group.0 as *mut A as *mut u8); 218 | assert_eq!(ptrs[1], &mut group.1 as *mut B as *mut u8); 219 | assert_eq!(ptrs[2], &mut group.2 as *mut C as *mut u8); 220 | 221 | let mut group = (B::default(), C::default(), A::default()); 222 | let mut ptrs = [core::ptr::null_mut(); MAX_COMPONENTS_PER_ENTITY]; 223 | ComponentGroup::as_sorted_pointers(&mut group, &mut ptrs); 224 | assert_eq!(ptrs[0], &mut group.2 as *mut A as *mut u8); 225 | assert_eq!(ptrs[1], &mut group.0 as *mut B as *mut u8); 226 | assert_eq!(ptrs[2], &mut group.1 as *mut C as *mut u8); 227 | } 228 | } 229 | 230 | #[test] 231 | fn test_component_group_sorted_pointers_as_ref_tuples() { 232 | unsafe { 233 | let mut group = (A::default(), B::default(), C::default()); 234 | 235 | let mut ptrs = [core::ptr::null_mut(); MAX_COMPONENTS_PER_ENTITY]; 236 | ComponentGroup::as_sorted_pointers(&mut group, &mut ptrs); 237 | 238 | let result = <(A, B, C) as ComponentGroup>::pointers_as_ref_tuple(&ptrs); 239 | assert_eq!(result.0 as *const A as *mut u8, ptrs[0]); 240 | assert_eq!(result.1 as *const B as *mut u8, ptrs[1]); 241 | assert_eq!(result.2 as *const C as *mut u8, ptrs[2]); 242 | 243 | let result = <(A, B, C) as ComponentGroup>::pointers_as_mut_ref_tuple(&ptrs); 244 | assert_eq!(result.0 as *mut A as *mut u8, ptrs[0]); 245 | assert_eq!(result.1 as *mut B as *mut u8, ptrs[1]); 246 | assert_eq!(result.2 as *mut C as *mut u8, ptrs[2]); 247 | 248 | let result = <(B, C, A) as ComponentGroup>::pointers_as_ref_tuple(&ptrs); 249 | assert_eq!(result.0 as *const B as *mut u8, ptrs[1]); 250 | assert_eq!(result.1 as *const C as *mut u8, ptrs[2]); 251 | assert_eq!(result.2 as *const A as *mut u8, ptrs[0]); 252 | let result = <(C, A, B) as ComponentGroup>::pointers_as_mut_ref_tuple(&ptrs); 253 | assert_eq!(result.0 as *mut C as *mut u8, ptrs[2]); 254 | assert_eq!(result.1 as *mut A as *mut u8, ptrs[0]); 255 | assert_eq!(result.2 as *mut B as *mut u8, ptrs[1]); 256 | } 257 | } 258 | 259 | #[test] 260 | fn test_component_group_sorted_pointers_to_tuples() { 261 | unsafe { 262 | let mut group = (A::default(), B::default(), C::default()); 263 | 264 | let mut ptrs = [core::ptr::null_mut(); MAX_COMPONENTS_PER_ENTITY]; 265 | ComponentGroup::as_sorted_pointers(&mut group, &mut ptrs); 266 | 267 | let result = <(A, B, C) as ComponentGroup>::read_from_sorted_pointers(&ptrs); 268 | assert_eq!(result.0, group.0); 269 | assert_eq!(result.1, group.1); 270 | assert_eq!(result.2, group.2); 271 | 272 | let result = <(C, A, B) as ComponentGroup>::read_from_sorted_pointers(&ptrs); 273 | assert_eq!(result.1, group.0); 274 | assert_eq!(result.2, group.1); 275 | assert_eq!(result.0, group.2); 276 | } 277 | } 278 | 279 | #[test] 280 | fn test_component_group_slices() { 281 | unsafe { 282 | let mut slice_a = [ 283 | A::default(), 284 | A::default(), 285 | A::default(), 286 | A::default(), 287 | A::default(), 288 | A::default(), 289 | A::default(), 290 | A::default(), 291 | A::default(), 292 | A::default(), 293 | A::default(), 294 | A::default(), 295 | A::default(), 296 | A::default(), 297 | A::default(), 298 | A::default(), 299 | ]; 300 | let mut slice_b = [ 301 | B::default(), 302 | B::default(), 303 | B::default(), 304 | B::default(), 305 | B::default(), 306 | B::default(), 307 | B::default(), 308 | B::default(), 309 | B::default(), 310 | B::default(), 311 | B::default(), 312 | B::default(), 313 | B::default(), 314 | B::default(), 315 | B::default(), 316 | B::default(), 317 | ]; 318 | let mut slice_c = [ 319 | C::default(), 320 | C::default(), 321 | C::default(), 322 | C::default(), 323 | C::default(), 324 | C::default(), 325 | C::default(), 326 | C::default(), 327 | C::default(), 328 | C::default(), 329 | C::default(), 330 | C::default(), 331 | C::default(), 332 | C::default(), 333 | C::default(), 334 | C::default(), 335 | ]; 336 | 337 | let mut pointers = [core::ptr::null_mut::(); MAX_COMPONENTS_PER_ENTITY]; 338 | pointers[0] = slice_a.as_mut_ptr() as *mut u8; 339 | pointers[1] = slice_b.as_mut_ptr() as *mut u8; 340 | pointers[2] = slice_c.as_mut_ptr() as *mut u8; 341 | 342 | let slices: (&[A], &[B], &[C]) = 343 | <(A, B, C) as ComponentGroup>::slice_unchecked(&pointers, slice_a.len()); 344 | assert_eq!(slices.0.as_ptr() as *mut u8, pointers[0]); 345 | assert_eq!(slices.1.as_ptr() as *mut u8, pointers[1]); 346 | assert_eq!(slices.2.as_ptr() as *mut u8, pointers[2]); 347 | 348 | let slices: (&[B], &[C], &[A]) = 349 | <(B, C, A) as ComponentGroup>::slice_unchecked(&pointers, slice_a.len()); 350 | assert_eq!(slices.0.as_ptr() as *mut u8, pointers[1]); 351 | assert_eq!(slices.1.as_ptr() as *mut u8, pointers[2]); 352 | assert_eq!(slices.2.as_ptr() as *mut u8, pointers[0]); 353 | } 354 | } 355 | } 356 | 357 | // impl_component_tuple!( 358 | // 16, 359 | // (T1, 0), 360 | // (T2, 1), 361 | // (T3, 2), 362 | // (T4, 3), 363 | // (T5, 4), 364 | // (T6, 5), 365 | // (T7, 6), 366 | // (T8, 7), 367 | // (T9, 8), 368 | // (T10, 9), 369 | // (T11, 10), 370 | // (T12, 11), 371 | // (T13, 12), 372 | // (T14, 13), 373 | // (T15, 14), 374 | // (T16, 15) 375 | // ); 376 | // 377 | // impl_component_tuple!( 378 | // 15, 379 | // (T1, 0), 380 | // (T2, 1), 381 | // (T3, 2), 382 | // (T4, 3), 383 | // (T5, 4), 384 | // (T6, 5), 385 | // (T7, 6), 386 | // (T8, 7), 387 | // (T9, 8), 388 | // (T10, 9), 389 | // (T11, 10), 390 | // (T12, 11), 391 | // (T13, 12), 392 | // (T14, 13), 393 | // (T15, 14) 394 | // ); 395 | 396 | impl_component_tuple!( 397 | 14, 398 | (T1, 0), 399 | (T2, 1), 400 | (T3, 2), 401 | (T4, 3), 402 | (T5, 4), 403 | (T6, 5), 404 | (T7, 6), 405 | (T8, 7), 406 | (T9, 8), 407 | (T10, 9), 408 | (T11, 10), 409 | (T12, 11), 410 | (T13, 12), 411 | (T14, 13) 412 | ); 413 | 414 | impl_component_tuple!( 415 | 13, 416 | (T1, 0), 417 | (T2, 1), 418 | (T3, 2), 419 | (T4, 3), 420 | (T5, 4), 421 | (T6, 5), 422 | (T7, 6), 423 | (T8, 7), 424 | (T9, 8), 425 | (T10, 9), 426 | (T11, 10), 427 | (T12, 11), 428 | (T13, 12) 429 | ); 430 | 431 | impl_component_tuple!( 432 | 12, 433 | (T1, 0), 434 | (T2, 1), 435 | (T3, 2), 436 | (T4, 3), 437 | (T5, 4), 438 | (T6, 5), 439 | (T7, 6), 440 | (T8, 7), 441 | (T9, 8), 442 | (T10, 9), 443 | (T11, 10), 444 | (T12, 11) 445 | ); 446 | 447 | impl_component_tuple!( 448 | 11, 449 | (T1, 0), 450 | (T2, 1), 451 | (T3, 2), 452 | (T4, 3), 453 | (T5, 4), 454 | (T6, 5), 455 | (T7, 6), 456 | (T8, 7), 457 | (T9, 8), 458 | (T10, 9), 459 | (T11, 10) 460 | ); 461 | 462 | impl_component_tuple!( 463 | 10, 464 | (T1, 0), 465 | (T2, 1), 466 | (T3, 2), 467 | (T4, 3), 468 | (T5, 4), 469 | (T6, 5), 470 | (T7, 6), 471 | (T8, 7), 472 | (T9, 8), 473 | (T10, 9) 474 | ); 475 | 476 | impl_component_tuple!( 477 | 9, 478 | (T1, 0), 479 | (T2, 1), 480 | (T3, 2), 481 | (T4, 3), 482 | (T5, 4), 483 | (T6, 5), 484 | (T7, 6), 485 | (T8, 7), 486 | (T9, 8) 487 | ); 488 | 489 | impl_component_tuple!( 490 | 8, 491 | (T1, 0), 492 | (T2, 1), 493 | (T3, 2), 494 | (T4, 3), 495 | (T5, 4), 496 | (T6, 5), 497 | (T7, 6), 498 | (T8, 7) 499 | ); 500 | impl_component_tuple!( 501 | 7, 502 | (T1, 0), 503 | (T2, 1), 504 | (T3, 2), 505 | (T4, 3), 506 | (T5, 4), 507 | (T6, 5), 508 | (T7, 6) 509 | ); 510 | 511 | impl_component_tuple!(6, (T1, 0), (T2, 1), (T3, 2), (T4, 3), (T5, 4), (T6, 5)); 512 | impl_component_tuple!(5, (T1, 0), (T2, 1), (T3, 2), (T4, 3), (T5, 4)); 513 | impl_component_tuple!(4, (T1, 0), (T2, 1), (T3, 2), (T4, 3)); 514 | impl_component_tuple!(3, (T1, 0), (T2, 1), (T3, 2)); 515 | impl_component_tuple!(2, (T1, 0), (T2, 1)); 516 | 517 | mod private { 518 | use crate::Component; 519 | 520 | pub trait SealedComponentGroup {} 521 | 522 | impl SealedComponentGroup for T where T: Component {} 523 | 524 | macro_rules! impl_sealed_component_tuples { 525 | ($($ty:ident)*) => {}; //base case 526 | ($head:ident, $($tail:ident),*) => { 527 | impl<$($tail),*, $head> SealedComponentGroup for impl_sealed_component_tuples!([$($tail)*] $head) 528 | where $head : Component, $( $tail : Component ),* {} 529 | 530 | impl_sealed_component_tuples!($($tail),*); 531 | }; 532 | ([] $($ty:ident)*) => { 533 | ($($ty), *) 534 | }; 535 | ([$first:ident $($tail:ident)*] $($ty:ident)*) => { 536 | impl_sealed_component_tuples!([$($tail)*] $first $($ty)*) 537 | }; 538 | } 539 | 540 | impl_sealed_component_tuples!( 541 | T16, T15, T14, T13, T12, T11, T10, T9, T8, T7, T6, T5, T4, T3, T2, T1 542 | ); 543 | } 544 | 545 | #[cfg(test)] 546 | mod tests { 547 | use super::*; 548 | use crate::Component; 549 | struct Position; 550 | struct Rotation; 551 | struct Velocity; 552 | impl Component for Position { 553 | const NAME: &'static str = "Position"; 554 | } 555 | impl Component for Rotation { 556 | const NAME: &'static str = "Rotation"; 557 | } 558 | impl Component for Velocity { 559 | const NAME: &'static str = "Velocity"; 560 | } 561 | 562 | #[test] 563 | fn test_component_group_len() { 564 | fn test_group_len(expected_len: usize) { 565 | assert_eq!(G::DESCRIPTOR.archetype().len() as usize, expected_len); 566 | } 567 | 568 | test_group_len::(1); 569 | test_group_len::<(Position, Rotation)>(2); 570 | test_group_len::<(Position, Rotation, Velocity)>(3); 571 | } 572 | 573 | #[test] 574 | fn test_component_group_descriptor() { 575 | #[cfg(test)] 576 | extern crate std; 577 | 578 | assert!(::DESCRIPTOR.is_valid()); 579 | assert!(!<(Position, Position) as ComponentGroup>::DESCRIPTOR.is_valid()); 580 | assert!(<(Position, Rotation) as ComponentGroup>::DESCRIPTOR.is_valid()); 581 | } 582 | } 583 | -------------------------------------------------------------------------------- /src/descriptors/component_group_descriptor.rs: -------------------------------------------------------------------------------- 1 | use crate::copy_component_descriptor_from_to; 2 | use crate::descriptors::archetype_descriptor::ArchetypeDescriptor; 3 | use crate::descriptors::component_descriptor::ComponentDescriptor; 4 | use crate::MAX_COMPONENTS_PER_ENTITY; 5 | 6 | /// Describes a group of components. 7 | /// Also contains mappings to and from sorted and unsorted variants. 8 | /// The reason for this is that a component group as type may have a different ordering of tuple elements, 9 | /// but in the ECS itself it should still be the same group. The mappings in this struct describe how 10 | /// to map from and to those variants. As such, each unique ordering of components in a tuple has 11 | /// it's own component group descriptor. 12 | #[derive(Debug)] 13 | pub struct ComponentGroupDescriptor { 14 | archetype: ArchetypeDescriptor, 15 | sorted_to_unsorted: [u8; MAX_COMPONENTS_PER_ENTITY], 16 | unsorted_to_sorted: [u8; MAX_COMPONENTS_PER_ENTITY], 17 | } 18 | 19 | impl ComponentGroupDescriptor { 20 | pub const INVALID: Self = Self { 21 | archetype: ArchetypeDescriptor::INVALID, 22 | sorted_to_unsorted: [0; MAX_COMPONENTS_PER_ENTITY], 23 | unsorted_to_sorted: [0; MAX_COMPONENTS_PER_ENTITY], 24 | }; 25 | 26 | pub const fn is_valid(&self) -> bool { 27 | self.archetype.is_valid() 28 | } 29 | 30 | pub const fn archetype(&self) -> &ArchetypeDescriptor { 31 | &self.archetype 32 | } 33 | 34 | #[allow(dead_code)] 35 | pub const fn as_unsorted(&self, sorted_index: u8) -> &ComponentDescriptor { 36 | unsafe { 37 | &self.archetype.components_unchecked() 38 | [self.sorted_to_unsorted[sorted_index as usize] as usize] 39 | } 40 | } 41 | #[allow(dead_code)] 42 | pub const fn sorted_to_unsorted(&self, index: u8) -> u8 { 43 | self.sorted_to_unsorted[index as usize] 44 | } 45 | 46 | pub const fn unsorted_to_sorted(&self, index: u8) -> u8 { 47 | self.unsorted_to_sorted[index as usize] 48 | } 49 | 50 | pub const fn len(&self) -> u8 { 51 | self.archetype.len() 52 | } 53 | } 54 | 55 | impl ComponentGroupDescriptor { 56 | pub const fn new(descriptors: &[ComponentDescriptor; N]) -> Self { 57 | if !Self::validate_component_descriptors(descriptors) { 58 | return Self::INVALID; 59 | } 60 | 61 | let sorted_descriptors = Self::compute_sorted_descriptors(descriptors); 62 | 63 | let id = ArchetypeDescriptor::compute_archetype_id(&sorted_descriptors); 64 | if !id.is_valid() { 65 | return Self::INVALID; 66 | } 67 | 68 | let (unsorted_to_sorted, sorted_to_unsorted) = 69 | ComponentGroupDescriptor::compute_sort_mappings(descriptors, &sorted_descriptors); 70 | 71 | let value = Self { 72 | archetype: ArchetypeDescriptor::new(id, N as u8, sorted_descriptors), 73 | sorted_to_unsorted, 74 | unsorted_to_sorted, 75 | }; 76 | if !value.archetype.archetype_id().is_valid() { 77 | return Self::INVALID; 78 | } 79 | value 80 | } 81 | 82 | const fn validate_component_descriptors( 83 | descriptors: &[ComponentDescriptor; N], 84 | ) -> bool { 85 | // Length may not be zero or larger than max components. 86 | if descriptors.is_empty() || descriptors.len() > MAX_COMPONENTS_PER_ENTITY { 87 | return false; 88 | } 89 | // Duplicates MUST not exist. 90 | let mut idx = 0; 91 | while idx < N { 92 | let mut cdx = idx + 1; 93 | while cdx < N { 94 | if descriptors[idx].component_type_id().into_u16() 95 | == descriptors[cdx].component_type_id().into_u16() 96 | { 97 | return false; 98 | } 99 | cdx += 1; 100 | } 101 | idx += 1; 102 | } 103 | true 104 | } 105 | 106 | /// Computes the sorted version of a given array of descriptors. 107 | /// # Warning: only functions correctly if descriptors passed in are correctly validated. 108 | /// # Similarly, N must be smaller or equal to [`MAX_COMPONENTS_PER_ENTITY`]. 109 | const fn compute_sorted_descriptors( 110 | descriptors: &[ComponentDescriptor; N], 111 | ) -> [ComponentDescriptor; MAX_COMPONENTS_PER_ENTITY] { 112 | let mut return_value = [ComponentDescriptor::INVALID; MAX_COMPONENTS_PER_ENTITY]; 113 | let mut i = 0; 114 | while i < N { 115 | copy_component_descriptor_from_to!(descriptors[i], return_value[i]); 116 | i += 1; 117 | } 118 | i = 0; 119 | 120 | while i < N { 121 | let mut j = i + 1; 122 | while j < N { 123 | if return_value[j].component_type_id.into_u16() 124 | < return_value[i].component_type_id.into_u16() 125 | { 126 | let mut temp = ComponentDescriptor::INVALID; 127 | copy_component_descriptor_from_to!(return_value[i], temp); 128 | copy_component_descriptor_from_to!(return_value[j], return_value[i]); 129 | copy_component_descriptor_from_to!(temp, return_value[j]); 130 | } 131 | j += 1; 132 | } 133 | i += 1; 134 | } 135 | 136 | return_value 137 | } 138 | 139 | /// Computes the mappings from sorted to unsorted and from unsorted to sorted. 140 | /// # Warning: MUST be used on valid mappings and N must be less than or equal to [`MAX_COMPONENTS_PER_ENTITY`]. 141 | const fn compute_sort_mappings( 142 | unsorted: &[ComponentDescriptor; N], 143 | sorted: &[ComponentDescriptor; MAX_COMPONENTS_PER_ENTITY], 144 | ) -> ( 145 | [u8; MAX_COMPONENTS_PER_ENTITY], 146 | [u8; MAX_COMPONENTS_PER_ENTITY], 147 | ) { 148 | let mut unsorted_to_sorted = [0; MAX_COMPONENTS_PER_ENTITY]; 149 | let mut sorted_to_unsorted = [0; MAX_COMPONENTS_PER_ENTITY]; 150 | 151 | let mut i = 0; 152 | while i < N { 153 | let mut j = 0; 154 | while j < N { 155 | if sorted[j].component_type_id.into_u16() 156 | == unsorted[i].component_type_id.into_u16() 157 | { 158 | unsorted_to_sorted[i] = j as u8; 159 | } 160 | if unsorted[j].component_type_id.into_u16() 161 | == sorted[i].component_type_id.into_u16() 162 | { 163 | sorted_to_unsorted[i] = j as u8; 164 | } 165 | j += 1; 166 | } 167 | i += 1; 168 | } 169 | (unsorted_to_sorted, sorted_to_unsorted) 170 | } 171 | } 172 | 173 | #[cfg(test)] 174 | mod tests { 175 | extern crate std; 176 | use std::*; 177 | 178 | use super::*; 179 | use crate::{Component, ComponentTypeId}; 180 | struct TestComponentA {} 181 | impl Component for TestComponentA { 182 | const NAME: &'static str = "A"; 183 | const ID: ComponentTypeId = ComponentTypeId::from_u16(1); 184 | } 185 | struct TestComponentB {} 186 | impl Component for TestComponentB { 187 | const NAME: &'static str = "B"; 188 | const ID: ComponentTypeId = ComponentTypeId::from_u16(2); 189 | } 190 | struct TestComponentC {} 191 | impl Component for TestComponentC { 192 | const NAME: &'static str = "C"; 193 | const ID: ComponentTypeId = ComponentTypeId::from_u16(3); 194 | } 195 | 196 | #[test] 197 | fn test_compute_sorted_descriptors() { 198 | let descriptors: [ComponentDescriptor; 3] = [ 199 | TestComponentA::DESCRIPTOR, 200 | TestComponentB::DESCRIPTOR, 201 | TestComponentC::DESCRIPTOR, 202 | ]; 203 | let result = ComponentGroupDescriptor::compute_sorted_descriptors(&descriptors); 204 | assert_eq!(TestComponentA::DESCRIPTOR, result[0]); 205 | assert_eq!(TestComponentB::DESCRIPTOR, result[1]); 206 | assert_eq!(TestComponentC::DESCRIPTOR, result[2]); 207 | } 208 | 209 | #[test] 210 | fn test_compute_sort_mappings() { 211 | let unsorted_descriptors: [ComponentDescriptor; 3] = [ 212 | TestComponentA::DESCRIPTOR, 213 | TestComponentB::DESCRIPTOR, 214 | TestComponentC::DESCRIPTOR, 215 | ]; 216 | let sorted_descriptors = 217 | ComponentGroupDescriptor::compute_sorted_descriptors(&unsorted_descriptors); 218 | 219 | let (unsorted_to_sorted, sorted_to_unsorted) = 220 | ComponentGroupDescriptor::compute_sort_mappings( 221 | &unsorted_descriptors, 222 | &sorted_descriptors, 223 | ); 224 | assert_eq!(unsorted_to_sorted[0..3], [0, 1, 2]); 225 | assert_eq!(sorted_to_unsorted[0..3], [0, 1, 2]); 226 | 227 | let unsorted_descriptors: [ComponentDescriptor; 3] = [ 228 | TestComponentB::DESCRIPTOR, 229 | TestComponentC::DESCRIPTOR, 230 | TestComponentA::DESCRIPTOR, 231 | ]; 232 | 233 | let sorted_descriptors = 234 | ComponentGroupDescriptor::compute_sorted_descriptors(&unsorted_descriptors); 235 | 236 | let (unsorted_to_sorted, sorted_to_unsorted) = 237 | ComponentGroupDescriptor::compute_sort_mappings( 238 | &unsorted_descriptors, 239 | &sorted_descriptors, 240 | ); 241 | assert_eq!(unsorted_to_sorted[0..3], [1, 2, 0]); 242 | assert_eq!(sorted_to_unsorted[0..3], [2, 0, 1]); 243 | } 244 | } 245 | -------------------------------------------------------------------------------- /src/descriptors/component_type_id.rs: -------------------------------------------------------------------------------- 1 | use crate::ArchetypeId; 2 | 3 | /// Represents the type of a Component as an identifier. 4 | #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 5 | #[repr(transparent)] 6 | pub struct ComponentTypeId(u16); 7 | 8 | impl From for ComponentTypeId { 9 | fn from(v: u16) -> Self { 10 | Self(v) 11 | } 12 | } 13 | 14 | impl From for ArchetypeId { 15 | fn from(value: ComponentTypeId) -> Self { 16 | ArchetypeId::from_u32(value.0 as u32) 17 | } 18 | } 19 | 20 | impl ComponentTypeId { 21 | pub const INVALID: ComponentTypeId = ComponentTypeId::from_u16(u16::MAX); 22 | 23 | pub const fn is_valid(&self) -> bool { 24 | self.0 != Self::INVALID.0 25 | } 26 | 27 | pub const fn from_u16(v: u16) -> Self { 28 | Self(v) 29 | } 30 | 31 | pub const fn into_u16(self) -> u16 { 32 | self.0 33 | } 34 | } 35 | 36 | impl ComponentTypeId { 37 | pub const fn to_ne_bytes(self) -> [u8; 2] { 38 | self.0.to_ne_bytes() 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/descriptors/mod.rs: -------------------------------------------------------------------------------- 1 | pub mod archetype_descriptor; 2 | pub mod archetype_id; 3 | pub mod component; 4 | pub mod component_descriptor; 5 | pub mod component_group; 6 | pub mod component_group_descriptor; 7 | pub mod component_type_id; 8 | 9 | pub use archetype_id::*; 10 | pub use component::Component; 11 | pub use component_descriptor::ComponentDescriptor; 12 | pub use component_group::ComponentGroup; 13 | pub use component_group_descriptor::ComponentGroupDescriptor; 14 | pub use component_type_id::*; 15 | -------------------------------------------------------------------------------- /src/entity_registry/archetype_index.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 3 | pub struct ArchetypeIndex { 4 | value: u16, 5 | } 6 | 7 | impl ArchetypeIndex { 8 | /// u16::MAX 9 | pub const INVALID_VALUE: u16 = u16::MAX; 10 | 11 | pub const fn new(value: u16) -> Option { 12 | if value == Self::INVALID_VALUE { 13 | return None; 14 | } 15 | Some(Self { value }) 16 | } 17 | 18 | pub const fn value(&self) -> u16 { 19 | self.value 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/entity_registry/entity.rs: -------------------------------------------------------------------------------- 1 | use crate::constants::*; 2 | 3 | /// Represents an abstract Entity. Is internally a handle into the ECS to query it's associated components. 4 | #[repr(transparent)] 5 | #[derive(Copy, Clone, Debug, Eq, PartialEq)] 6 | pub struct Entity { 7 | handle: u32, 8 | } 9 | 10 | impl Default for Entity { 11 | fn default() -> Self { 12 | Self::INVALID 13 | } 14 | } 15 | 16 | impl Entity { 17 | pub const INVALID: Entity = 18 | unsafe { Entity::new_unchecked(MAX_ENTITY_HANDLE_VALUE, MAX_ENTITY_VERSION_VALUE) }; 19 | 20 | /// Constructs a new Entity from a raw u32. 21 | /// The higher/leftmost 24 bits as index, the lower/rightmost 8 bits are used as version. 22 | /// # Safety 23 | /// Keep in mind the bits are interpreted as defined by the entity handle layout. 24 | /// These must be respected by the provided integer value. 25 | pub const unsafe fn from_raw(raw: u32) -> Entity { 26 | Self { handle: raw } 27 | } 28 | 29 | /// Returns if entity is valid, meaning it is NOT equal to Entity::INVALID. 30 | pub const fn is_valid(&self) -> bool { 31 | self.handle != Self::INVALID.handle 32 | } 33 | 34 | /// Returns the invalid entity. 35 | pub const fn invalid() -> Entity { 36 | Self::INVALID 37 | } 38 | 39 | /// Manually construct a new Entity. index MUST be lower than 2^24! 40 | /// Failing to uphold this invariant will corrupt the internal handle. 41 | /// # Safety 42 | /// - index MUST be lower than 2^24! 43 | pub const unsafe fn new_unchecked(index: u32, version: u8) -> Entity { 44 | Entity { 45 | handle: (index << ENTITY_VERSION_BITS) | version as u32, 46 | } 47 | } 48 | 49 | /// Returns the index part of the entity's handle. 50 | pub const fn index(&self) -> u32 { 51 | self.handle >> ENTITY_VERSION_BITS 52 | } 53 | 54 | /// Sets the index part of the entity's handle. 55 | /// index MUST be lower than 2^24! 56 | /// Failing to uphold this invariant will corrupt the internal handle. 57 | /// # Safety 58 | /// - index MUST be lower than 2^24! 59 | pub unsafe fn set_index(&mut self, index: u32) { 60 | debug_assert!( 61 | index < 2u32.pow(ENTITY_HANDLE_BITS as u32), 62 | "Entity index must be < 2^24!" 63 | ); 64 | 65 | let version: u8 = (0xFFFFFF & self.handle) as u8; 66 | self.handle = (index << ENTITY_VERSION_BITS) | version as u32; 67 | } 68 | 69 | /// Returns the version part of the entity's handle. 70 | pub const fn version(&self) -> u8 { 71 | (0xFFFFFF & self.handle) as u8 72 | } 73 | 74 | /// Sets the version part of the entity's handle. 75 | pub fn set_version(&mut self, version: u8) { 76 | self.handle = (self.index() << ENTITY_VERSION_BITS) | version as u32; 77 | } 78 | 79 | /// Returns the raw entity handle. 80 | pub const fn raw(&self) -> u32 { 81 | self.handle 82 | } 83 | } 84 | 85 | #[test] 86 | fn test_entity_handles() { 87 | let mut entity = unsafe { Entity::new_unchecked(8_000_000, 255) }; 88 | assert_eq!(entity.index(), 8_000_000); 89 | assert_eq!(entity.version(), 255); 90 | 91 | entity.set_version(20); 92 | assert_eq!(entity.version(), 20); 93 | assert_eq!(entity.index(), 8_000_000); 94 | 95 | unsafe { 96 | entity.set_index(30); 97 | } 98 | assert_eq!(entity.index(), 30); 99 | assert_eq!(entity.version(), 20); 100 | 101 | assert_eq!(Entity::invalid().raw(), u32::MAX); 102 | } 103 | -------------------------------------------------------------------------------- /src/entity_registry/entry.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::INVALID_ARCHETYPE_INDEX; 3 | 4 | /// Represents entity reference to the [ version | index_in_archetype | archetype_index | length | custom_bits ]. 5 | /// MEMORY_LAYOUTS: 6 | /// Valid: |version: u8|idx_in_arch: u24|arch_idx: u16 ] 7 | /// Invalid: |version: u8|next_fr_slt: u24|INV_ARCH: u16 ] 8 | /// | 0 | 1 2 3 | 4 5 ] 9 | #[repr(C)] 10 | #[derive(Clone, Debug)] 11 | pub struct EntityEntry { 12 | values: [u8; 6], 13 | } 14 | 15 | impl Default for EntityEntry { 16 | fn default() -> Self { 17 | Self { 18 | values: [ 19 | 0, // version byte 1 20 | 0, // index_in_archetype byte 1 21 | 0, // index_in_archetype byte 2 22 | 0, // index_in_archetype byte 3 23 | 0, // archetype_index byte 1 24 | 0, // archetype_index byte 2 25 | ], 26 | } 27 | } 28 | } 29 | 30 | impl EntityEntry { 31 | pub const fn version(&self) -> u8 { 32 | return self.values[0]; 33 | } 34 | pub fn set_version(&mut self, version: u8) { 35 | self.values[0] = version; 36 | } 37 | pub const fn index_in_archetype(&self) -> IndexInArchetype { 38 | IndexInArchetype::from_bytes([self.values[1], self.values[2], self.values[3]]) 39 | } 40 | pub fn set_index_in_archetype(&mut self, index_in_archetype: IndexInArchetype) { 41 | self.values[1] = index_in_archetype.to_bytes()[0]; 42 | self.values[2] = index_in_archetype.to_bytes()[1]; 43 | self.values[3] = index_in_archetype.to_bytes()[2]; 44 | } 45 | pub const fn archetype_index(&self) -> u16 { 46 | u16::from_ne_bytes([self.values[4], self.values[5]]) 47 | } 48 | pub fn set_archetype_index(&mut self, archetype_index: u16) { 49 | let bytes = archetype_index.to_ne_bytes(); 50 | self.values[4] = bytes[0]; 51 | self.values[5] = bytes[1]; 52 | } 53 | /// Checks if this entry points to a valid entity. 54 | pub const fn is_valid(&self) -> bool { 55 | return self.archetype_index() != INVALID_ARCHETYPE_INDEX; 56 | } 57 | /// Sets the archetype index to invalid, indicating this entry does not point to a existing entity. 58 | /// # Safety 59 | /// - next_free_slot must at most be 24 bits. 60 | pub unsafe fn invalidate(&mut self, next_free_slot: u32) { 61 | self.set_index_in_archetype(IndexInArchetype::new_unchecked(next_free_slot)); 62 | self.set_archetype_index(INVALID_ARCHETYPE_INDEX); 63 | } 64 | } 65 | 66 | #[cfg(test)] 67 | mod tests { 68 | use super::{EntityEntry, IndexInArchetype}; 69 | 70 | const TEST_VALUES_U8: [u8; 10] = [0, 3, 7, 12, 89, u8::MAX - 1, u8::MAX, 72, 134, 1]; 71 | const TEST_VALUES_U16: [u16; 10] = [0, 1, 3, 7, 234, 29304, 13032, u16::MAX, u16::MAX - 1, 1]; 72 | const TEST_VALUES_U32: [u32; 10] = [ 73 | 0, 74 | 1, 75 | 3, 76 | 7, 77 | 234, 78 | 2429304, 79 | 13032, 80 | IndexInArchetype::INVALID_VALUE - 1, 81 | 2304820, 82 | 1, 83 | ]; 84 | 85 | /// Checks if bytes that are not in the mutation_allowed list are modified. 86 | /// Returns true if they're not mutated. 87 | fn check_bytes( 88 | before_bytes: &[u8; 6], 89 | after_bytes: &[u8; 6], 90 | mutation_allowed: &[usize], 91 | ) -> bool { 92 | for i in 0..before_bytes.len() { 93 | if mutation_allowed.contains(&i) { 94 | continue; 95 | } 96 | if before_bytes[i] != after_bytes[i] { 97 | return false; 98 | } 99 | } 100 | true 101 | } 102 | 103 | #[test] 104 | fn test_entity_register_entry() { 105 | let mut entry = EntityEntry::default(); 106 | 107 | assert_eq!(entry.version(), 0); 108 | assert_eq!(entry.archetype_index(), 0); 109 | assert_eq!(entry.index_in_archetype().value(), 0); 110 | 111 | // Test IndexInArchetype 112 | for value in TEST_VALUES_U32 { 113 | let idx = IndexInArchetype::new(value).unwrap(); 114 | assert_eq!(idx.value(), value); 115 | } 116 | 117 | // Test version field 118 | for value in TEST_VALUES_U8 { 119 | let before_bytes = entry.values; 120 | entry.set_version(value); 121 | assert_eq!(entry.version(), value); 122 | assert!(check_bytes(&before_bytes, &entry.values, &[0])); 123 | } 124 | // Test archetype index field. 125 | for value in TEST_VALUES_U16 { 126 | let before_bytes = entry.values; 127 | entry.set_archetype_index(value); 128 | assert_eq!(entry.archetype_index(), value); 129 | assert!(check_bytes(&before_bytes, &entry.values, &[4, 5])); 130 | } 131 | // Test index in archetype field. 132 | for value in TEST_VALUES_U32 { 133 | let before_bytes = entry.values; 134 | entry.set_index_in_archetype(unsafe { IndexInArchetype::new_unchecked(value) }); 135 | assert_eq!(entry.index_in_archetype().value(), value); 136 | assert!(check_bytes(&before_bytes, &entry.values, &[1, 2, 3])); 137 | } 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/entity_registry/index_in_archetype.rs: -------------------------------------------------------------------------------- 1 | #[repr(C)] 2 | #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] 3 | pub struct IndexInArchetype { 4 | value: u32, 5 | } 6 | 7 | impl IndexInArchetype { 8 | // Equivalent to 2^24 - 1, as the stored value is [0 - 2^24) excluding 2^24 itself. 9 | pub const INVALID_VALUE: u32 = 16777215; 10 | 11 | /// Constructs a new IndexInArchetype using `value`. 12 | /// Returns `None` in case `value` >= Self::INVALID_VALUE. 13 | pub const fn new(value: u32) -> Option { 14 | if value >= Self::INVALID_VALUE { 15 | return None; 16 | } 17 | Some(Self { value }) 18 | } 19 | /// Constructs a new IndexInArchetype using `value`. 20 | /// If value >= `Self::INVALID_VALUE` behaviour is undefined. 21 | pub const unsafe fn new_unchecked(value: u32) -> IndexInArchetype { 22 | Self { value } 23 | } 24 | 25 | /// Constructs a new IndexInArchetype from raw bytes. 26 | pub const fn from_bytes(bytes: [u8; 3]) -> IndexInArchetype { 27 | let mut value = 0; 28 | value += (bytes[0] as u32) << 16; 29 | value += (bytes[1] as u32) << 8; 30 | value += bytes[2] as u32; 31 | Self { value } 32 | } 33 | 34 | /// Returns the triple byte representation of the value. 35 | /// This is a shifted representation storing only the 3 most significant bytes. 36 | pub const fn to_bytes(&self) -> [u8; 3] { 37 | [ 38 | ((self.value & 0x00FF0000) >> 16) as u8, 39 | ((self.value & 0x0000FF00) >> 8) as u8, 40 | (self.value & 0x000000FF) as u8, 41 | ] 42 | } 43 | 44 | /// Returns the raw numeric value of the index in archetype. 45 | pub const fn value(&self) -> u32 { 46 | self.value 47 | } 48 | } 49 | 50 | impl Default for IndexInArchetype { 51 | fn default() -> Self { 52 | Self { value: 0 } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/entity_registry/iterator.rs: -------------------------------------------------------------------------------- 1 | use super::entry::EntityEntry; 2 | use super::Entity; 3 | use core::iter::FusedIterator; 4 | 5 | pub struct EntityIter<'a> { 6 | entities: &'a [EntityEntry], 7 | current: usize, 8 | } 9 | 10 | impl<'a> EntityIter<'a> { 11 | pub(super) fn new(entities: &'a [EntityEntry]) -> Self { 12 | Self { 13 | entities, 14 | current: 0, 15 | } 16 | } 17 | } 18 | 19 | impl<'a> Iterator for EntityIter<'a> { 20 | type Item = Entity; 21 | 22 | fn next(&mut self) -> Option { 23 | while self.current < self.entities.len() { 24 | self.current += 1; 25 | let entry = &self.entities[self.current - 1]; 26 | if entry.is_valid() { 27 | return unsafe { 28 | Some(Entity::new_unchecked( 29 | (self.current - 1) as u32, 30 | entry.version(), 31 | )) 32 | }; 33 | } 34 | } 35 | None 36 | } 37 | } 38 | 39 | impl<'a> FusedIterator for EntityIter<'a> {} 40 | -------------------------------------------------------------------------------- /src/entity_registry/mod.rs: -------------------------------------------------------------------------------- 1 | mod entity; 2 | mod archetype_index; 3 | mod entry; 4 | mod iterator; 5 | mod index_in_archetype; 6 | 7 | pub use entity::*; 8 | pub use entry::*; 9 | pub use iterator::*; 10 | pub use index_in_archetype::*; 11 | pub use archetype_index::*; 12 | 13 | use alloc::vec::*; 14 | 15 | pub struct EntityRegistry { 16 | entities: Vec, 17 | next_free_slot: u32, 18 | } 19 | 20 | impl Default for EntityRegistry { 21 | fn default() -> Self { 22 | Self { 23 | entities: Vec::new(), 24 | next_free_slot: IndexInArchetype::INVALID_VALUE, 25 | } 26 | } 27 | } 28 | 29 | impl EntityRegistry { 30 | pub const MAX_ENTITY_COUNT: usize = crate::MAX_ENTITY_HANDLE_VALUE as usize; 31 | 32 | pub fn can_register_new_entity(&self) -> bool { 33 | self.entities.len() < Self::MAX_ENTITY_COUNT 34 | } 35 | 36 | pub fn create_entity(&mut self, index_in_archetype: IndexInArchetype, archetype_index: ArchetypeIndex) -> Option { 37 | if self.entities.len() >= Self::MAX_ENTITY_COUNT { 38 | return None; 39 | } 40 | let (entity, entry) = if self.next_free_slot == IndexInArchetype::INVALID_VALUE { 41 | // Linked list of free slots is empty, so we need to allocate a new entity. 42 | self.entities.push(EntityEntry::default()); 43 | let idx = self.entities.len() - 1; 44 | ( 45 | unsafe { Entity::new_unchecked(idx as u32, 0) }, 46 | self.entities.last_mut().unwrap(), 47 | ) 48 | } else { 49 | let slot = self.next_free_slot; 50 | let entry = &mut self.entities[slot as usize]; 51 | self.next_free_slot = entry.index_in_archetype().value(); 52 | ( 53 | unsafe { Entity::new_unchecked(slot as u32, entry.version()) }, 54 | &mut self.entities[slot as usize] 55 | ) 56 | }; 57 | entry.set_archetype_index(archetype_index.value()); 58 | entry.set_index_in_archetype(index_in_archetype); 59 | Some(entity) 60 | } 61 | 62 | pub fn destroy_entity(&mut self, entity: Entity) -> bool { 63 | if entity.index() as usize >= self.entities.len() || entity == Entity::INVALID { 64 | return false; 65 | } 66 | let entry = &mut self.entities[entity.index() as usize]; 67 | if entry.version() != entity.version() || !entry.is_valid() { 68 | return false; 69 | } 70 | unsafe { entry.invalidate(self.next_free_slot) }; 71 | self.next_free_slot = entity.index(); 72 | entry.set_version(entry.version().wrapping_add(1)); 73 | true 74 | } 75 | 76 | pub fn entity_entry(&self, entity: Entity) -> Option<&EntityEntry> { 77 | if entity.index() as usize >= self.entities.len() || entity == Entity::INVALID { 78 | return None; 79 | } 80 | let entry = &self.entities[entity.index() as usize]; 81 | if entry.version() != entity.version() || !entry.is_valid() { 82 | return None; 83 | } 84 | Some(entry) 85 | } 86 | 87 | pub fn entity_entry_mut(&mut self, entity: Entity) -> Option<&mut EntityEntry> { 88 | if entity.index() as usize >= self.entities.len() || entity == Entity::INVALID { 89 | return None; 90 | } 91 | let entry = &mut self.entities[entity.index() as usize]; 92 | if entry.version() != entity.version() || !entry.is_valid() { 93 | return None; 94 | } 95 | Some(entry) 96 | } 97 | 98 | pub fn iter(&self) -> impl Iterator + '_ { 99 | EntityIter::new(&self.entities) 100 | } 101 | } 102 | 103 | #[cfg(test)] 104 | mod tests { 105 | use super::*; 106 | 107 | fn verify_linked_list(register: &EntityRegistry) { 108 | if register.next_free_slot == IndexInArchetype::INVALID_VALUE { 109 | // None of the slots may contain a marker that it's an invalid slot. 110 | for elem in ®ister.entities { 111 | assert!(elem.is_valid()); 112 | } 113 | } else { 114 | let mut value = register.next_free_slot; 115 | while value != IndexInArchetype::INVALID_VALUE { 116 | assert!(value as usize <= register.entities.len()); 117 | let slot = ®ister.entities[value as usize]; 118 | assert!(!slot.is_valid()); 119 | value = slot.index_in_archetype().value(); 120 | } 121 | } 122 | } 123 | 124 | #[test] 125 | fn test_entity_register() { 126 | let mut register = EntityRegistry::default(); 127 | let index_in_archetype = IndexInArchetype::new(1).unwrap(); 128 | let archetype_index = ArchetypeIndex::new(1).unwrap(); 129 | 130 | let entity = register 131 | .create_entity(index_in_archetype, archetype_index) 132 | .unwrap(); 133 | 134 | assert!(register.entity_entry(entity).is_some()); 135 | verify_linked_list(®ister); 136 | assert_eq!(register.next_free_slot, IndexInArchetype::INVALID_VALUE); 137 | assert_eq!(register.entities.len(), 1); 138 | 139 | assert!(register.destroy_entity(entity)); 140 | assert_eq!(register.next_free_slot, entity.index()); 141 | assert!(!register.entities[entity.index() as usize].is_valid()); 142 | assert_eq!(register.entities[entity.index() as usize].version(), 1); 143 | assert_eq!(register.entities[entity.index() as usize].archetype_index(), ArchetypeIndex::INVALID_VALUE); 144 | assert!(register.entity_entry(entity).is_none()); 145 | assert!(register.entity_entry_mut(entity).is_none()); 146 | 147 | let entity = register.create_entity(index_in_archetype, archetype_index).unwrap(); 148 | let entry = register.entity_entry(entity).unwrap(); 149 | assert_eq!(entry.archetype_index(), archetype_index.value()); 150 | assert_eq!(entry.index_in_archetype(), index_in_archetype); 151 | assert_eq!(entity.index(), 0); 152 | 153 | verify_linked_list(®ister); 154 | assert_eq!(register.next_free_slot, IndexInArchetype::INVALID_VALUE); 155 | assert_eq!(register.entities.len(), 1); 156 | 157 | } 158 | 159 | const ENTITY_COUNT: u32 = 1024; 160 | #[test] 161 | fn test_many_entities() { 162 | let mut registry = EntityRegistry::default(); 163 | // Check destroying invalid entity. 164 | assert!(!registry.destroy_entity(Entity::invalid())); 165 | let index_in_archetype = IndexInArchetype::new(2).unwrap(); 166 | let archetype_index = ArchetypeIndex::new(1).unwrap(); 167 | 168 | let entities = (0..ENTITY_COUNT) 169 | .into_iter() 170 | .filter_map(|_| registry.create_entity(index_in_archetype, archetype_index)) 171 | .collect::>(); 172 | entities.iter().rev().cloned().for_each(|e| { 173 | let entry = registry.entity_entry(e).unwrap(); 174 | assert_eq!(entry.version(), 0); 175 | assert_eq!(entry.archetype_index(), 1); 176 | assert_eq!(entry.index_in_archetype().value(), 2); 177 | assert!(registry.destroy_entity(e)); 178 | }); 179 | entities.iter().cloned().for_each(|e| { 180 | assert_eq!(registry.destroy_entity(e), false); 181 | assert!(registry.entity_entry(e).is_none()); 182 | assert!(registry.entity_entry_mut(e).is_none()); 183 | }); 184 | 185 | assert!(!registry.destroy_entity(Entity::invalid())); 186 | 187 | let entities = (0..ENTITY_COUNT) 188 | .into_iter() 189 | .filter_map(|_| registry.create_entity(index_in_archetype, archetype_index)) 190 | .collect::>(); 191 | entities.iter().rev().cloned().for_each(|entity| { 192 | let entry = registry.entity_entry(entity).unwrap(); 193 | assert_ne!(entry.version(), 0); 194 | assert_eq!(entry.archetype_index(), 1); 195 | assert_eq!(entry.index_in_archetype().value(), 2); 196 | assert!(registry.destroy_entity(entity)); 197 | }); 198 | entities.iter().for_each(|entity| { 199 | assert!(!registry.destroy_entity(*entity)); 200 | assert!(registry.entity_entry(*entity).is_none()); 201 | assert!(registry.entity_entry_mut(*entity).is_none()); 202 | }); 203 | 204 | for entity in registry.iter() { 205 | let _ = entities.contains(&entity); 206 | } 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /src/fnv1a.rs: -------------------------------------------------------------------------------- 1 | const FNV_OFFSET_BASIS_32: u32 = 0x811c9dc5; 2 | #[allow(dead_code)] 3 | const FNV_OFFSET_BASIS_64: u64 = 0xcbf29ce484222325; 4 | 5 | const FNV_PRIME_32: u32 = 0x01000193; 6 | #[allow(dead_code)] 7 | const FNV_PRIME_64: u64 = 0x00000100000001B3; 8 | 9 | /// Computes 64-bits fnv1a hash of the given slice, or up-to limit if provided. 10 | /// If limit is zero or exceeds slice length, slice length is used instead. 11 | pub const fn fnv1a_hash_64(bytes: &[u8], limit: Option) -> u64 { 12 | let mut hash = FNV_OFFSET_BASIS_64; 13 | 14 | let mut i = 0; 15 | let len = match limit { 16 | Some(v) => { 17 | if v <= bytes.len() && v > 0 { 18 | v 19 | } else { 20 | bytes.len() 21 | } 22 | } 23 | None => bytes.len(), 24 | }; 25 | 26 | while i < len { 27 | hash ^= bytes[i] as u64; 28 | hash = hash.wrapping_mul(FNV_PRIME_64); 29 | i += 1; 30 | } 31 | hash 32 | } 33 | 34 | /// Computes 32-bits fnv1a hash of the given slice, or up-to limit if provided. 35 | /// If limit is zero or exceeds slice length, slice length is used instead. 36 | pub const fn fnv1a_hash_32(bytes: &[u8], limit: Option) -> u32 { 37 | let mut hash = FNV_OFFSET_BASIS_32; 38 | 39 | let mut i = 0; 40 | let len = match limit { 41 | Some(v) => { 42 | if v <= bytes.len() && v > 0 { 43 | v 44 | } else { 45 | bytes.len() 46 | } 47 | } 48 | None => bytes.len(), 49 | }; 50 | 51 | while i < len { 52 | hash ^= bytes[i] as u32; 53 | hash = hash.wrapping_mul(FNV_PRIME_32); 54 | i += 1; 55 | } 56 | hash 57 | } 58 | 59 | /// Computes 32-bits fnv1a hash and xor higher and lower 16-bits. 60 | /// Up to limit if provided, otherwise slice length. 61 | /// If limit is zero or exceeds slice length, slice length is used instead. 62 | #[allow(dead_code)] 63 | pub const fn fnv1a_hash_16_xor(bytes: &[u8], limit: Option) -> u16 { 64 | let bytes = fnv1a_hash_32(bytes, limit).to_ne_bytes(); 65 | let upper: u16 = u16::from_ne_bytes([bytes[0], bytes[1]]); 66 | let lower: u16 = u16::from_ne_bytes([bytes[2], bytes[3]]); 67 | upper ^ lower 68 | } 69 | 70 | /// Computes 64-bit fnv1a hash from a str. 71 | #[allow(dead_code)] 72 | pub const fn fnv1a_hash_str_64(input: &str) -> u64 { 73 | fnv1a_hash_64(input.as_bytes(), None) 74 | } 75 | 76 | /// Computes 32-bit fnv1a hash from a str. 77 | #[allow(dead_code)] 78 | pub const fn fnv1a_hash_str_32(input: &str) -> u32 { 79 | fnv1a_hash_32(input.as_bytes(), None) 80 | } 81 | 82 | /// Computes 16-bit fnv1a hash from a str. 83 | #[allow(dead_code)] 84 | pub const fn fnv1a_hash_str_16_xor(input: &str) -> u16 { 85 | fnv1a_hash_16_xor(input.as_bytes(), None) 86 | } 87 | -------------------------------------------------------------------------------- /src/lib.rs: -------------------------------------------------------------------------------- 1 | #![no_std] 2 | 3 | extern crate alloc; 4 | 5 | pub mod archetype; 6 | pub mod archetype_registry; 7 | pub mod constants; 8 | pub mod descriptors; 9 | pub mod entity_registry; 10 | pub mod fnv1a; 11 | pub mod registry; 12 | 13 | pub use archetype::Archetype; 14 | pub use constants::*; 15 | pub use descriptors::*; 16 | pub use entity_registry::*; 17 | pub use registry::Registry; 18 | 19 | #[cfg(test)] 20 | mod test_components; 21 | 22 | #[cfg(feature = "derive")] 23 | pub use shard_ecs_derive::*; -------------------------------------------------------------------------------- /src/registry/mod.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | mod tests; 3 | 4 | mod registry; 5 | 6 | pub use registry::*; 7 | -------------------------------------------------------------------------------- /src/registry/registry.rs: -------------------------------------------------------------------------------- 1 | use crate::ArchetypeIndex; 2 | use crate::archetype::Archetype; 3 | use crate::archetype_descriptor::ArchetypeDescriptor; 4 | use crate::archetype_registry::ArchetypeRegistry; 5 | use crate::descriptors::component_group::ComponentGroup; 6 | use crate::entity_registry::IndexInArchetype; 7 | use crate::{entity_registry::EntityRegistry, Component, Entity}; 8 | 9 | /// The primary construct in the *Shard* Entity Component System (ECS). 10 | #[derive(Default)] 11 | pub struct Registry { 12 | entities: EntityRegistry, 13 | archetypes: ArchetypeRegistry, 14 | } 15 | 16 | impl Registry { 17 | /// Creates a new entity using the provided components. 18 | /// Returns Ok with a Entity if successful, or Err(components) if not. 19 | /// Returns Err if the provided component group is invalid or an internal limit is exceeded. 20 | /// Panics in case of allocation failure. 21 | pub fn create_entity<'c, G: ComponentGroup>(&mut self, components: G) -> Result { 22 | if !G::DESCRIPTOR.is_valid() { 23 | return Err(components); 24 | } 25 | let (archetype_index, archetype) = match self 26 | .archetypes 27 | .find_or_create_archetype(G::DESCRIPTOR.archetype()) 28 | { 29 | Some(v) => v, 30 | None => return Err(components), 31 | }; 32 | let index_in_archetype = IndexInArchetype::new(archetype.len()).unwrap(); 33 | let entity = match self.entities.create_entity(index_in_archetype, ArchetypeIndex::new(archetype_index).unwrap()) { 34 | Some(v) => v, 35 | None => return Err(components), 36 | }; 37 | unsafe { archetype.push_entity_unchecked(entity, components) }; 38 | Ok(entity) 39 | } 40 | 41 | /// Removes the entity from the registry. 42 | /// This function return false if the entity given is invalid. 43 | pub fn destroy_entity(&mut self, entity: Entity) -> bool { 44 | let entry = match self.entities.entity_entry(entity) { 45 | None => return false, 46 | Some(v) => v, 47 | }; 48 | let archetype = unsafe { self.archetypes.get_unchecked_mut(entry.archetype_index()) }; 49 | let index_in_archetype = entry.index_in_archetype(); 50 | unsafe { 51 | if archetype.swap_drop_unchecked(index_in_archetype.value()) { 52 | // A swap was needed, so we need to update the index_in_archetype of the entry that it was swapped with. 53 | // We retrieve the entity handle using the metadata, which is now at the old entity's position. 54 | let swapped_entity = *archetype 55 | .entities() 56 | .get_unchecked(index_in_archetype.value() as usize); 57 | self.entities 58 | .entity_entry_mut(swapped_entity) 59 | .unwrap() 60 | .set_index_in_archetype(index_in_archetype); 61 | } 62 | }; 63 | let _v = self.entities.destroy_entity(entity); 64 | debug_assert!(_v); 65 | true 66 | } 67 | 68 | /// Removes the entity from the registry if it matches the given component group exactly. 69 | /// Otherwise, it simply leaves the entity as is. 70 | /// This function return None if either entity given is invalid, or does not match the given component group. 71 | pub fn remove_entity<'a, G: ComponentGroup>(&'a mut self, entity: Entity) -> Option { 72 | let entry = match self.entities.entity_entry(entity) { 73 | None => return None, 74 | Some(v) => v, 75 | }; 76 | let archetype = unsafe { self.archetypes.get_unchecked_mut(entry.archetype_index()) }; 77 | let index_in_archetype = entry.index_in_archetype(); 78 | unsafe { 79 | return match archetype.swap_remove_unchecked::(index_in_archetype.value()) { 80 | (value, true) => { 81 | // A swap was needed, so we need to update the index_in_archetype of the entry that it was swapped with. 82 | // We retrieve the entity handle using the metadata, which is now at the old entity's position. 83 | let swapped_entity = archetype.entities()[index_in_archetype.value() as usize]; 84 | self.entities 85 | .entity_entry_mut(swapped_entity) 86 | .unwrap() 87 | .set_index_in_archetype(index_in_archetype); 88 | let _v = self.entities.destroy_entity(entity); 89 | debug_assert!(_v); 90 | Some(value) 91 | } 92 | (value, false) => { 93 | let _v = self.entities.destroy_entity(entity); 94 | debug_assert!(_v); 95 | Some(value) 96 | } 97 | }; 98 | } 99 | } 100 | 101 | /// Returns true if a given entity has the specified component. 102 | /// Returns false if entity is invalid or does not have the specified component. 103 | pub fn has_component(&self, entity: Entity) -> bool { 104 | let entry = match self.entities.entity_entry(entity) { 105 | None => return false, 106 | Some(v) => v, 107 | }; 108 | let archetype = unsafe { self.archetypes.get_unchecked(entry.archetype_index()) }; 109 | archetype.descriptor().has_component::() 110 | } 111 | 112 | /// Returns true if a given entity has all of the specified components. 113 | /// Returns false if entity is invalid or does not have all of the specified components. 114 | /// If you need to check for only a single components, prefer to use [`Registry::has_component`] instead. 115 | pub fn has_components<'registry, G: ComponentGroup>(&'registry self, entity: Entity) -> bool { 116 | let entry = match self.entities.entity_entry(entity) { 117 | None => return false, 118 | Some(v) => v, 119 | }; 120 | let archetype = unsafe { self.archetypes.get_unchecked(entry.archetype_index()) }; 121 | archetype 122 | .descriptor() 123 | .contains_subset(G::DESCRIPTOR.archetype()) 124 | } 125 | 126 | /// Returns a reference to the specified component if the entity has it. 127 | /// Returns false if entity is invalid or does not have the specified component. 128 | pub fn get_component(&self, entity: Entity) -> Option<&C> { 129 | let entry = match self.entities.entity_entry(entity) { 130 | None => return None, 131 | Some(v) => v, 132 | }; 133 | unsafe { 134 | let archetype = self.archetypes.get_unchecked(entry.archetype_index()); 135 | if !archetype.descriptor().has_component::() { 136 | return None; 137 | } 138 | archetype.get_component_unchecked::(entry.index_in_archetype().value()) 139 | } 140 | .into() 141 | } 142 | 143 | /// Returns a tuple of references to the specified components if the entity has all of them. 144 | /// Returns false if entity is invalid or does not have the specified components. 145 | /// If you need to get only a single component, use [`Registry::get_component`] instead. 146 | pub fn get_components<'registry, G: ComponentGroup>( 147 | &'registry self, 148 | entity: Entity, 149 | ) -> Option> { 150 | let entry = match self.entities.entity_entry(entity) { 151 | None => return None, 152 | Some(v) => v, 153 | }; 154 | unsafe { 155 | let archetype = self.archetypes.get_unchecked(entry.archetype_index()); 156 | if !archetype 157 | .descriptor() 158 | .contains_subset(G::DESCRIPTOR.archetype()) 159 | { 160 | return None; 161 | } 162 | archetype.get_fuzzy_components_unchecked::(entry.index_in_archetype().value()) 163 | } 164 | .into() 165 | } 166 | 167 | /// Returns a mutable reference to the specified component if the entity has it. 168 | /// Returns false if entity is invalid or does not have the specified component. 169 | /// If you need to get only a single component, use [`Registry::get_component_mut`] instead. 170 | pub fn get_component_mut(&mut self, entity: Entity) -> Option<&mut C> { 171 | let entry = match self.entities.entity_entry(entity) { 172 | None => return None, 173 | Some(v) => v, 174 | }; 175 | unsafe { 176 | let archetype = self.archetypes.get_unchecked_mut(entry.archetype_index()); 177 | if !archetype.descriptor().has_component::() { 178 | return None; 179 | } 180 | archetype.get_component_unchecked_mut::(entry.index_in_archetype().value()) 181 | } 182 | .into() 183 | } 184 | 185 | /// Returns a tuple of mutable references to the specified components if the entity has all of them. 186 | /// Returns false if entity is invalid or does not have the specified components. 187 | pub fn get_components_mut<'registry, G: ComponentGroup>( 188 | &'registry mut self, 189 | entity: Entity, 190 | ) -> Option> { 191 | let entry = match self.entities.entity_entry(entity) { 192 | None => return None, 193 | Some(v) => v, 194 | }; 195 | unsafe { 196 | let archetype = self.archetypes.get_unchecked_mut(entry.archetype_index()); 197 | if !archetype 198 | .descriptor() 199 | .contains_subset(G::DESCRIPTOR.archetype()) 200 | { 201 | return None; 202 | } 203 | archetype.get_fuzzy_components_unchecked_mut::(entry.index_in_archetype().value()) 204 | } 205 | .into() 206 | } 207 | 208 | /// Adds a given component to the entity if it's not yet present. 209 | /// Returns the original component in case of failure for any reason. 210 | /// Reasons for failure: 211 | /// - Invalid entity provided. 212 | /// - Destination archetype could not be created. 213 | pub fn add_component(&mut self, entity: Entity, component: C) -> Result<(), C> { 214 | let entry = match self.entities.entity_entry(entity) { 215 | None => return Err(component), 216 | Some(v) => v.clone(), 217 | }; 218 | 219 | // Get the new archetype 220 | let (source_archetype, destination_archetype_index, destination_archetype) = match self 221 | .archetypes 222 | .find_or_create_archetype_adding_component(entry.archetype_index(), &C::DESCRIPTOR) 223 | { 224 | Some(v) => v, 225 | None => return Err(component), 226 | }; 227 | 228 | // Make sure the entity we move is at the end of it's archetype (so data stays contiguous). 229 | if unsafe { source_archetype.swap_to_last_unchecked(entry.index_in_archetype().value()) } { 230 | // A swap was needed, so we need to update the index_in_archetype of the entry that it was swapped with. 231 | // We retrieve the entity handle using the metadata, which is now at the swapped with entity's position. 232 | let swapped_entity = 233 | source_archetype.entities()[entry.index_in_archetype().value() as usize]; 234 | self.entities 235 | .entity_entry_mut(swapped_entity) 236 | .unwrap() 237 | .set_index_in_archetype(entry.index_in_archetype()); 238 | } 239 | 240 | unsafe { 241 | // Make space in the destination archetype. 242 | destination_archetype.push_uninitialized_entity(); 243 | 244 | // copy from end to end. 245 | let new_source_entity_index_in_archetype = source_archetype.len() - 1; 246 | let destination_entity_index_in_archetype = destination_archetype.len() - 1; 247 | // Write common components. 248 | Archetype::copy_common_components_between_archetypes_unchecked( 249 | source_archetype, 250 | new_source_entity_index_in_archetype, 251 | destination_archetype, 252 | destination_entity_index_in_archetype, 253 | ); 254 | // Write added component 255 | destination_archetype 256 | .write_single_component_unchecked(destination_entity_index_in_archetype, component); 257 | 258 | // Copy the metadata 259 | destination_archetype.entities_mut()[destination_entity_index_in_archetype as usize] = 260 | source_archetype.entities()[new_source_entity_index_in_archetype as usize]; 261 | 262 | // Make the source archetype forget the old entity. 263 | source_archetype.decrement_len_unchecked(); 264 | 265 | // Update the original entity entry to point to destination archetype and index in archetype. 266 | let entity_entry = self.entities.entity_entry_mut(entity).unwrap(); 267 | entity_entry.set_archetype_index(destination_archetype_index); 268 | entity_entry.set_index_in_archetype( 269 | IndexInArchetype::new(destination_entity_index_in_archetype).unwrap(), 270 | ); 271 | 272 | Ok(()) 273 | } 274 | } 275 | 276 | /// Removes a given component from the entity if it's present. 277 | /// Returns the component in if successful. 278 | /// Reasons for failure: 279 | /// - Invalid entity provided. 280 | /// - Destination archetype could not be created. 281 | pub fn remove_component(&mut self, entity: Entity) -> Result { 282 | let entry = match self.entities.entity_entry(entity) { 283 | None => return Err(()), 284 | Some(v) => v.clone(), 285 | }; 286 | 287 | // Get the new archetype 288 | let (source_archetype, destination_archetype_index, destination_archetype) = match self 289 | .archetypes 290 | .find_or_create_archetype_removing_component(entry.archetype_index(), &C::DESCRIPTOR) 291 | { 292 | Some(v) => v, 293 | None => return Err(()), 294 | }; 295 | 296 | // Make sure the entity we move is at the end of it's archetype (so data stays contiguous). 297 | if unsafe { source_archetype.swap_to_last_unchecked(entry.index_in_archetype().value()) } { 298 | // A swap was needed, so we need to update the index_in_archetype of the entry that it was swapped with. 299 | // We retrieve the entity handle using the metadata, which is now at the swapped with entity's position. 300 | let swapped_entity = 301 | source_archetype.entities()[entry.index_in_archetype().value() as usize]; 302 | self.entities 303 | .entity_entry_mut(swapped_entity) 304 | .unwrap() 305 | .set_index_in_archetype(entry.index_in_archetype()); 306 | } 307 | 308 | unsafe { 309 | // Make space in the destination archetype. 310 | destination_archetype.push_uninitialized_entity(); 311 | 312 | // copy from end to end. 313 | let new_source_entity_index_in_archetype = source_archetype.len() - 1; 314 | let destination_entity_index_in_archetype = destination_archetype.len() - 1; 315 | // Write common components. 316 | Archetype::copy_common_components_between_archetypes_unchecked( 317 | source_archetype, 318 | new_source_entity_index_in_archetype, 319 | destination_archetype, 320 | destination_entity_index_in_archetype, 321 | ); 322 | // Read removed component 323 | let component: C = 324 | source_archetype.read_component_unchecked(new_source_entity_index_in_archetype); 325 | 326 | // Copy the metadata 327 | destination_archetype.entities_mut()[destination_entity_index_in_archetype as usize] = 328 | source_archetype.entities()[new_source_entity_index_in_archetype as usize]; 329 | 330 | // Make the source archetype forget the old entity. 331 | source_archetype.decrement_len_unchecked(); 332 | 333 | // Update the original entity entry to point to destination archetype and index in archetype. 334 | let entity_entry = self.entities.entity_entry_mut(entity).unwrap(); 335 | entity_entry.set_archetype_index(destination_archetype_index); 336 | entity_entry.set_index_in_archetype( 337 | IndexInArchetype::new(destination_entity_index_in_archetype).unwrap(), 338 | ); 339 | 340 | Ok(component) 341 | } 342 | } 343 | } 344 | 345 | impl Registry { 346 | /// Returns an iterator which iterates over all entities in the registry. 347 | pub fn iter_entities(&self) -> impl Iterator + '_ { 348 | self.entities.iter() 349 | } 350 | 351 | /// Returns an iterator which iterates over all components in archetypes 352 | /// matching the specified predicate. 353 | pub fn iter_components_matching<'registry, G: ComponentGroup>( 354 | &'registry self, 355 | ) -> impl Iterator::SliceRefTuple<'registry>> + 'registry { 356 | self.archetypes.iter_components_matching::() 357 | } 358 | 359 | /// Returns an iterator which mutably iterates over all components in archetypes 360 | /// matching the specified predicate. 361 | pub fn iter_components_matching_mut<'registry, G: ComponentGroup>( 362 | &'registry mut self, 363 | ) -> impl Iterator::SliceMutRefTuple<'registry>> + 'registry { 364 | self.archetypes.iter_components_matching_mut::() 365 | } 366 | 367 | /// Returns an iterator which iterates over all entities and components in archetypes 368 | /// matching the specified predicate. 369 | pub fn iter_entity_components_matching<'registry, G: ComponentGroup>( 370 | &'registry self, 371 | ) -> impl Iterator< 372 | Item = ( 373 | &'registry [Entity], 374 | ::SliceRefTuple<'registry>, 375 | ), 376 | > + 'registry { 377 | self.archetypes.iter_entity_components_matching::() 378 | } 379 | 380 | /// Returns an iterator which mutably iterates over all entities and components in archetypes 381 | /// matching the specified predicate. 382 | pub fn iter_entity_components_matching_mut<'registry, G: ComponentGroup>( 383 | &'registry mut self, 384 | ) -> impl Iterator< 385 | Item = ( 386 | &'registry [Entity], 387 | ::SliceMutRefTuple<'registry>, 388 | ), 389 | > + 'registry { 390 | self.archetypes.iter_entity_components_matching_mut::() 391 | } 392 | 393 | /// Returns an iterator which iterates over all components in archetypes 394 | /// matching the specified predicate. 395 | /// Archetypes not matching the filter closure are excluded. 396 | pub fn iter_filtered_components_matching< 397 | 'registry, 398 | G: ComponentGroup, 399 | F: Fn(&ArchetypeDescriptor) -> bool + 'registry, 400 | >( 401 | &'registry self, 402 | filter_closure: F, 403 | ) -> impl Iterator::SliceRefTuple<'registry>> + 'registry { 404 | self.archetypes 405 | .iter_filtered_components_matching::(filter_closure) 406 | } 407 | 408 | /// Returns an iterator which mutably iterates over all components in archetypes 409 | /// matching the specified predicate. 410 | /// Archetypes not matching the filter closure are excluded. 411 | pub fn iter_filtered_components_matching_mut< 412 | 'registry, 413 | G: ComponentGroup, 414 | F: Fn(&ArchetypeDescriptor) -> bool + 'registry, 415 | >( 416 | &'registry mut self, 417 | filter_closure: F, 418 | ) -> impl Iterator::SliceMutRefTuple<'registry>> + 'registry { 419 | self.archetypes 420 | .iter_filtered_components_matching_mut::(filter_closure) 421 | } 422 | 423 | /// Returns an iterator which iterates over all entities and components in archetypes 424 | /// matching the specified predicate. 425 | /// Archetypes not matching the filter closure are excluded. 426 | pub fn iter_filtered_entity_components_matching< 427 | 'registry, 428 | G: ComponentGroup, 429 | F: Fn(&ArchetypeDescriptor) -> bool + 'registry, 430 | >( 431 | &'registry self, 432 | filter_closure: F, 433 | ) -> impl Iterator< 434 | Item = ( 435 | &'registry [Entity], 436 | ::SliceRefTuple<'registry>, 437 | ), 438 | > + 'registry { 439 | self.archetypes 440 | .iter_filtered_entity_components_matching::(filter_closure) 441 | } 442 | 443 | /// Returns an iterator which mutably iterates over all entities and components in archetypes 444 | /// matching the specified predicate. 445 | /// Archetypes not matching the filter closure are excluded. 446 | pub fn iter_filtered_entity_components_matching_mut< 447 | 'registry, 448 | G: ComponentGroup, 449 | F: Fn(&ArchetypeDescriptor) -> bool + 'registry, 450 | >( 451 | &'registry mut self, 452 | filter_closure: F, 453 | ) -> impl Iterator< 454 | Item = ( 455 | &'registry [Entity], 456 | ::SliceMutRefTuple<'registry>, 457 | ), 458 | > + 'registry { 459 | self.archetypes 460 | .iter_filtered_entity_components_matching_mut::(filter_closure) 461 | } 462 | 463 | /// Returns a tuple of component slices if the exact archetype 464 | /// matching the predicate exists. 465 | pub fn iter_components_exact<'registry, G: ComponentGroup>( 466 | &'registry self, 467 | ) -> ::SliceRefTuple<'registry> { 468 | match self.archetypes.find_archetype(G::DESCRIPTOR.archetype()) { 469 | Some(v) => unsafe { v.get_slices_unchecked_exact::() }, 470 | None => G::empty_slice(), 471 | } 472 | } 473 | 474 | /// Returns a tuple of mutable component slices if the exact archetype 475 | /// matching the predicate exists. 476 | pub fn iter_components_exact_mut<'registry, G: ComponentGroup>( 477 | &'registry mut self, 478 | ) -> ::SliceMutRefTuple<'registry> { 479 | match self 480 | .archetypes 481 | .find_archetype_mut(G::DESCRIPTOR.archetype()) 482 | { 483 | Some(v) => unsafe { v.get_slices_unchecked_exact_mut::() }, 484 | None => G::empty_slice_mut(), 485 | } 486 | } 487 | 488 | /// Returns a tuple of an entity slice and component slices if the exact archetype 489 | /// matching the predicate exists. 490 | pub fn iter_entity_components_exact<'registry, G: ComponentGroup>( 491 | &'registry self, 492 | ) -> ( 493 | &'registry [Entity], 494 | ::SliceRefTuple<'registry>, 495 | ) { 496 | match self.archetypes.find_archetype(G::DESCRIPTOR.archetype()) { 497 | Some(v) => unsafe { (v.entities(), v.get_slices_unchecked_exact::()) }, 498 | None => (&[], G::empty_slice()), 499 | } 500 | } 501 | 502 | /// Returns a tuple of an entity slice and mutable component slices if the exact archetype 503 | /// matching the predicate exists. 504 | pub fn iter_entity_components_exact_mut<'registry, G: ComponentGroup>( 505 | &'registry mut self, 506 | ) -> ( 507 | &'registry [Entity], 508 | ::SliceMutRefTuple<'registry>, 509 | ) { 510 | match self 511 | .archetypes 512 | .find_archetype_mut(G::DESCRIPTOR.archetype()) 513 | { 514 | // Safety: entities is a separate slice, not being accessed in get_slices_unchecked_exact_mut. 515 | Some(v) => unsafe { 516 | ( 517 | (*(v as *mut Archetype)).entities(), 518 | v.get_slices_unchecked_exact_mut::(), 519 | ) 520 | }, 521 | None => (&[], G::empty_slice_mut()), 522 | } 523 | } 524 | } 525 | -------------------------------------------------------------------------------- /src/registry/tests.rs: -------------------------------------------------------------------------------- 1 | #[cfg(test)] 2 | use crate::test_components::*; 3 | #[cfg(test)] 4 | use crate::*; 5 | use alloc::vec::Vec; 6 | 7 | #[test] 8 | fn registry_test_get_component() { 9 | let mut registry = Registry::default(); 10 | let entity = registry 11 | .create_entity((A::default(), B::default())) 12 | .unwrap(); 13 | assert_eq!(registry.get_component(entity), Some(&A::default())); 14 | assert_eq!(registry.get_component_mut(entity), Some(&mut B::default())); 15 | assert_eq!(registry.get_component::(entity), None); 16 | assert_eq!(registry.get_component_mut::(Entity::invalid()), None); 17 | assert_eq!( 18 | registry.get_components::<(A, B)>(entity), 19 | Some((&A::default(), &B::default())) 20 | ); 21 | assert_eq!( 22 | registry.get_components::<(B, A)>(entity), 23 | Some((&B::default(), &A::default())) 24 | ); 25 | assert_eq!(registry.get_components::<(A, B)>(Entity::invalid()), None); 26 | assert_eq!( 27 | registry.get_components_mut::<(A, B)>(entity), 28 | Some((&mut A::default(), &mut B::default())) 29 | ); 30 | assert_eq!( 31 | registry.get_components_mut::<(B, A)>(entity), 32 | Some((&mut B::default(), &mut A::default())) 33 | ); 34 | assert_eq!( 35 | registry.get_components_mut::<(A, B)>(Entity::invalid()), 36 | None 37 | ); 38 | assert_eq!( 39 | registry.get_component::(entity), 40 | registry.get_components::(entity) 41 | ); 42 | } 43 | 44 | #[test] 45 | fn registry_test_has_component() { 46 | let mut registry: Registry = Default::default(); 47 | let entity = registry 48 | .create_entity((A::default(), B::default())) 49 | .unwrap(); 50 | assert_eq!(registry.has_component::(entity), true); 51 | assert_eq!(registry.has_component::(entity), true); 52 | assert_eq!(registry.has_component::(entity), false); 53 | assert_eq!(registry.has_component::(Entity::invalid()), false); 54 | 55 | assert_eq!(registry.has_components::<(A, B)>(entity), true); 56 | assert_eq!(registry.has_components::<(A, C)>(entity), false); 57 | assert_eq!(registry.has_components::<(A, B)>(Entity::invalid()), false); 58 | } 59 | 60 | #[test] 61 | fn test_registry() { 62 | let mut registry = Registry::default(); 63 | let entity = registry.create_entity((A::default(), B::default())); 64 | assert!(entity.is_ok()); 65 | let entity = entity.unwrap(); 66 | assert_eq!(entity.version(), 0); 67 | let component = registry.get_component::(entity); 68 | assert!(component.is_some()); 69 | let component = component.unwrap(); 70 | assert_eq!(*component, A::default()); 71 | let component = registry.get_component_mut::(entity); 72 | assert!(component.is_some()); 73 | let component = component.unwrap(); 74 | assert_eq!(*component, B::default()); 75 | registry.destroy_entity(entity); 76 | let entity = registry.create_entity((A::default(), B::default())); 77 | assert!(entity.is_ok()); 78 | let entity = entity.unwrap(); 79 | assert_eq!(entity.version(), 1); 80 | let component = registry.get_component::(entity); 81 | assert!(component.is_some()); 82 | let component = component.unwrap(); 83 | assert_eq!(*component, A::default()); 84 | let component = registry.get_component_mut::(entity); 85 | assert!(component.is_some()); 86 | let component = component.unwrap(); 87 | assert_eq!(*component, B::default()); 88 | 89 | let entity_data = registry.remove_entity::<(B, A)>(entity); 90 | assert!(entity_data.is_some()); 91 | let (b, a) = entity_data.unwrap(); 92 | assert_eq!(a, A::default()); 93 | assert_eq!(b, B::default()); 94 | 95 | let entity = registry.create_entity((A::default(), B::default())); 96 | assert!(entity.is_ok()); 97 | let entity = entity.unwrap(); 98 | assert!(registry.has_component::(entity)); 99 | assert!(registry.has_component::(entity)); 100 | 101 | assert!(registry.add_component(entity, C::default()).is_ok()); 102 | 103 | assert!(registry.has_component::(entity)); 104 | assert!(registry.has_component::(entity)); 105 | assert!(registry.has_component::(entity)); 106 | 107 | assert!(registry.remove_component::(entity).is_ok()); 108 | 109 | assert!(registry.has_components::<(C, B)>(entity)); 110 | assert_eq!(registry.has_component::(entity), false); 111 | 112 | registry.destroy_entity(entity); 113 | 114 | const COUNT: usize = 32; 115 | let mut registry = Registry::default(); 116 | let entities: Vec<_> = (0..COUNT) 117 | .map(|e| { 118 | registry 119 | .create_entity((A { _data: e }, B { _data: COUNT - e })) 120 | .unwrap() 121 | }) 122 | .collect(); 123 | 124 | registry 125 | .iter_entities() 126 | .for_each(|e| assert!(entities.contains(&e))); 127 | 128 | for (entities, (a, b)) in registry.iter_entity_components_matching::<(A, B)>() { 129 | entities.iter().for_each(|e| assert!(entities.contains(&e))); 130 | a.iter() 131 | .enumerate() 132 | .for_each(|(i, a)| assert_eq!(a._data, i)); 133 | b.iter() 134 | .enumerate() 135 | .for_each(|(i, b)| assert_eq!(b._data, COUNT - i)); 136 | } 137 | 138 | let _entities2: Vec<_> = (0..COUNT) 139 | .map(|e| { 140 | registry 141 | .create_entity((A { _data: e }, B { _data: COUNT - e }, C { _data: e })) 142 | .unwrap() 143 | }) 144 | .collect(); 145 | let mut counter = 0; 146 | for _ in registry.iter_components_matching::<(A, B)>() { 147 | counter += 1; 148 | } 149 | assert_eq!(counter, 2); 150 | 151 | let entities = (0..1000) 152 | .into_iter() 153 | .map(|_e| { 154 | registry 155 | .create_entity((A::default(), B::default())) 156 | .unwrap() 157 | }) 158 | .collect::>(); 159 | 160 | for entity in &entities { 161 | let entity = entity.clone(); 162 | assert!(registry.add_component(entity, C::default()).is_ok()); 163 | assert!(registry.has_component::(entity)); 164 | } 165 | for entity in &entities { 166 | let entity = entity.clone(); 167 | match rand::random() { 168 | true => { 169 | assert!(registry.destroy_entity(entity)) 170 | } 171 | false => match rand::random() { 172 | true => { 173 | assert!(registry.remove_component::(entity).is_ok()); 174 | assert!(registry.has_components::<(A, B)>(entity)); 175 | assert_eq!(registry.has_component::(entity), false); 176 | assert_eq!( 177 | registry.get_components::<(A, B)>(entity), 178 | Some((&A::default(), &B::default())) 179 | ); 180 | } 181 | false => { 182 | assert!(registry.remove_component::(entity).is_ok()); 183 | assert!(registry.has_components::<(C, B)>(entity)); 184 | assert_eq!(registry.has_component::(entity), false); 185 | assert_eq!( 186 | registry.get_components::<(C, B)>(entity), 187 | Some((&C::default(), &B::default())) 188 | ); 189 | } 190 | }, 191 | } 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /src/test_components.rs: -------------------------------------------------------------------------------- 1 | use crate::*; 2 | 3 | #[derive(Clone, Eq, PartialEq, Debug)] 4 | pub struct A { 5 | pub _data: usize, 6 | } 7 | impl Default for A { 8 | fn default() -> Self { 9 | Self { _data: 1 } 10 | } 11 | } 12 | impl Component for A { 13 | const NAME: &'static str = "A"; 14 | const ID: ComponentTypeId = ComponentTypeId::from_u16(1); 15 | } 16 | #[derive(Clone, Eq, PartialEq, Debug)] 17 | pub struct B { 18 | pub _data: usize, 19 | } 20 | impl Default for B { 21 | fn default() -> Self { 22 | Self { _data: 2 } 23 | } 24 | } 25 | impl Component for B { 26 | const NAME: &'static str = "B"; 27 | const ID: ComponentTypeId = ComponentTypeId::from_u16(2); 28 | } 29 | #[derive(Clone, Eq, PartialEq, Debug)] 30 | pub struct C { 31 | pub _data: usize, 32 | } 33 | impl Default for C { 34 | fn default() -> Self { 35 | Self { _data: 3 } 36 | } 37 | } 38 | impl Component for C { 39 | const NAME: &'static str = "C"; 40 | const ID: ComponentTypeId = ComponentTypeId::from_u16(3); 41 | } 42 | #[derive(Clone, Eq, PartialEq, Debug)] 43 | pub struct DropLogA { 44 | pub _data: usize, 45 | } 46 | impl Default for DropLogA { 47 | fn default() -> Self { 48 | Self { _data: 4 } 49 | } 50 | } 51 | impl Component for DropLogA { 52 | const NAME: &'static str = "DropLogA"; 53 | const ID: ComponentTypeId = ComponentTypeId::from_u16(4); 54 | } 55 | #[cfg(test)] 56 | impl Drop for DropLogA { 57 | fn drop(&mut self) { 58 | extern crate std; 59 | std::println!("Dropping A: {:#?}", self as *const Self); 60 | } 61 | } 62 | #[derive(Clone, Eq, PartialEq, Debug)] 63 | pub struct DropLogB { 64 | pub _data: usize, 65 | } 66 | impl Default for DropLogB { 67 | fn default() -> Self { 68 | Self { _data: 5 } 69 | } 70 | } 71 | impl Component for DropLogB { 72 | const NAME: &'static str = "DropLogB"; 73 | const ID: ComponentTypeId = ComponentTypeId::from_u16(5); 74 | } 75 | #[cfg(test)] 76 | impl Drop for DropLogB { 77 | fn drop(&mut self) { 78 | extern crate std; 79 | std::println!("Dropping B: {:#?}", self as *const Self); 80 | } 81 | } 82 | #[derive(Clone, Eq, PartialEq, Debug)] 83 | pub struct DropLogC { 84 | pub _data: usize, 85 | } 86 | impl Default for DropLogC { 87 | fn default() -> Self { 88 | Self { _data: 6 } 89 | } 90 | } 91 | impl Component for DropLogC { 92 | const NAME: &'static str = "DropLogC"; 93 | const ID: ComponentTypeId = ComponentTypeId::from_u16(6); 94 | } 95 | #[cfg(test)] 96 | impl Drop for DropLogC { 97 | fn drop(&mut self) { 98 | extern crate std; 99 | std::println!("Dropping C: {:#?}", self as *const Self); 100 | } 101 | } 102 | --------------------------------------------------------------------------------