diff options
Diffstat (limited to 'ecs')
35 files changed, 0 insertions, 5373 deletions
diff --git a/ecs/Cargo.toml b/ecs/Cargo.toml deleted file mode 100644 index 4945171..0000000 --- a/ecs/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -name = "ecs" -version = "0.1.0" -edition = "2021" - -[dependencies] -seq-macro = "0.3.5" -paste = "1.0.14" -thiserror = "1.0.49" -tracing = "0.1.39" -linkme = "0.3.29" -hashbrown = "0.15.2" -parking_lot = "0.12.3" -ecs-macros = { path = "../ecs-macros" } -util-macros = { path = "../util-macros" } - -[dev-dependencies.criterion] -version = "0.5.1" -default-features = false -features = ["cargo_bench_support"] - -[[bench]] -name = "query" -harness = false diff --git a/ecs/benches/query.rs b/ecs/benches/query.rs deleted file mode 100644 index f14bb06..0000000 --- a/ecs/benches/query.rs +++ /dev/null @@ -1,141 +0,0 @@ -use std::hint::black_box; -use std::path::PathBuf; - -use criterion::{criterion_group, criterion_main, Criterion}; -use ecs::{Component, World}; - -#[derive(Component)] -struct Foo -{ - _text: String, -} - -#[derive(Component)] -struct Bar -{ - _path: PathBuf, - _num: u64, -} - -#[derive(Component)] -struct Position -{ - _x: f32, - _y: f32, - _z: f32, -} - -#[derive(Component)] -struct PosA -{ - _x: f32, - _y: f32, - _z: f32, -} - -#[derive(Component)] -struct PosB -{ - _x: f32, - _y: f32, - _z: f32, -} - -#[derive(Component)] -struct PosC -{ - _x: f32, - _y: f32, - _z: f32, -} - -#[derive(Component)] -struct MoreText -{ - _more_text: String, -} - -#[derive(Component)] -struct EvenMoreText -{ - _even_more_text: String, -} - -fn spawn_1000_entities(world: &mut World) -{ - for _ in 0..300 { - world.create_entity(( - Bar { - _path: "/dev/zero".into(), - _num: 65789, - }, - Position { _x: 13.98, _y: 27.0, _z: 0.2 }, - Foo { _text: "Hello there".to_string() }, - PosA { - _x: 1183.98, - _y: 272628.0, - _z: 3306.2, - }, - PosB { - _x: 171183.98, - _y: 28.0, - _z: 336.2901, - }, - PosC { _x: 8273.98, _y: 28.0, _z: 336.2901 }, - MoreText { - _more_text: "Lorem ipsum".to_string(), - }, - EvenMoreText { - _even_more_text: "Wow so much text".to_string(), - }, - )); - } - - for _ in 0..700 { - world.create_entity(( - Bar { - _path: "/dev/null".into(), - _num: 65789, - }, - Position { _x: 88.11, _y: 9.0, _z: 36.11 }, - Foo { _text: "Hey".to_string() }, - PosA { - _x: 118310.98, - _y: 272628.0, - _z: 3306.2, - }, - PosB { _x: 11323.98, _y: 28.0, _z: 336.2901 }, - PosC { - _x: 8273.98, - _y: 21818.0, - _z: 336.2901, - }, - MoreText { - _more_text: "Lorem ipsum".to_string(), - }, - EvenMoreText { - _even_more_text: "Wow much text".to_string(), - }, - )); - } -} - -fn benchbark(criterion: &mut Criterion) -{ - criterion.bench_function("Iterate 1000 entities", |bencher| { - let mut world = World::new(); - - spawn_1000_entities(&mut world); - - let query = world.query::<(&Bar, &Position, &Foo), ()>(); - - bencher.iter(|| { - for comps in query.iter() { - black_box(comps); - } - }) - }); -} - -criterion_group!(benches, benchbark); -criterion_main!(benches); diff --git a/ecs/examples/event_loop.rs b/ecs/examples/event_loop.rs deleted file mode 100644 index 2365eb0..0000000 --- a/ecs/examples/event_loop.rs +++ /dev/null @@ -1,98 +0,0 @@ -use ecs::actions::Actions; -use ecs::phase::{Phase, UPDATE as UPDATE_PHASE}; -use ecs::relationship::{ChildOf, Relationship}; -use ecs::{static_entity, Component, Query, World}; - -#[derive(Component)] -struct Wool -{ - remaining: u32, -} - -#[derive(Component)] -struct Health -{ - health: u32, -} - -#[derive(Component)] -struct Name -{ - name: &'static str, -} - -fn sheer(query: Query<(&mut Wool, &Name)>) -{ - for (mut wool, name) in &query { - if wool.remaining == 0 { - println!("{} Has no wool left", name.name); - - continue; - } - - // Sheer the whool - wool.remaining -= 5; - - println!("Sheered 5 wool from {}", name.name); - } -} - -fn feed(query: Query<(&mut Health, &Name)>) -{ - for (mut health, name) in &query { - health.health += 1; - - println!("Feeded {} which gained 1 health", name.name); - } -} - -fn age(query: Query<(&mut Health, &Name)>, mut actions: Actions) -{ - for (mut health, name) in &query { - if health.health <= 2 { - health.health = 0; - - println!("{} passed away", name.name); - - actions.stop(); - - continue; - } - - health.health -= 2; - - println!("{} aged and lost 2 health", name.name); - } -} - -static_entity!( - SHEER_PHASE, - (Phase, <Relationship<ChildOf, Phase>>::new(*UPDATE_PHASE)) -); - -static_entity!( - FEED_PHASE, - (Phase, <Relationship<ChildOf, Phase>>::new(*SHEER_PHASE)) -); - -static_entity!( - AGE_PHASE, - (Phase, <Relationship<ChildOf, Phase>>::new(*FEED_PHASE)) -); - -fn main() -{ - let mut world = World::new(); - - world.register_system(*SHEER_PHASE, sheer); - world.register_system(*FEED_PHASE, feed); - world.register_system(*AGE_PHASE, age); - - world.create_entity(( - Wool { remaining: 30 }, - Health { health: 3 }, - Name { name: "Bessy" }, - )); - - world.start_loop(); -} diff --git a/ecs/examples/extension.rs b/ecs/examples/extension.rs deleted file mode 100644 index f6282e1..0000000 --- a/ecs/examples/extension.rs +++ /dev/null @@ -1,70 +0,0 @@ -use ecs::actions::Actions; -use ecs::extension::{Collector as ExtensionCollector, Extension}; -use ecs::phase::UPDATE as UPDATE_PHASE; -use ecs::{Component, Query, World}; - -#[derive(Debug, Component)] -struct Position -{ - x: u32, - y: u32, -} - -#[derive(Debug, Component)] -struct EnemySpawnSource; - -#[derive(Debug, Component)] -enum EvilnessLevel -{ - Medium, -} - -fn spawn_enemies( - spawner_query: Query<(&EnemySpawnSource, &Position)>, - enemies_query: Query<(&EvilnessLevel,)>, - mut actions: Actions, -) -{ - let Some((_, enemy_spawner_position)) = spawner_query.iter().next() else { - return; - }; - - let enemy_cnt = enemies_query.iter().count(); - - if enemy_cnt > 3 { - return; - } - - actions.spawn(( - EvilnessLevel::Medium, - Position { - x: enemy_spawner_position.x * enemy_cnt as u32, - y: enemy_spawner_position.y, - }, - )); - - println!("Spawned enemy with medium evilness and 45 strength"); -} - -struct EnemySpawningExtension; - -impl Extension for EnemySpawningExtension -{ - fn collect(self, mut collector: ExtensionCollector<'_>) - { - collector.add_system(*UPDATE_PHASE, spawn_enemies); - - collector.add_entity((Position { x: 187, y: 30 }, EnemySpawnSource)); - } -} - -fn main() -{ - let mut world = World::new(); - - world.add_extension(EnemySpawningExtension); - - for _ in 0..7 { - world.step(); - } -} diff --git a/ecs/examples/multiple_queries.rs b/ecs/examples/multiple_queries.rs deleted file mode 100644 index e0c957f..0000000 --- a/ecs/examples/multiple_queries.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::fmt::Display; - -use ecs::phase::START as START_PHASE; -use ecs::{Component, Query, World}; - -#[derive(Component)] -struct Health -{ - health: u32, -} - -#[derive(Component)] -enum AttackStrength -{ - Strong, - Weak, -} - -#[derive(Component)] -struct EnemyName -{ - name: String, -} - -impl Display for EnemyName -{ - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result - { - self.name.fmt(formatter) - } -} - -fn do_attacks( - attacker_query: Query<(&AttackStrength,)>, - enemy_query: Query<(&mut Health, &EnemyName)>, -) -{ - for (attack_strength,) in &attacker_query { - for (mut health, enemy_name) in &enemy_query { - let damage = match *attack_strength { - AttackStrength::Strong => 20, - AttackStrength::Weak => 10, - }; - - if health.health <= damage { - println!("Enemy '{}' died", *enemy_name); - - health.health = 0; - - continue; - } - - health.health -= damage; - - println!("Enemy '{}' took {damage} damage", *enemy_name); - } - } -} - -fn main() -{ - let mut world = World::new(); - - world.register_system(*START_PHASE, do_attacks); - - world.create_entity(( - Health { health: 100 }, - EnemyName { name: "Big spider".to_string() }, - )); - - world.create_entity(( - Health { health: 30 }, - EnemyName { name: "Small goblin".to_string() }, - )); - - world.create_entity(( - Health { health: 30 }, - EnemyName { name: "Headcrab".to_string() }, - )); - - world.create_entity((AttackStrength::Strong,)); - world.create_entity((AttackStrength::Weak,)); - - world.step(); -} diff --git a/ecs/examples/optional_component.rs b/ecs/examples/optional_component.rs deleted file mode 100644 index 488dad2..0000000 --- a/ecs/examples/optional_component.rs +++ /dev/null @@ -1,81 +0,0 @@ -use ecs::phase::UPDATE as UPDATE_PHASE; -use ecs::{Component, Query, World}; - -#[derive(Debug, Component)] -struct PettingCapacity -{ - capacity_left: u32, -} - -#[derive(Debug, Clone, Copy, Component)] -enum Aggressivity -{ - High, - Medium, - Low, -} - -#[derive(Debug, Component)] -pub struct CatName -{ - name: String, -} - -fn pet_cats(query: Query<(&CatName, &mut PettingCapacity, &Option<Aggressivity>)>) -{ - for (cat_name, mut petting_capacity, aggressivity) in &query { - let Some(aggressivity) = aggressivity else { - println!("Aggressivity of cat {} is unknown. Skipping", cat_name.name); - continue; - }; - - if let Aggressivity::High = *aggressivity { - println!("Cat {} is aggressive. Skipping", cat_name.name); - continue; - } - - if petting_capacity.capacity_left == 0 { - println!( - "Cat {} have had enough of being petted. Skipping", - cat_name.name - ); - continue; - } - - println!("Petting cat {}", cat_name.name); - - petting_capacity.capacity_left -= 1; - } -} - -fn main() -{ - let mut world = World::new(); - - world.register_system(*UPDATE_PHASE, pet_cats); - - world.create_entity(( - CatName { name: "Jasper".to_string() }, - Aggressivity::Medium, - PettingCapacity { capacity_left: 5 }, - )); - - world.create_entity(( - CatName { name: "Otto".to_string() }, - PettingCapacity { capacity_left: 9 }, - )); - - world.create_entity(( - CatName { name: "Carrie".to_string() }, - PettingCapacity { capacity_left: 2 }, - Aggressivity::High, - )); - - world.create_entity(( - CatName { name: "Tommy".to_string() }, - PettingCapacity { capacity_left: 1 }, - Aggressivity::Low, - )); - - world.step(); -} diff --git a/ecs/examples/relationship.rs b/ecs/examples/relationship.rs deleted file mode 100644 index 240884a..0000000 --- a/ecs/examples/relationship.rs +++ /dev/null @@ -1,50 +0,0 @@ -use ecs::phase::START as START_PHASE; -use ecs::relationship::Relationship; -use ecs::{Component, Query, World}; - -#[derive(Component)] -struct Sword -{ - attack_strength: u32, -} - -#[derive(Component)] -struct Player; - -#[derive(Component)] -struct Health -{ - health: u32, -} - -struct Holding; - -fn print_player_stats( - player_query: Query<(&Player, &Health, &Relationship<Holding, Sword>)>, -) -{ - for (_, health, sword_relationship) in &player_query { - println!("Player health: {}", health.health); - - if let Some(sword) = sword_relationship.get(0) { - println!("Player sword attack strength: {}", sword.attack_strength); - } - } -} - -fn main() -{ - let mut world = World::new(); - - world.register_system(*START_PHASE, print_player_stats); - - let sword_uid = world.create_entity((Sword { attack_strength: 17 },)); - - world.create_entity(( - Player, - Health { health: 180 }, - Relationship::<Holding, Sword>::new(sword_uid), - )); - - world.step(); -} diff --git a/ecs/examples/simple.rs b/ecs/examples/simple.rs deleted file mode 100644 index 0169062..0000000 --- a/ecs/examples/simple.rs +++ /dev/null @@ -1,42 +0,0 @@ -use ecs::phase::START as START_PHASE; -use ecs::{Component, Query, World}; - -#[derive(Component)] -struct SomeData -{ - num: u64, -} - -#[derive(Component)] -struct Greeting -{ - greeting: String, -} - -fn say_hello(query: Query<(&SomeData, &Greeting)>) -{ - for (data, greeting) in &query { - println!("{}: {}", greeting.greeting, data.num); - } -} - -fn main() -{ - let mut world = World::new(); - - world.register_system(*START_PHASE, say_hello); - - world.create_entity(( - SomeData { num: 987_654 }, - Greeting { - greeting: "Good afternoon".to_string(), - }, - )); - - world.create_entity(( - SomeData { num: 345 }, - Greeting { greeting: "Good evening".to_string() }, - )); - - world.step(); -} diff --git a/ecs/examples/with_local.rs b/ecs/examples/with_local.rs deleted file mode 100644 index 4658fc0..0000000 --- a/ecs/examples/with_local.rs +++ /dev/null @@ -1,69 +0,0 @@ -use ecs::component::local::Local; -use ecs::phase::UPDATE as UPDATE_PHASE; -use ecs::system::{Into, System}; -use ecs::{Component, Query, World}; - -#[derive(Component)] -struct SomeData -{ - num: u64, -} - -#[derive(Component)] -struct Name -{ - name: String, -} - -#[derive(Component)] -struct SayHelloState -{ - cnt: usize, -} - -fn say_hello(query: Query<(&SomeData,)>, mut state: Local<SayHelloState>) -{ - for (data,) in &query { - println!("Hello there. Count {}: {}", state.cnt, data.num); - - state.cnt += 1; - } -} - -fn say_whats_up(query: Query<(&SomeData, &Name)>, mut state: Local<SayHelloState>) -{ - for (data, name) in &query { - println!( - "Whats up, {}. Number is {}. Count {}", - name.name, data.num, state.cnt - ); - - state.cnt += 1; - } -} - -fn main() -{ - let mut world = World::new(); - - world.register_system( - *UPDATE_PHASE, - say_hello - .into_system() - .initialize((SayHelloState { cnt: 0 },)), - ); - - world.register_system( - *UPDATE_PHASE, - say_whats_up - .into_system() - .initialize((SayHelloState { cnt: 0 },)), - ); - - world.create_entity((SomeData { num: 987_654 }, Name { name: "Bob".to_string() })); - - world.create_entity((SomeData { num: 345 },)); - - world.step(); - world.step(); -} diff --git a/ecs/examples/with_sole.rs b/ecs/examples/with_sole.rs deleted file mode 100644 index 689e562..0000000 --- a/ecs/examples/with_sole.rs +++ /dev/null @@ -1,53 +0,0 @@ -use ecs::phase::{Phase, UPDATE as UPDATE_PHASE}; -use ecs::relationship::{ChildOf, Relationship}; -use ecs::sole::Single; -use ecs::{static_entity, Component, Query, Sole, World}; - -#[derive(Component)] -struct Ammo -{ - ammo_left: u32, -} - -#[derive(Sole, Default)] -struct AmmoCounter -{ - counter: u32, -} - -fn count_ammo(query: Query<(&Ammo,)>, mut ammo_counter: Single<AmmoCounter>) -{ - for (ammo,) in &query { - println!("Found {} ammo", ammo.ammo_left); - - ammo_counter.counter += ammo.ammo_left; - } -} - -fn print_total_ammo_count(ammo_counter: Single<AmmoCounter>) -{ - println!("Total ammo count: {}", ammo_counter.counter); - - assert_eq!(ammo_counter.counter, 19); -} - -static_entity!( - PRINT_AMMO_COUNT_PHASE, - (Phase, <Relationship<ChildOf, Phase>>::new(*UPDATE_PHASE)) -); - -fn main() -{ - let mut world = World::new(); - - world.register_system(*UPDATE_PHASE, count_ammo); - world.register_system(*PRINT_AMMO_COUNT_PHASE, print_total_ammo_count); - - world.create_entity((Ammo { ammo_left: 4 },)); - world.create_entity((Ammo { ammo_left: 7 },)); - world.create_entity((Ammo { ammo_left: 8 },)); - - world.add_sole(AmmoCounter::default()).unwrap(); - - world.step(); -} diff --git a/ecs/src/actions.rs b/ecs/src/actions.rs deleted file mode 100644 index 89fd84a..0000000 --- a/ecs/src/actions.rs +++ /dev/null @@ -1,177 +0,0 @@ -use std::marker::PhantomData; -use std::sync::{Arc, Weak}; - -use crate::component::{ - Component, - Metadata as ComponentMetadata, - Sequence as ComponentSequence, -}; -use crate::system::{Param as SystemParam, System}; -use crate::uid::{Kind as UidKind, Uid}; -use crate::{ActionQueue, World}; - -/// Used to to queue up actions for a [`World`] to perform. -#[derive(Debug)] -pub struct Actions<'world> -{ - action_queue: &'world ActionQueue, - action_queue_weak: Weak<ActionQueue>, -} - -impl<'world> Actions<'world> -{ - /// Queues up a entity to spawn at the end of the current tick. - pub fn spawn<Comps: ComponentSequence>(&mut self, components: Comps) - { - self.action_queue.push(Action::Spawn( - components.into_array().into(), - EventIds { ids: Comps::added_event_ids() }, - )); - } - - /// Queues up despawning a entity at the end of the current tick. - pub fn despawn(&mut self, entity_uid: Uid) - { - debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - - self.action_queue.push(Action::Despawn(entity_uid)); - } - - /// Queues up adding component(s) to a entity at the end of the current tick. - pub fn add_components<Comps>(&mut self, entity_uid: Uid, components: Comps) - where - Comps: ComponentSequence, - { - debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - - if Comps::COUNT == 0 { - return; - } - - self.action_queue.push(Action::AddComponents( - entity_uid, - components.into_array().into(), - EventIds { ids: Comps::added_event_ids() }, - )); - } - - /// Queues up removing component(s) from a entity at the end of the current tick. - pub fn remove_components<Comps>(&mut self, entity_uid: Uid) - where - Comps: ComponentSequence, - { - debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - - if Comps::COUNT == 0 { - return; - } - - self.action_queue.push(Action::RemoveComponents( - entity_uid, - Comps::metadata().into_iter().collect(), - EventIds { ids: Comps::removed_event_ids() }, - )); - } - - /// Stops the [`World`]. The world will finish the current tick and that tick will be - /// the last. - pub fn stop(&mut self) - { - self.action_queue.push(Action::Stop); - } - - /// Returns a struct which holds a weak reference to the [`World`] that `Actions` - /// references and that can be used to aquire a new `Actions` instance if the - /// referenced [`World`] is still alive. - #[must_use] - pub fn to_weak_ref(&self) -> WeakRef - { - WeakRef { - action_queue: self.action_queue_weak.clone(), - } - } - - fn new(action_queue: &'world Arc<ActionQueue>) -> Self - { - Self { - action_queue, - action_queue_weak: Arc::downgrade(action_queue), - } - } -} - -impl<'world> SystemParam<'world> for Actions<'world> -{ - type Input = (); - - fn initialize<SystemImpl>( - _system: &mut impl System<'world, SystemImpl>, - _input: Self::Input, - ) - { - } - - fn new<SystemImpl>( - _system: &'world impl System<'world, SystemImpl>, - world: &'world World, - ) -> Self - { - Self::new(&world.data.action_queue) - } -} - -#[derive(Debug, Clone)] -pub struct WeakRef -{ - action_queue: Weak<ActionQueue>, -} - -impl WeakRef -{ - /// Returns a struct which can be used to retrieve a [`Actions`]. - /// - /// Returns [`None`] if the referenced [`World`] has been dropped. - #[must_use] - pub fn access(&self) -> Option<Ref<'_>> - { - Some(Ref { - action_queue: self.action_queue.upgrade()?, - _pd: PhantomData, - }) - } -} - -/// Intermediate between [`Actions`] and [`WeakRef`]. Contains a strong reference to -/// a world which is not allowed direct access to. -#[derive(Debug, Clone)] -pub struct Ref<'weak_ref> -{ - action_queue: Arc<ActionQueue>, - _pd: PhantomData<&'weak_ref ()>, -} - -impl<'weak_ref> Ref<'weak_ref> -{ - #[must_use] - pub fn to_actions(&self) -> Actions<'_> - { - Actions::new(&self.action_queue) - } -} - -#[derive(Debug)] -pub(crate) struct EventIds -{ - pub(crate) ids: Vec<Uid>, -} - -/// A action for a [`System`] to perform. -#[derive(Debug)] -pub(crate) enum Action -{ - Spawn(Vec<Box<dyn Component>>, EventIds), - Despawn(Uid), - AddComponents(Uid, Vec<Box<dyn Component>>, EventIds), - RemoveComponents(Uid, Vec<ComponentMetadata>, EventIds), - Stop, -} diff --git a/ecs/src/archetype.rs b/ecs/src/archetype.rs deleted file mode 100644 index 846e231..0000000 --- a/ecs/src/archetype.rs +++ /dev/null @@ -1,56 +0,0 @@ -use std::hash::{DefaultHasher, Hash, Hasher}; - -use crate::component::Metadata as ComponentMetadata; - -/// Archetype ID. -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Id -{ - hash: u64, -} - -impl Id -{ - pub fn from_components_metadata( - components_metadata: &impl AsRef<[ComponentMetadata]>, - ) -> Self - { - if components_metadata.as_ref().len() == 0 { - return Self { hash: 0 }; - } - - debug_assert!( - components_metadata - .as_ref() - .is_sorted_by_key(|comp_metadata| comp_metadata.id), - "Cannot create archetype ID from a unsorted component metadata list" - ); - - let component_ids = - components_metadata - .as_ref() - .iter() - .filter_map(|component_metadata| { - if component_metadata.is_optional { - return None; - } - - Some(component_metadata.id) - }); - - let mut hasher = DefaultHasher::new(); - - for component_id in component_ids { - component_id.hash(&mut hasher); - } - - let hash = hasher.finish(); - - assert_ne!( - hash, 0, - "Archetype ID 0 is reserved for a archetype with zero components" - ); - - Self { hash } - } -} diff --git a/ecs/src/component.rs b/ecs/src/component.rs deleted file mode 100644 index b2ecf80..0000000 --- a/ecs/src/component.rs +++ /dev/null @@ -1,406 +0,0 @@ -use std::any::{type_name, Any}; -use std::fmt::Debug; - -use seq_macro::seq; - -use crate::event::component::{ - Added as ComponentAddedEvent, - Kind as ComponentEventKind, - Removed as ComponentRemovedEvent, -}; -use crate::lock::{Error as LockError, Lock, ReadGuard, WriteGuard}; -use crate::system::Input as SystemInput; -use crate::type_name::TypeName; -use crate::uid::Uid; -use crate::util::Array; -use crate::{EntityComponent, World}; - -pub mod local; - -pub(crate) mod storage; - -pub trait Component: SystemInput + Any + TypeName -{ - /// The component type in question. Will usually be `Self` - type Component: Component - where - Self: Sized; - - type RefMut<'component>: FromOptionalMut<'component> + FromLockedOptional<'component> - where - Self: Sized; - - type Ref<'component>: FromOptional<'component> + FromLockedOptional<'component> - where - Self: Sized; - - /// Returns the ID of this component. - fn id() -> Uid - where - Self: Sized; - - /// The ID of the component `self`. Returns the same value as [`Component::id`]. - fn self_id(&self) -> Uid; - - /// Returns the component UID of a component event for this component. - fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid; - - #[doc(hidden)] - fn as_any_mut(&mut self) -> &mut dyn Any; - - #[doc(hidden)] - fn as_any(&self) -> &dyn Any; - - /// Returns whether the component `self` is optional. - fn self_is_optional(&self) -> bool - { - false - } - - /// Returns whether this component is optional. - #[must_use] - fn is_optional() -> bool - where - Self: Sized, - { - false - } -} - -impl dyn Component -{ - pub fn downcast_mut<Real: 'static>(&mut self) -> Option<&mut Real> - { - self.as_any_mut().downcast_mut() - } - - pub fn downcast_ref<Real: 'static>(&self) -> Option<&Real> - { - self.as_any().downcast_ref() - } - - pub fn is<Other: 'static>(&self) -> bool - { - self.as_any().is::<Other>() - } -} - -impl Debug for dyn Component -{ - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result - { - formatter.debug_struct("Component").finish_non_exhaustive() - } -} - -impl TypeName for Box<dyn Component> -{ - fn type_name(&self) -> &'static str - { - self.as_ref().type_name() - } -} - -impl<ComponentT> Component for Option<ComponentT> -where - ComponentT: Component, - for<'a> Option<ComponentT::Ref<'a>>: FromOptional<'a> + FromLockedOptional<'a>, - for<'a> Option<ComponentT::RefMut<'a>>: FromOptionalMut<'a> + FromLockedOptional<'a>, -{ - type Component = ComponentT; - type Ref<'component> = Option<ComponentT::Ref<'component>>; - type RefMut<'component> = Option<ComponentT::RefMut<'component>>; - - fn id() -> Uid - { - ComponentT::id() - } - - fn self_id(&self) -> Uid - { - Self::id() - } - - fn get_event_uid(&self, event_kind: ComponentEventKind) -> Uid - { - match event_kind { - ComponentEventKind::Removed => ComponentRemovedEvent::<Self>::id(), - } - } - - fn as_any_mut(&mut self) -> &mut dyn Any - { - self - } - - fn as_any(&self) -> &dyn Any - { - self - } - - fn self_is_optional(&self) -> bool - { - true - } - - fn is_optional() -> bool - { - true - } -} - -impl<ComponentT> TypeName for Option<ComponentT> -where - ComponentT: Component, -{ - fn type_name(&self) -> &'static str - { - type_name::<Self>() - } -} - -impl<ComponentT> SystemInput for Option<ComponentT> where ComponentT: Component {} - -/// A sequence of components. -pub trait Sequence -{ - /// The number of components in this component sequence. - const COUNT: usize; - - type Array: Array<Box<dyn Component>>; - - fn into_array(self) -> Self::Array; - - fn metadata() -> impl Array<Metadata>; - - fn added_event_ids() -> Vec<Uid>; - - fn removed_event_ids() -> Vec<Uid>; -} - -/// A sequence of references (immutable or mutable) to components. -pub trait RefSequence -{ - type Handles<'component>; - - type Metadata: Array<Metadata>; - - fn metadata() -> Self::Metadata; - - fn from_components<'component>( - components: &'component [EntityComponent], - component_index_lookup: impl Fn(Uid) -> Option<usize>, - world: &'component World, - ) -> Self::Handles<'component>; -} - -/// A mutable or immutable reference to a component. -pub trait Ref -{ - type Component: Component; - type Handle<'component>: FromLockedOptional<'component>; -} - -impl<ComponentT> Ref for &ComponentT -where - ComponentT: Component, -{ - type Component = ComponentT; - type Handle<'component> = ComponentT::Ref<'component>; -} - -impl<ComponentT> Ref for &mut ComponentT -where - ComponentT: Component, -{ - type Component = ComponentT; - type Handle<'component> = ComponentT::RefMut<'component>; -} - -/// [`Component`] metadata. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub struct Metadata -{ - pub id: Uid, - pub is_optional: bool, -} - -impl Metadata -{ - pub fn get<ComponentT: Component + ?Sized>(component: &ComponentT) -> Self - { - Self { - id: component.self_id(), - is_optional: component.self_is_optional(), - } - } - - pub fn of<ComponentT: Component>() -> Self - { - Self { - id: ComponentT::id(), - is_optional: ComponentT::is_optional(), - } - } -} - -pub trait FromOptionalMut<'comp> -{ - fn from_optional_mut_component( - optional_component: Option<WriteGuard<'comp, Box<dyn Component>>>, - world: &'comp World, - ) -> Self; -} - -pub trait FromOptional<'comp> -{ - fn from_optional_component( - optional_component: Option<ReadGuard<'comp, Box<dyn Component>>>, - world: &'comp World, - ) -> Self; -} - -pub trait FromLockedOptional<'comp>: Sized -{ - fn from_locked_optional_component( - optional_component: Option<&'comp Lock<Box<dyn Component>>>, - world: &'comp World, - ) -> Result<Self, LockError>; -} - -macro_rules! inner { - ($c: tt) => { - seq!(I in 0..=$c { - impl<#(Comp~I: Component,)*> Sequence for (#(Comp~I,)*) - where - #(for<'comp> Comp~I::RefMut<'comp>: FromOptionalMut<'comp>,)* - #(for<'comp> Comp~I::Ref<'comp>: FromOptional<'comp>,)* - { - const COUNT: usize = $c + 1; - - type Array = [Box<dyn Component>; $c + 1]; - - fn into_array(self) -> Self::Array - { - [#(Box::new(self.I) as Box<dyn Component>,)*] - } - - fn metadata() -> impl Array<Metadata> - { - [ - #( - Metadata { - id: Comp~I::id(), - is_optional: Comp~I::is_optional(), - }, - )* - ] - } - - fn added_event_ids() -> Vec<Uid> - { - vec![ - #(ComponentAddedEvent::<Comp~I>::id(),)* - ] - } - - fn removed_event_ids() -> Vec<Uid> - { - vec![ - #(ComponentRemovedEvent::<Comp~I>::id(),)* - ] - } - } - - impl<#(CompRef~I: Ref,)*> RefSequence for (#(CompRef~I,)*) - { - type Handles<'component> = (#(CompRef~I::Handle<'component>,)*); - - type Metadata = [Metadata; $c + 1]; - - fn metadata() -> Self::Metadata - { - [#( - Metadata { - id: CompRef~I::Component::id(), - is_optional: CompRef~I::Component::is_optional(), - }, - )*] - } - - fn from_components<'component>( - components: &'component [EntityComponent], - component_index_lookup: impl Fn(Uid) -> Option<usize>, - world: &'component World, - ) -> Self::Handles<'component> - { - (#( - CompRef~I::Handle::from_locked_optional_component( - component_index_lookup(CompRef~I::Component::id()) - .and_then(|component_index| components.get(component_index)) - .map(|component| &component.component), - world, - ).unwrap_or_else(|err| { - panic!( - "Taking component {} lock failed: {err}", - type_name::<CompRef~I::Component>() - ); - }), - )*) - } - } - }); - }; -} - -seq!(C in 0..=16 { - inner!(C); -}); - -impl Sequence for () -{ - type Array = [Box<dyn Component>; 0]; - - const COUNT: usize = 0; - - fn into_array(self) -> Self::Array - { - [] - } - - fn metadata() -> impl Array<Metadata> - { - [] - } - - fn added_event_ids() -> Vec<Uid> - { - Vec::new() - } - - fn removed_event_ids() -> Vec<Uid> - { - Vec::new() - } -} - -impl RefSequence for () -{ - type Handles<'component> = (); - type Metadata = [Metadata; 0]; - - fn metadata() -> Self::Metadata - { - [] - } - - fn from_components<'component>( - _components: &'component [EntityComponent], - _component_index_lookup: impl Fn(Uid) -> Option<usize>, - _world: &'component World, - ) -> Self::Handles<'component> - { - () - } -} diff --git a/ecs/src/component/local.rs b/ecs/src/component/local.rs deleted file mode 100644 index ad79f6f..0000000 --- a/ecs/src/component/local.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::ops::{Deref, DerefMut}; - -use crate::component::Component; -use crate::system::{ComponentRefMut, Param as SystemParam, System}; -use crate::World; - -/// Holds a component which is local to a single system. -#[derive(Debug)] -pub struct Local<'world, LocalComponent: Component> -{ - local_component: ComponentRefMut<'world, LocalComponent>, -} - -impl<'world, LocalComponent> SystemParam<'world> for Local<'world, LocalComponent> -where - LocalComponent: Component, -{ - type Input = LocalComponent; - - fn initialize<SystemImpl>( - system: &mut impl System<'world, SystemImpl>, - input: Self::Input, - ) - { - system.set_local_component(input); - } - - fn new<SystemImpl>( - system: &'world impl System<'world, SystemImpl>, - _world: &'world World, - ) -> Self - { - let local_component = system - .get_local_component_mut::<LocalComponent>() - .expect("Local component is uninitialized"); - - Self { local_component } - } -} - -impl<'world, LocalComponent> Deref for Local<'world, LocalComponent> -where - LocalComponent: Component, -{ - type Target = LocalComponent; - - fn deref(&self) -> &Self::Target - { - &self.local_component - } -} - -impl<'world, LocalComponent> DerefMut for Local<'world, LocalComponent> -where - LocalComponent: Component, -{ - fn deref_mut(&mut self) -> &mut Self::Target - { - &mut self.local_component - } -} diff --git a/ecs/src/component/storage.rs b/ecs/src/component/storage.rs deleted file mode 100644 index 0475bf1..0000000 --- a/ecs/src/component/storage.rs +++ /dev/null @@ -1,656 +0,0 @@ -use std::any::type_name; -use std::borrow::Borrow; -use std::cell::RefCell; -use std::slice::Iter as SliceIter; -use std::vec::IntoIter as OwnedVecIter; - -use hashbrown::{HashMap, HashSet}; - -use crate::archetype::Id as ArchetypeId; -use crate::component::{Component, Metadata as ComponentMetadata}; -use crate::type_name::TypeName; -use crate::uid::Uid; -use crate::EntityComponent; - -#[derive(Debug, Default)] -pub struct Storage -{ - archetypes: Vec<Archetype>, - archetype_lookup: RefCell<HashMap<ArchetypeId, ArchetypeLookupEntry>>, - entity_archetype_lookup: HashMap<Uid, ArchetypeId>, -} - -impl Storage -{ - pub fn iter_archetypes_with_comps( - &self, - comp_metadata: impl AsRef<[ComponentMetadata]>, - ) -> ArchetypeRefIter<'_> - { - debug_assert!(comp_metadata - .as_ref() - .is_sorted_by_key(|metadata| metadata.id)); - - let archetype_id = ArchetypeId::from_components_metadata(&comp_metadata); - - if !self.archetype_lookup.borrow().contains_key(&archetype_id) { - self.archetype_lookup.borrow_mut().insert( - archetype_id, - self.create_populated_archetype_lookup_entry(comp_metadata.as_ref()), - ); - } - - self.iter_archetypes_by_lookup(archetype_id) - } - - pub fn get_entity_archetype(&self, entity_uid: Uid) -> Option<&Archetype> - { - let archetype_id = self.entity_archetype_lookup.get(&entity_uid)?; - - let archetype_index = self.get_archetype_index_by_id(*archetype_id)?; - - self.archetypes.get(archetype_index) - } - - pub fn remove_entity(&mut self, entity_uid: Uid) - { - let Some(archetype_id) = self.entity_archetype_lookup.get(&entity_uid) else { - return; - }; - - let Some(archetype_index) = self.get_archetype_index_by_id(*archetype_id) else { - return; - }; - - let Some(archetype) = self.archetypes.get_mut(archetype_index) else { - return; - }; - - archetype.take_entity(entity_uid); - - self.entity_archetype_lookup.remove(&entity_uid); - } - - #[tracing::instrument(skip_all)] - pub fn push_entity( - &mut self, - entity_uid: Uid, - mut components: Vec<Box<dyn Component>>, - ) -> Result<(ArchetypeId, Uid), Error> - { - if self.entity_archetype_lookup.contains_key(&entity_uid) { - return Err(Error::EntityAlreadyExists(entity_uid)); - } - - components.sort_by_key(|component| component.self_id()); - tracing::trace!( - "Pushing entity with components: ({})", - &components.iter().fold( - String::with_capacity(components.len() * 25), - |mut acc, component| { - acc.extend([", ", component.type_name()]); - acc - } - )[2..] - ); - - let archetype_id = ArchetypeId::from_components_metadata( - &components - .iter() - .map(|component| ComponentMetadata::get(&**component)) - .collect::<Vec<_>>(), - ); - - let comp_ids_set = create_non_opt_component_id_set( - components - .iter() - .map(|component| ComponentMetadata::get(&**component)), - ); - - let archetype_index = self.get_or_create_archetype(archetype_id, &components); - - self.populate_matching_archetype_lookup_entries(&comp_ids_set, archetype_index); - - let archetype = self - .archetypes - .get_mut(archetype_index) - .expect("Archetype is gone"); - - archetype.push_entity(entity_uid, components); - - self.entity_archetype_lookup - .insert(entity_uid, archetype_id); - - Ok((archetype_id, entity_uid)) - } - - pub fn add_components_to_entity( - &mut self, - entity_uid: Uid, - components: Vec<Box<dyn Component>>, - ) -> Option<()> - { - let archetype_id = self.entity_archetype_lookup.get(&entity_uid)?; - - let archetype_index = self.get_archetype_index_by_id(*archetype_id)?; - - let archetype = self.archetypes.get_mut(archetype_index)?; - - let contains_component_already = components - .iter() - .any(|component| archetype.component_ids.contains_key(&component.self_id())); - - if contains_component_already { - let component_cnt = components.len(); - - // TODO: return error - panic!( - "Entity with UID {:?} already contains one or more component(s) ({})", - entity_uid, - components - .iter() - .flat_map(|component| [component.type_name(), ", "]) - .enumerate() - .take_while(|(index, _)| { *index < (component_cnt * 2) - 1 }) - .map(|(_, component)| component) - .collect::<String>() - ); - } - - let entity = archetype.take_entity(entity_uid)?; - - self.entity_archetype_lookup.remove(&entity_uid); - - self.push_entity( - entity_uid, - entity - .components - .into_iter() - .map(|component| component.component.into_inner()) - .chain(components) - .collect(), - ) - .expect("Not supposed to return Err since the entity is removed"); - - Some(()) - } - - pub fn remove_components_from_entity( - &mut self, - entity_uid: Uid, - component_ids: impl IntoIterator<Item = Uid>, - ) -> Option<()> - { - let archetype_id = self.entity_archetype_lookup.get(&entity_uid)?; - - let archetype_index = self.get_archetype_index_by_id(*archetype_id)?; - - let archetype = self.archetypes.get_mut(archetype_index)?; - - let entity = archetype.take_entity(entity_uid)?; - - let component_ids_set = component_ids.into_iter().collect::<HashSet<_>>(); - - self.entity_archetype_lookup.remove(&entity_uid); - - self.push_entity( - entity_uid, - entity - .components - .into_iter() - .map(|component| component.component.into_inner()) - .filter(|component| !component_ids_set.contains(&component.self_id())) - .collect(), - ) - .expect("Not supposed to return Err since the entity is removed"); - - Some(()) - } - - fn populate_matching_archetype_lookup_entries( - &mut self, - comp_ids_set: &HashSet<Uid>, - archetype_index: usize, - ) - { - let mut archetype_lookup = self.archetype_lookup.borrow_mut(); - - for (_, lookup_entry) in archetype_lookup.iter_mut() { - if &lookup_entry.component_ids == comp_ids_set { - continue; - } - - // There shouldn't be duplicate archetype indices in the lookup entry - if lookup_entry.archetype_indices.contains(&archetype_index) { - continue; - } - - if lookup_entry.component_ids.is_subset(comp_ids_set) { - lookup_entry.archetype_indices.push(archetype_index); - } - } - } - - fn get_or_create_archetype( - &mut self, - archetype_id: ArchetypeId, - components: &[Box<dyn Component>], - ) -> usize - { - let mut archetype_lookup = self.archetype_lookup.borrow_mut(); - - if !archetype_lookup.contains_key(&archetype_id) { - self.archetypes.push(Archetype::new( - components.iter().map(|component| component.self_id()), - )); - } - - let lookup_entry = archetype_lookup.entry(archetype_id).or_insert_with(|| { - self.create_populated_archetype_lookup_entry( - components - .iter() - .map(|component| ComponentMetadata::get(&**component)), - ) - }); - - // SAFETY: Above, we push a archetype index if archetype_indices is empty so this - // cannot fail - unsafe { *lookup_entry.archetype_indices.first().unwrap_unchecked() } - } - - fn get_archetype_index_by_id(&self, archetype_id: ArchetypeId) -> Option<usize> - { - let archetype_lookup = self.archetype_lookup.borrow(); - - let archetype_lookup_entry = archetype_lookup.get(&archetype_id)?; - - let index = *archetype_lookup_entry - .archetype_indices - .first() - .expect("No archetype indices in archetype lookup entry"); - - debug_assert!( - self.archetypes.get(index).is_some_and(|archetype| archetype - .component_ids_is(&archetype_lookup_entry.component_ids)), - "Archetype components is not exact match" - ); - - Some(index) - } - - fn iter_archetypes_by_lookup(&self, archetype_id: ArchetypeId) - -> ArchetypeRefIter<'_> - { - let archetype_lookup = self.archetype_lookup.borrow(); - - // The archetype indices have to be cloned to prevent a panic when query - // iterations are nested. The panic happens because the archetype_lookup RefCell - // is borrowed and it tries to mutably borrow it - let archetype_indices = archetype_lookup - .get(&archetype_id) - .unwrap() - .archetype_indices - .clone(); - - ArchetypeRefIter { - indices: archetype_indices.into_iter(), - archetypes: &self.archetypes, - } - } - - fn create_populated_archetype_lookup_entry<CompMetadataIter>( - &self, - comp_metadata_iter: CompMetadataIter, - ) -> ArchetypeLookupEntry - where - CompMetadataIter: IntoIterator<Item: Borrow<ComponentMetadata>>, - { - let comp_ids_set = create_non_opt_component_id_set(comp_metadata_iter); - - let mut exact_matching_archetype_index = None; - - let matching_archetype_indices = self - .archetypes - .iter() - .enumerate() - .filter_map(|(index, archetype)| { - if archetype.component_ids_is(&comp_ids_set) { - exact_matching_archetype_index = Some(index); - - return None; - } - - if archetype.component_ids_is_superset(&comp_ids_set) { - return Some(index); - } - - None - }) - .collect::<Vec<_>>(); - - ArchetypeLookupEntry { - component_ids: comp_ids_set, - archetype_indices: exact_matching_archetype_index - .into_iter() - .chain(matching_archetype_indices) - .collect(), - } - } -} - -/// Component storage error -#[derive(Debug, Clone, thiserror::Error)] -pub enum Error -{ - #[error("Entity already exists")] - EntityAlreadyExists(Uid), -} - -impl TypeName for Storage -{ - fn type_name(&self) -> &'static str - { - type_name::<Self>() - } -} - -#[derive(Debug)] -struct ArchetypeLookupEntry -{ - component_ids: HashSet<Uid>, - archetype_indices: Vec<usize>, -} - -#[derive(Debug)] -pub struct Archetype -{ - component_ids: HashMap<Uid, usize>, - entity_lookup: HashMap<Uid, usize>, - entity_uid_lookup: Vec<Uid>, - entities: Vec<ArchetypeEntity>, -} - -impl Archetype -{ - fn new(component_ids: impl IntoIterator<Item = Uid>) -> Self - { - Self { - component_ids: component_ids - .into_iter() - .enumerate() - .map(|(index, component_id)| (component_id, index)) - .collect(), - entity_lookup: HashMap::new(), - entity_uid_lookup: Vec::new(), - entities: Vec::new(), - } - } - - pub fn component_ids_is_superset(&self, other_component_ids: &HashSet<Uid>) -> bool - { - if other_component_ids.len() <= self.component_ids.len() { - other_component_ids - .iter() - .all(|v| self.component_ids.contains_key(v)) - } else { - false - } - } - - pub fn component_ids_is(&self, other_component_ids: &HashSet<Uid>) -> bool - { - if other_component_ids.len() == self.component_ids.len() { - other_component_ids - .iter() - .all(|v| self.component_ids.contains_key(v)) - } else { - false - } - } - - pub fn get_entity(&self, entity_uid: Uid) -> Option<&ArchetypeEntity> - { - let entity_index = *self.entity_lookup.get(&entity_uid)?; - - self.entities.get(entity_index) - } - - pub fn entities(&self) -> EntityIter<'_> - { - EntityIter { iter: self.entities.iter() } - } - - pub fn entity_cnt(&self) -> usize - { - self.entities.len() - } - - pub fn get_index_for_component(&self, component_id: Uid) -> Option<usize> - { - self.component_ids.get(&component_id).copied() - } - - fn push_entity( - &mut self, - entity_uid: Uid, - components: impl IntoIterator<Item = Box<dyn Component>>, - ) - { - self.entities.push(ArchetypeEntity { - uid: entity_uid, - components: components.into_iter().map(Into::into).collect(), - }); - - let index = self.entities.len() - 1; - - self.entity_lookup.insert(entity_uid, index); - - self.entity_uid_lookup.push(entity_uid); - } - - pub fn take_entity(&mut self, entity_uid: Uid) -> Option<ArchetypeEntity> - { - let entity_index = self.entity_lookup.remove(&entity_uid)?; - - let last_entity_uid = *self - .entity_uid_lookup - .get(self.entities.len() - 1) - .expect("Entity UID lookup contains too few entity UIDS"); - - // By using swap_remove, no memory reallocation occurs and only one index in the - // entity lookup needs to be updated - let removed_entity = self.entities.swap_remove(entity_index); - - self.entity_lookup.insert(last_entity_uid, entity_index); - - self.entity_uid_lookup.swap_remove(entity_index); - - Some(removed_entity) - } -} - -#[derive(Debug)] -pub struct ArchetypeEntity -{ - uid: Uid, - components: Vec<EntityComponent>, -} - -impl ArchetypeEntity -{ - pub fn uid(&self) -> Uid - { - self.uid - } - - pub fn components(&self) -> &[EntityComponent] - { - &self.components - } - - pub fn get_component(&self, index: usize) -> Option<&EntityComponent> - { - self.components.get(index) - } -} - -#[derive(Debug)] -pub struct ArchetypeRefIter<'component_storage> -{ - indices: OwnedVecIter<usize>, - archetypes: &'component_storage [Archetype], -} - -impl<'component_storage> Iterator for ArchetypeRefIter<'component_storage> -{ - type Item = &'component_storage Archetype; - - fn next(&mut self) -> Option<Self::Item> - { - let archetype_index = self.indices.next()?; - - Some( - self.archetypes - .get(archetype_index) - .expect("Archetype index in archetype lookup entry was not found"), - ) - } -} - -#[derive(Debug)] -pub struct EntityIter<'archetype> -{ - iter: SliceIter<'archetype, ArchetypeEntity>, -} - -impl<'archetype> Iterator for EntityIter<'archetype> -{ - type Item = &'archetype ArchetypeEntity; - - fn next(&mut self) -> Option<Self::Item> - { - self.iter.next() - } -} - -fn create_non_opt_component_id_set<Item>( - component_metadata_iter: impl IntoIterator<Item = Item>, -) -> HashSet<Uid> -where - Item: Borrow<ComponentMetadata>, -{ - component_metadata_iter - .into_iter() - .filter_map(|item| { - let component_metadata = item.borrow(); - - if component_metadata.is_optional { - return None; - } - - Some(component_metadata.id) - }) - .collect::<HashSet<_>>() -} - -#[cfg(test)] -mod tests -{ - - use ecs_macros::Component; - - use super::Storage; - use crate::archetype::Id as ArchetypeId; - use crate::component::{Component, Metadata as ComponentMetadata}; - use crate::uid::{Kind as UidKind, Uid}; - - #[derive(Debug, Component)] - struct HealthPotion - { - _hp_restoration: u32, - } - - #[derive(Debug, Component)] - struct Hookshot - { - _range: u32, - } - - #[derive(Debug, Component)] - struct DekuNut - { - _throwing_damage: u32, - } - - #[derive(Debug, Component)] - struct Bow - { - _damage: u32, - } - - #[derive(Debug, Component)] - struct IronBoots; - - #[test] - fn push_entity_works() - { - let mut component_storage = Storage::default(); - - component_storage - .push_entity( - Uid::new_unique(UidKind::Entity), - vec![ - Box::new(HealthPotion { _hp_restoration: 12 }), - Box::new(Hookshot { _range: 50 }), - ], - ) - .expect("Expected Ok"); - - assert_eq!(component_storage.archetypes.len(), 1); - - let archetype = component_storage - .archetypes - .first() - .expect("Expected a archetype in archetypes Vec"); - - assert_eq!(archetype.component_ids.len(), 2); - - // One entity - assert_eq!(archetype.entities.len(), 1); - - let entity_components = archetype - .entities - .first() - .expect("Expected a entity in archetype"); - - assert_eq!(entity_components.components.len(), 2); - - assert_eq!(component_storage.archetype_lookup.borrow().len(), 1); - - let mut components_metadata = [ - ComponentMetadata { - id: HealthPotion::id(), - is_optional: false, - }, - ComponentMetadata { - id: Hookshot::id(), - is_optional: false, - }, - ]; - - components_metadata.sort_by_key(|comp_metadata| comp_metadata.id); - - let archetype_lookup = component_storage.archetype_lookup.borrow(); - - let lookup_entry = archetype_lookup - .get(&ArchetypeId::from_components_metadata(&components_metadata)) - .expect("Expected entry in archetype lookup map"); - - let first_archetype_index = lookup_entry - .archetype_indices - .first() - .expect("Expected archetype lookup to contain a archetype reference"); - - assert_eq!(*first_archetype_index, 0); - } -} diff --git a/ecs/src/entity.rs b/ecs/src/entity.rs deleted file mode 100644 index 3de9cd5..0000000 --- a/ecs/src/entity.rs +++ /dev/null @@ -1,32 +0,0 @@ -use linkme::distributed_slice; - -use crate::World; - -#[allow(clippy::module_name_repetitions)] -#[macro_export] -macro_rules! static_entity { - ($visibility: vis $ident: ident, $components: expr) => { - $visibility static $ident: ::std::sync::LazyLock<$crate::uid::Uid> = - ::std::sync::LazyLock::new(|| { - $crate::uid::Uid::new_unique($crate::uid::Kind::Entity) - }); - - $crate::private::paste::paste! { - mod [<__ecs_ $ident:lower _static_entity_priv>] { - use super::*; - - #[$crate::private::linkme::distributed_slice( - $crate::entity::CREATE_STATIC_ENTITIES - )] - #[linkme(crate=$crate::private::linkme)] - static CREATE_STATIC_ENTITY: fn(&$crate::World) = |world| { - world.create_entity_with_uid($components, *$ident); - }; - } - } - } -} - -#[distributed_slice] -#[doc(hidden)] -pub static CREATE_STATIC_ENTITIES: [fn(&World)]; diff --git a/ecs/src/event.rs b/ecs/src/event.rs deleted file mode 100644 index 9cea807..0000000 --- a/ecs/src/event.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod component; diff --git a/ecs/src/event/component.rs b/ecs/src/event/component.rs deleted file mode 100644 index b4edffc..0000000 --- a/ecs/src/event/component.rs +++ /dev/null @@ -1,84 +0,0 @@ -//! Component events. - -use std::fmt::{Debug, Formatter}; -use std::marker::PhantomData; - -use ecs_macros::Component; - -use crate::component::Component; - -/// Event emitted when: -/// a) A entity with component `ComponentT` is spawned. -/// b) A component `ComponentT` is added to a entity. -#[derive(Clone, Component)] -pub struct Added<ComponentT> -where - ComponentT: Component, -{ - _pd: PhantomData<ComponentT>, -} - -impl<ComponentT> Debug for Added<ComponentT> -where - ComponentT: Component, -{ - fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result - { - formatter - .debug_struct("Added") - .field("_pd", &self._pd) - .finish() - } -} - -impl<ComponentT> Default for Added<ComponentT> -where - ComponentT: Component, -{ - fn default() -> Self - { - Self { _pd: PhantomData } - } -} - -/// Event emitted when: -/// a) A `ComponentT` component is removed from a entity. -/// b) A entity with component `ComponentT` is despawned. -#[derive(Clone, Component)] -pub struct Removed<ComponentT> -where - ComponentT: Component, -{ - _pd: PhantomData<ComponentT>, -} - -impl<ComponentT> Debug for Removed<ComponentT> -where - ComponentT: Component, -{ - fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result - { - formatter - .debug_struct("Removed") - .field("_pd", &self._pd) - .finish() - } -} - -impl<ComponentT> Default for Removed<ComponentT> -where - ComponentT: Component, -{ - fn default() -> Self - { - Self { _pd: PhantomData } - } -} - -/// Specifies a kind of component event UID. -#[derive(Debug, Clone, Copy)] -#[non_exhaustive] -pub enum Kind -{ - Removed, -} diff --git a/ecs/src/extension.rs b/ecs/src/extension.rs deleted file mode 100644 index 42ebef9..0000000 --- a/ecs/src/extension.rs +++ /dev/null @@ -1,55 +0,0 @@ -use crate::component::Sequence as ComponentSequence; -use crate::sole::Sole; -use crate::system::System; -use crate::uid::Uid; -use crate::{SoleAlreadyExistsError, World}; - -/// A collection of systems, entities & soles that can be added to a [`World`]. -pub trait Extension -{ - fn collect(self, collector: Collector<'_>); -} - -/// Passed to a [`Extension`] to collects it's systems, entities & soles. -pub struct Collector<'world> -{ - world: &'world mut World, -} - -impl<'world> Collector<'world> -{ - /// Returns a new `Collector` for the given [`World`]. - pub fn new(world: &'world mut World) -> Self - { - Self { world } - } - - /// Adds a system to the [`World`]. - pub fn add_system<'this, SystemImpl>( - &'this mut self, - phase_euid: Uid, - system: impl System<'this, SystemImpl>, - ) - { - self.world.register_system(phase_euid, system); - } - - /// Adds a entity to the [`World`]. - pub fn add_entity<Comps>(&mut self, components: Comps) - where - Comps: ComponentSequence, - { - self.world.create_entity(components); - } - - /// Adds a globally shared singleton value to the [`World`]. - /// - /// # Errors - /// Returns `Err` if this [`Sole`] has already been added. - pub fn add_sole<SoleT>(&mut self, sole: SoleT) -> Result<(), SoleAlreadyExistsError> - where - SoleT: Sole, - { - self.world.add_sole(sole) - } -} diff --git a/ecs/src/lib.rs b/ecs/src/lib.rs deleted file mode 100644 index 72b5cf9..0000000 --- a/ecs/src/lib.rs +++ /dev/null @@ -1,654 +0,0 @@ -#![deny(clippy::all, clippy::pedantic)] - -use std::any::{type_name, TypeId}; -use std::cell::RefCell; -use std::fmt::Debug; -use std::mem::ManuallyDrop; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; - -use hashbrown::HashMap; - -use crate::actions::Action; -use crate::component::storage::Storage as ComponentStorage; -use crate::component::{ - Component, - Metadata as ComponentMetadata, - RefSequence as ComponentRefSequence, - Sequence as ComponentSequence, -}; -use crate::entity::CREATE_STATIC_ENTITIES; -use crate::event::component::Kind as ComponentEventKind; -use crate::extension::{Collector as ExtensionCollector, Extension}; -use crate::lock::{Lock, WriteGuard}; -use crate::phase::{Phase, START as START_PHASE}; -use crate::query::flexible::Query as FlexibleQuery; -use crate::query::options::{Not, Options as QueryOptions, With}; -use crate::relationship::{ChildOf, DependsOn, Relationship}; -use crate::sole::Sole; -use crate::stats::Stats; -use crate::system::{System, SystemComponent}; -use crate::type_name::TypeName; -use crate::uid::{Kind as UidKind, Uid}; -use crate::util::Sortable; - -pub mod actions; -pub mod component; -pub mod entity; -pub mod event; -pub mod extension; -pub mod lock; -pub mod phase; -pub mod query; -pub mod relationship; -pub mod sole; -pub mod stats; -pub mod system; -pub mod tuple; -pub mod type_name; -pub mod uid; -pub mod util; - -#[doc(hidden)] -pub mod private; - -mod archetype; - -pub use ecs_macros::{Component, Sole}; - -pub use crate::query::Query; - -#[derive(Debug)] -pub struct World -{ - data: WorldData, - stop: AtomicBool, - is_first_tick: AtomicBool, -} - -impl World -{ - #[must_use] - pub fn new() -> Self - { - let mut world = Self { - data: WorldData::default(), - stop: AtomicBool::new(false), - is_first_tick: AtomicBool::new(false), - }; - - world.add_sole(Stats::default()).ok(); - - for create_static_entity in CREATE_STATIC_ENTITIES { - create_static_entity(&world); - } - - world - } - - /// Creates a new entity with the given components. - /// - /// # Panics - /// Will panic if mutable internal lock cannot be acquired. - pub fn create_entity<Comps>(&mut self, components: Comps) -> Uid - where - Comps: ComponentSequence, - { - let entity_uid = Uid::new_unique(UidKind::Entity); - - self.create_entity_with_uid(components, entity_uid); - - entity_uid - } - - #[tracing::instrument(skip_all)] - #[doc(hidden)] - pub fn create_entity_with_uid<Comps>(&self, components: Comps, entity_uid: Uid) - where - Comps: ComponentSequence, - { - debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - - #[allow(unused_variables)] - if let Err(err) = self - .data - .component_storage - .write_nonblock() - .expect("Failed to acquire read-write component storage lock") - .push_entity(entity_uid, components.into_array().into()) - { - tracing::error!("Failed to create entity: {err}"); - - return; - }; - - for added_event_id in Comps::added_event_ids() { - self.emit_event_by_id(added_event_id); - } - } - - /// Adds a globally shared singleton value. - /// - /// # Errors - /// Returns `Err` if this [`Sole`] has already been added. - pub fn add_sole<SoleT>(&mut self, sole: SoleT) -> Result<(), SoleAlreadyExistsError> - where - SoleT: Sole, - { - self.data.sole_storage.insert(sole) - } - - pub fn register_system<'this, SystemImpl>( - &'this mut self, - phase_euid: Uid, - system: impl System<'this, SystemImpl>, - ) - { - self.create_entity(( - SystemComponent { system: system.into_type_erased() }, - Relationship::<DependsOn, Phase>::new(phase_euid), - )); - } - - pub fn register_observer_system<'this, SystemImpl, Event>( - &'this mut self, - system: impl System<'this, SystemImpl>, - event: Event, - ) where - Event: Component, - { - self.create_entity::<(SystemComponent, Event)>(( - SystemComponent { system: system.into_type_erased() }, - event, - )); - } - - /// Adds a extensions. - /// - /// # Panics - /// Will panic if mutable internal lock cannot be acquired. - pub fn add_extension(&mut self, extension: impl Extension) - { - let extension_collector = ExtensionCollector::new(self); - - extension.collect(extension_collector); - } - - pub fn query<Comps, OptionsT>(&self) -> Query<Comps, OptionsT> - where - Comps: ComponentRefSequence, - OptionsT: QueryOptions, - { - Query::new(self) - } - - pub fn flexible_query<CompMetadata>( - &self, - comp_metadata: CompMetadata, - ) -> FlexibleQuery<CompMetadata> - where - CompMetadata: Sortable<Item = ComponentMetadata> + AsRef<[ComponentMetadata]>, - { - FlexibleQuery::new(self, comp_metadata) - } - - /// Performs a single tick. - /// - /// # Panics - /// Will panic if a internal lock cannot be acquired. - pub fn step(&self) -> StepResult - { - if self.stop.load(Ordering::Relaxed) { - return StepResult::Stop; - } - - if self - .is_first_tick - .compare_exchange(false, true, Ordering::Relaxed, Ordering::Relaxed) - .is_ok() - { - self.query_and_run_systems(*START_PHASE); - } - - self.perform_phases(); - - self.perform_queued_actions(); - - if self.stop.load(Ordering::Relaxed) { - return StepResult::Stop; - } - - let mut stats_lock = self - .data - .sole_storage - .get::<Stats>() - .expect("No stats sole found") - .write_nonblock() - .expect("Failed to aquire read-write stats sole lock"); - - let stats = stats_lock - .downcast_mut::<Stats>() - .expect("Casting stats sole to Stats type failed"); - - stats.current_tick += 1; - - StepResult::Continue - } - - /// Starts a loop which calls [`Self::step`] until the world is stopped. - /// - /// # Panics - /// Will panic if a internal lock cannot be acquired. - pub fn start_loop(&self) - { - while let StepResult::Continue = self.step() {} - } - - fn query_and_run_systems(&self, phase_euid: Uid) - { - let system_comps_query = - self.query::<(&SystemComponent, &Relationship<DependsOn, Phase>), ()>(); - - let system_iter = system_comps_query.iter().filter(|(_, phase_rel)| { - phase_rel - .target_uids() - .any(|target_uid| target_uid == phase_euid) - }); - - for (system_component, _) in system_iter { - // SAFETY: The world lives long enough - unsafe { - system_component.system.run(self); - } - } - } - - fn perform_child_phases(&self, parent_phase_euid: Uid) - { - let phase_query = self.query::<(&Phase, &Relationship<ChildOf, Phase>), ()>(); - - for (child_phase_euid, (_, phase_rel)) in phase_query.iter_with_euids() { - if !phase_rel - .target_uids() - .any(|phase_euid| phase_euid == parent_phase_euid) - { - continue; - } - - self.query_and_run_systems(child_phase_euid); - self.perform_child_phases(child_phase_euid); - } - } - - fn perform_phases(&self) - { - let phase_query = - self.query::<(&Phase,), Not<With<Relationship<ChildOf, Phase>>>>(); - - for (phase_euid, (_,)) in phase_query.iter_with_euids() { - if phase_euid == *START_PHASE { - continue; - } - - self.query_and_run_systems(phase_euid); - self.perform_child_phases(phase_euid); - } - } - - #[tracing::instrument(skip_all)] - fn perform_queued_actions(&self) - { - let mut active_action_queue = match *self.data.action_queue.active_queue.borrow() - { - ActiveActionQueue::A => &self.data.action_queue.queue_a, - ActiveActionQueue::B => &self.data.action_queue.queue_b, - } - .write_nonblock() - .unwrap_or_else(|err| { - panic!( - "Failed to take read-write action queue lock {:?}: {err}", - self.data.action_queue.active_queue - ); - }); - - let mut has_swapped_active_queue = false; - - for action in active_action_queue.drain(..) { - match action { - Action::Spawn(components, component_added_event_ids) => { - let mut component_storage_lock = self.lock_component_storage_rw(); - - #[allow(unused_variables)] - if let Err(err) = component_storage_lock - .push_entity(Uid::new_unique(UidKind::Entity), components) - { - tracing::error!("Failed to create entity: {err}"); - - continue; - } - - drop(component_storage_lock); - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - for comp_added_event_id in component_added_event_ids.ids { - self.emit_event_by_id(comp_added_event_id); - } - } - Action::Despawn(entity_uid) => { - self.despawn_entity(entity_uid, &mut has_swapped_active_queue); - } - Action::AddComponents( - entity_uid, - components, - component_added_event_ids, - ) => { - let mut component_storage_lock = self.lock_component_storage_rw(); - - component_storage_lock - .add_components_to_entity(entity_uid, components); - - drop(component_storage_lock); - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - for comp_added_event_id in component_added_event_ids.ids { - self.emit_event_by_id(comp_added_event_id); - } - } - Action::RemoveComponents( - entity_uid, - components_metadata, - component_removed_event_ids, - ) => { - let mut component_storage_lock = self.lock_component_storage_rw(); - - component_storage_lock.remove_components_from_entity( - entity_uid, - components_metadata - .iter() - .map(|component_metadata| component_metadata.id), - ); - - drop(component_storage_lock); - - if !has_swapped_active_queue { - self.swap_event_queue(&mut has_swapped_active_queue); - } - - for comp_removed_event_id in component_removed_event_ids.ids { - self.emit_event_by_id(comp_removed_event_id); - } - } - Action::Stop => { - self.stop.store(true, Ordering::Relaxed); - } - } - } - } - - fn despawn_entity(&self, entity_uid: Uid, has_swapped_active_queue: &mut bool) - { - let mut component_storage_lock = self.lock_component_storage_rw(); - - let Some(archetype) = component_storage_lock.get_entity_archetype(entity_uid) - else { - tracing::error!("No archetype for entity {entity_uid:?} was found"); - - return; - }; - - let entity = archetype - .get_entity(entity_uid) - .expect("Entity archetype was found but the entity is not in the archetype"); - - let component_removed_event_uids = entity - .components() - .iter() - .map(|component| { - component - .component - .read_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to acquire read-only {} component lock", - component.name - ) - }) - .get_event_uid(ComponentEventKind::Removed) - }) - .collect::<Vec<_>>(); - - component_storage_lock.remove_entity(entity_uid); - - drop(component_storage_lock); - - if !*has_swapped_active_queue { - self.swap_event_queue(has_swapped_active_queue); - } - - for comp_removed_event_id in component_removed_event_uids { - self.emit_event_by_id(comp_removed_event_id); - } - } - - fn emit_event_by_id(&self, event_id: Uid) - { - let query = self.flexible_query([ - ComponentMetadata::of::<SystemComponent>(), - ComponentMetadata { id: event_id, is_optional: false }, - ]); - - for (system,) in query - .iter::<()>() - .into_component_iter::<(&SystemComponent,)>(self) - { - unsafe { - system.system.run(self); - } - } - } - - fn swap_event_queue(&self, has_swapped_active_queue: &mut bool) - { - let mut active_queue = self.data.action_queue.active_queue.borrow_mut(); - - *active_queue = match *active_queue { - ActiveActionQueue::A => ActiveActionQueue::B, - ActiveActionQueue::B => ActiveActionQueue::A, - }; - - *has_swapped_active_queue = true; - } - - fn lock_component_storage_rw(&self) -> WriteGuard<'_, ComponentStorage> - { - self.data - .component_storage - .write_nonblock() - .expect("Failed to acquire read-write component storage lock") - } -} - -impl Default for World -{ - fn default() -> Self - { - Self::new() - } -} - -/// The result of calling [`World::step`]. -pub enum StepResult -{ - /// Another step can be made. - Continue, - - /// The world have been stopped so no step can be made again. - Stop, -} - -#[derive(Debug, Default)] -pub struct WorldData -{ - component_storage: Arc<Lock<ComponentStorage>>, - sole_storage: SoleStorage, - action_queue: Arc<ActionQueue>, -} - -#[derive(Debug)] -#[non_exhaustive] -pub struct EntityComponent -{ - pub id: Uid, - pub name: &'static str, - pub component: Lock<Box<dyn Component>>, -} - -impl From<Box<dyn Component>> for EntityComponent -{ - fn from(component: Box<dyn Component>) -> Self - { - Self { - id: component.self_id(), - name: component.type_name(), - component: Lock::new(component), - } - } -} - -#[derive(Debug, Default, Clone, Copy)] -enum ActiveActionQueue -{ - #[default] - A, - B, -} - -#[derive(Debug, Default)] -struct ActionQueue -{ - queue_a: Lock<Vec<Action>>, - queue_b: Lock<Vec<Action>>, - active_queue: RefCell<ActiveActionQueue>, -} - -impl ActionQueue -{ - fn push(&self, action: Action) - { - match *self.active_queue.borrow() { - ActiveActionQueue::A => self - .queue_a - .write_nonblock() - .expect("Failed to aquire read-write action queue A lock") - .push(action), - ActiveActionQueue::B => self - .queue_b - .write_nonblock() - .expect("Failed to aquire read-write action queue A lock") - .push(action), - } - } -} - -impl TypeName for ActionQueue -{ - fn type_name(&self) -> &'static str - { - type_name::<Self>() - } -} - -#[derive(Debug, thiserror::Error)] -#[error("Sole {0} already exists")] -pub struct SoleAlreadyExistsError(pub &'static str); - -#[derive(Debug)] -struct StoredSole -{ - sole: Arc<Lock<Box<dyn Sole>>>, - drop_last: bool, -} - -#[derive(Debug, Default)] -struct SoleStorage -{ - storage: HashMap<TypeId, ManuallyDrop<StoredSole>>, -} - -impl SoleStorage -{ - fn get<SoleT: Sole>(&self) -> Option<&Arc<Lock<Box<dyn Sole>>>> - { - self.storage - .get(&TypeId::of::<SoleT>()) - .map(|sole| &sole.sole) - } - - fn insert<SoleT: Sole>(&mut self, sole: SoleT) -> Result<(), SoleAlreadyExistsError> - { - let sole_type_id = TypeId::of::<SoleT>(); - - if self.storage.contains_key(&sole_type_id) { - return Err(SoleAlreadyExistsError(type_name::<SoleT>())); - } - - let drop_last = sole.drop_last(); - - // TODO: Reconsider this maybe? - #[allow(clippy::arc_with_non_send_sync)] - self.storage.insert( - sole_type_id, - ManuallyDrop::new(StoredSole { - sole: Arc::new(Lock::new(Box::new(sole))), - drop_last, - }), - ); - - Ok(()) - } -} - -impl Drop for SoleStorage -{ - fn drop(&mut self) - { - let mut soles_to_drop_last = Vec::new(); - - for sole in self.storage.values_mut() { - if sole.drop_last { - tracing::trace!( - "Sole {} pushed to dropping last queue", - sole.sole.read_nonblock().unwrap().type_name() - ); - - soles_to_drop_last.push(sole); - continue; - } - tracing::trace!( - "Dropping sole {}", - sole.sole.read_nonblock().unwrap().type_name() - ); - - unsafe { - ManuallyDrop::drop(sole); - } - } - - for sole in &mut soles_to_drop_last { - tracing::trace!( - "Dropping sole {} last", - sole.sole.read_nonblock().unwrap().type_name() - ); - - unsafe { - ManuallyDrop::drop(sole); - } - } - } -} diff --git a/ecs/src/lock.rs b/ecs/src/lock.rs deleted file mode 100644 index c700098..0000000 --- a/ecs/src/lock.rs +++ /dev/null @@ -1,272 +0,0 @@ -use std::mem::{forget, transmute}; -use std::ops::{Deref, DerefMut}; - -use parking_lot::{ - MappedRwLockReadGuard, - MappedRwLockWriteGuard, - RwLock, - RwLockReadGuard, - RwLockWriteGuard, -}; - -use crate::type_name::TypeName; - -#[derive(Debug, Default)] -pub struct Lock<Value> -where - Value: TypeName, -{ - inner: RwLock<Value>, -} - -impl<Value> Lock<Value> -where - Value: TypeName, -{ - pub fn new(value: Value) -> Self - { - Self { inner: RwLock::new(value) } - } - - /// Tries to a acquire a handle to the resource with read access. - /// - /// # Errors - /// Returns `Err` if unavailable (A mutable handle is hold). - pub fn read_nonblock(&self) -> Result<ReadGuard<Value>, Error> - { - let guard = self.inner.try_read().ok_or(Error::ReadUnavailable)?; - - tracing::trace!("Acquired lock to value of type {}", guard.type_name()); - - Ok(ReadGuard { inner: guard }) - } - - /// Tries to a acquire a handle to the resource with mutable access. - /// - /// # Errors - /// Returns `Err` if unavailable (A mutable or immutable handle is hold). - pub fn write_nonblock(&self) -> Result<WriteGuard<Value>, Error> - { - let guard = self.inner.try_write().ok_or(Error::WriteUnavailable)?; - - tracing::trace!( - "Acquired mutable lock to value of type {}", - guard.type_name() - ); - - Ok(WriteGuard { inner: guard }) - } - - pub fn into_inner(self) -> Value - { - self.inner.into_inner() - } -} - -#[derive(Debug, thiserror::Error)] -pub enum Error -{ - #[error("Lock is unavailable for reading")] - ReadUnavailable, - - #[error("Lock is unavailable for writing")] - WriteUnavailable, -} - -#[derive(Debug)] -pub struct ReadGuard<'guard, Value> -where - Value: TypeName, -{ - inner: RwLockReadGuard<'guard, Value>, -} - -impl<'guard, Value> ReadGuard<'guard, Value> -where - Value: TypeName, -{ - pub fn map<NewValue>( - self, - func: impl FnOnce(&Value) -> &NewValue, - ) -> MappedReadGuard<'guard, NewValue> - where - NewValue: TypeName, - { - // The 'inner' field cannot be moved out of ReadGuard in a normal way since - // ReadGuard implements Drop - let inner = unsafe { std::ptr::read(&self.inner) }; - forget(self); - - MappedReadGuard { - inner: RwLockReadGuard::map(inner, func), - } - } - - /// Converts the `ReadGuard` to a `ReadGuard` with a possibly longer lifetime. - /// - /// # Safety - /// The returned `ReadGuard` must **NOT** be used for longer than the original - /// lifetime. - #[must_use] - pub unsafe fn upgrade_lifetime<'new>(self) -> ReadGuard<'new, Value> - { - unsafe { transmute(self) } - } -} - -impl<'guard, Value> Deref for ReadGuard<'guard, Value> -where - Value: TypeName, -{ - type Target = Value; - - fn deref(&self) -> &Self::Target - { - &self.inner - } -} - -impl<'guard, Value> Drop for ReadGuard<'guard, Value> -where - Value: TypeName, -{ - fn drop(&mut self) - { - tracing::trace!("Dropped lock to value of type {}", self.type_name()); - } -} - -#[derive(Debug)] -pub struct MappedReadGuard<'guard, Value> -where - Value: TypeName, -{ - inner: MappedRwLockReadGuard<'guard, Value>, -} - -impl<'guard, Value> Deref for MappedReadGuard<'guard, Value> -where - Value: TypeName, -{ - type Target = Value; - - fn deref(&self) -> &Self::Target - { - &self.inner - } -} - -impl<'guard, Value> Drop for MappedReadGuard<'guard, Value> -where - Value: TypeName, -{ - fn drop(&mut self) - { - tracing::trace!("Dropped mapped lock to value of type {}", self.type_name()); - } -} - -#[derive(Debug)] -pub struct WriteGuard<'guard, Value> -where - Value: TypeName, -{ - inner: RwLockWriteGuard<'guard, Value>, -} - -impl<'guard, Value> WriteGuard<'guard, Value> -where - Value: TypeName, -{ - pub fn map<NewValue>( - self, - func: impl FnOnce(&mut Value) -> &mut NewValue, - ) -> MappedWriteGuard<'guard, NewValue> - where - NewValue: TypeName, - { - // The 'inner' field cannot be moved out of ReadGuard in a normal way since - // ReadGuard implements Drop - let inner = unsafe { std::ptr::read(&self.inner) }; - forget(self); - - MappedWriteGuard { - inner: RwLockWriteGuard::map(inner, func), - } - } -} - -impl<'guard, Value> Deref for WriteGuard<'guard, Value> -where - Value: TypeName, -{ - type Target = Value; - - fn deref(&self) -> &Self::Target - { - &self.inner - } -} - -impl<'guard, Value> DerefMut for WriteGuard<'guard, Value> -where - Value: TypeName, -{ - fn deref_mut(&mut self) -> &mut Self::Target - { - &mut self.inner - } -} - -impl<'guard, Value> Drop for WriteGuard<'guard, Value> -where - Value: TypeName, -{ - fn drop(&mut self) - { - tracing::trace!("Dropped mutable lock to value of type {}", self.type_name()); - } -} - -#[derive(Debug)] -pub struct MappedWriteGuard<'guard, Value> -where - Value: TypeName, -{ - inner: MappedRwLockWriteGuard<'guard, Value>, -} - -impl<'guard, Value> Deref for MappedWriteGuard<'guard, Value> -where - Value: TypeName, -{ - type Target = Value; - - fn deref(&self) -> &Self::Target - { - &self.inner - } -} - -impl<'guard, Value> DerefMut for MappedWriteGuard<'guard, Value> -where - Value: TypeName, -{ - fn deref_mut(&mut self) -> &mut Self::Target - { - &mut self.inner - } -} - -impl<'guard, Value> Drop for MappedWriteGuard<'guard, Value> -where - Value: TypeName, -{ - fn drop(&mut self) - { - tracing::trace!( - "Dropped mapped mutable lock to value of type {}", - self.type_name() - ); - } -} diff --git a/ecs/src/phase.rs b/ecs/src/phase.rs deleted file mode 100644 index b8660f2..0000000 --- a/ecs/src/phase.rs +++ /dev/null @@ -1,15 +0,0 @@ -use ecs_macros::Component; - -use crate::relationship::{ChildOf, Relationship}; -use crate::static_entity; - -#[derive(Debug, Default, Clone, Copy, Component)] -pub struct Phase; - -static_entity!(pub START, (Phase,)); - -static_entity!(pub PRE_UPDATE, (Phase,)); - -static_entity!(pub UPDATE, (Phase, <Relationship<ChildOf, Phase>>::new(*PRE_UPDATE))); - -static_entity!(pub PRESENT, (Phase, <Relationship<ChildOf, Phase>>::new(*UPDATE))); diff --git a/ecs/src/private.rs b/ecs/src/private.rs deleted file mode 100644 index 56a6552..0000000 --- a/ecs/src/private.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[doc(hidden)] -pub use {linkme, paste}; diff --git a/ecs/src/query.rs b/ecs/src/query.rs deleted file mode 100644 index ca9345c..0000000 --- a/ecs/src/query.rs +++ /dev/null @@ -1,215 +0,0 @@ -use std::marker::PhantomData; - -use crate::component::RefSequence as ComponentRefSequence; -use crate::query::flexible::{ - EntityHandle, - Iter as FlexibleQueryIter, - Query as FlexibleQuery, -}; -use crate::query::options::Options; -use crate::system::{Param as SystemParam, System}; -use crate::uid::Uid; -use crate::World; - -pub mod flexible; -pub mod options; - -#[derive(Debug)] -pub struct Query<'world, Comps, OptionsT = ()> -where - Comps: ComponentRefSequence, -{ - world: &'world World, - inner: FlexibleQuery<'world, Comps::Metadata>, - _pd: PhantomData<(Comps, OptionsT)>, -} - -impl<'world, Comps, OptionsT> Query<'world, Comps, OptionsT> -where - Comps: ComponentRefSequence, - OptionsT: Options, -{ - /// Iterates over the entities matching this query, the iterator item being the entity - /// components. - #[must_use] - pub fn iter<'query>( - &'query self, - ) -> ComponentIter<'query, 'world, Comps, FlexibleQueryIter<'query>> - { - tracing::trace!("Searching for {}", std::any::type_name::<Comps>()); - - ComponentIter { - world: self.world, - iter: self.inner.iter::<OptionsT>(), - comps_pd: PhantomData, - } - } - - /// Iterates over the entities matching this query, the iterator item being the entity - /// [`Uid`] and the entity components. - #[must_use] - pub fn iter_with_euids<'query>( - &'query self, - ) -> ComponentAndEuidIter<'query, 'world, Comps, FlexibleQueryIter<'query>> - { - tracing::trace!("Searching for {}", std::any::type_name::<Comps>()); - - ComponentAndEuidIter { - world: self.world, - iter: self.inner.iter::<OptionsT>(), - comps_pd: PhantomData, - } - } - - /// Iterates over the entities matching this query using the iterator returned by - /// `func`. - /// - /// This function exists so that a custom [`EntityHandle`] iterator can be given to - /// [`ComponentIter`] without giving the user access to a reference to the [`World`]. - #[must_use] - pub fn iter_with<'query, OutIter>( - &'query self, - func: impl FnOnce(FlexibleQueryIter<'query>) -> OutIter, - ) -> ComponentIter<'query, 'world, Comps, OutIter> - where - OutIter: Iterator<Item = EntityHandle<'query>>, - { - tracing::trace!("Searching for {}", std::any::type_name::<Comps>()); - - ComponentIter { - world: self.world, - iter: func(self.inner.iter::<OptionsT>()), - comps_pd: PhantomData, - } - } - - /// Returns the UID of the entity at the given query iteration index. - #[must_use] - pub fn get_entity_uid(&self, entity_index: usize) -> Option<Uid> - { - Some(self.inner.iter::<OptionsT>().nth(entity_index)?.uid()) - } - - pub(crate) fn new(world: &'world World) -> Self - { - Self { - world, - inner: world.flexible_query(Comps::metadata()), - _pd: PhantomData, - } - } -} - -impl<'query, 'world, Comps, OptionsT> IntoIterator - for &'query Query<'world, Comps, OptionsT> -where - Comps: ComponentRefSequence + 'world, - OptionsT: Options, -{ - type IntoIter = ComponentIter<'query, 'world, Comps, FlexibleQueryIter<'query>>; - type Item = Comps::Handles<'query>; - - fn into_iter(self) -> Self::IntoIter - { - self.iter() - } -} - -impl<'world, Comps, OptionsT> SystemParam<'world> for Query<'world, Comps, OptionsT> -where - Comps: ComponentRefSequence, - OptionsT: Options, -{ - type Input = (); - - fn initialize<SystemImpl>( - _system: &mut impl System<'world, SystemImpl>, - _input: Self::Input, - ) - { - } - - fn new<SystemImpl>( - _system: &'world impl System<'world, SystemImpl>, - world: &'world World, - ) -> Self - { - Self::new(world) - } -} - -pub struct ComponentIter<'query, 'world, Comps, EntityHandleIter> -where - EntityHandleIter: Iterator<Item = EntityHandle<'query>>, -{ - world: &'world World, - iter: EntityHandleIter, - comps_pd: PhantomData<Comps>, -} - -impl<'query, 'world, Comps, EntityHandleIter> - ComponentIter<'query, 'world, Comps, EntityHandleIter> -where - Comps: ComponentRefSequence + 'world, - EntityHandleIter: Iterator<Item = EntityHandle<'query>>, - 'world: 'query, -{ - pub(crate) fn new(world: &'world World, iter: EntityHandleIter) -> Self - { - Self { world, iter, comps_pd: PhantomData } - } -} - -impl<'query, 'world, Comps, EntityHandleIter> Iterator - for ComponentIter<'query, 'world, Comps, EntityHandleIter> -where - Comps: ComponentRefSequence + 'world, - EntityHandleIter: Iterator<Item = EntityHandle<'query>>, - 'world: 'query, -{ - type Item = Comps::Handles<'query>; - - fn next(&mut self) -> Option<Self::Item> - { - let entity_handle = self.iter.next()?; - - Some(Comps::from_components( - entity_handle.components(), - |component_uid| entity_handle.get_component_index(component_uid), - self.world, - )) - } -} - -pub struct ComponentAndEuidIter<'query, 'world, Comps, EntityHandleIter> -where - EntityHandleIter: Iterator<Item = EntityHandle<'query>>, -{ - world: &'world World, - iter: EntityHandleIter, - comps_pd: PhantomData<Comps>, -} - -impl<'query, 'world, Comps, EntityHandleIter> Iterator - for ComponentAndEuidIter<'query, 'world, Comps, EntityHandleIter> -where - Comps: ComponentRefSequence + 'world, - EntityHandleIter: Iterator<Item = EntityHandle<'query>>, - 'world: 'query, -{ - type Item = (Uid, Comps::Handles<'query>); - - fn next(&mut self) -> Option<Self::Item> - { - let entity_handle = self.iter.next()?; - - Some(( - entity_handle.uid(), - Comps::from_components( - entity_handle.components(), - |component_uid| entity_handle.get_component_index(component_uid), - self.world, - ), - )) - } -} diff --git a/ecs/src/query/flexible.rs b/ecs/src/query/flexible.rs deleted file mode 100644 index 5c23e68..0000000 --- a/ecs/src/query/flexible.rs +++ /dev/null @@ -1,145 +0,0 @@ -//! Low-level querying. -use std::iter::{repeat_n, Filter, Flatten, Map, RepeatN, Zip}; - -use crate::component::storage::{ - Archetype, - ArchetypeEntity, - ArchetypeRefIter, - EntityIter, - Storage as ComponentStorage, -}; -use crate::component::{ - Metadata as ComponentMetadata, - RefSequence as ComponentRefSequence, -}; -use crate::lock::ReadGuard; -use crate::query::options::Options; -use crate::query::ComponentIter; -use crate::uid::Uid; -use crate::util::Sortable; -use crate::{EntityComponent, World}; - -/// Low-level entity query structure. -#[derive(Debug)] -pub struct Query<'world, CompMetadata> -where - CompMetadata: Sortable<Item = ComponentMetadata> + AsRef<[ComponentMetadata]>, -{ - component_storage: ReadGuard<'world, ComponentStorage>, - comp_metadata: CompMetadata, -} - -impl<'world, CompMetadata> Query<'world, CompMetadata> -where - CompMetadata: Sortable<Item = ComponentMetadata> + AsRef<[ComponentMetadata]>, -{ - /// Iterates over the entities matching this query. - #[must_use] - pub fn iter<'query, OptionsT: Options>(&'query self) -> Iter<'query> - { - Iter { - iter: self - .component_storage - .iter_archetypes_with_comps(&self.comp_metadata) - .map( - (|archetype| { - repeat_n(archetype, archetype.entity_cnt()) - .zip(archetype.entities()) - }) as ComponentIterMapFn, - ) - .flatten() - .filter(|(_, entity)| OptionsT::entity_filter(entity.components())), - } - } - - pub(crate) fn new(world: &'world World, mut comp_metadata: CompMetadata) -> Self - { - comp_metadata.sort_by_key_b(|metadata| metadata.id); - - Self { - component_storage: world - .data - .component_storage - .read_nonblock() - .expect("Failed to acquire read-only component storage lock"), - comp_metadata, - } - } -} - -pub struct Iter<'query> -{ - iter: QueryEntityIter<'query>, -} - -impl<'query> Iter<'query> -{ - /// Converts this iterator into a [`ComponentIter`]. - /// - /// Note: The matching entities of this iterator should have all of the non-[`Option`] - /// components in `Comps`, otherwise iterating the [`ComponentIter`] will cause a - /// panic. - #[must_use] - #[inline] - pub fn into_component_iter<'world, Comps>( - self, - world: &'world World, - ) -> ComponentIter<'query, 'world, Comps, Self> - where - Comps: ComponentRefSequence + 'world, - 'world: 'query, - { - ComponentIter::new(world, self) - } -} - -impl<'query> Iterator for Iter<'query> -{ - type Item = EntityHandle<'query>; - - fn next(&mut self) -> Option<Self::Item> - { - let (archetype, entity) = self.iter.next()?; - - Some(EntityHandle { archetype, entity }) - } -} - -pub struct EntityHandle<'query> -{ - archetype: &'query Archetype, - entity: &'query ArchetypeEntity, -} - -impl<'query> EntityHandle<'query> -{ - /// Returns the [`Uid`] of this entity. - #[inline] - pub fn uid(&self) -> Uid - { - self.entity.uid() - } - - #[inline] - pub fn components(&self) -> &'query [EntityComponent] - { - self.entity.components() - } - - #[inline] - pub fn get_component_index(&self, component_uid: Uid) -> Option<usize> - { - self.archetype.get_index_for_component(component_uid) - } -} - -type ComponentIterMapFn = - for<'a> fn(&'a Archetype) -> Zip<RepeatN<&'a Archetype>, EntityIter<'a>>; - -type ComponentIterFilterFn = - for<'a, 'b> fn(&'a (&'b Archetype, &'b ArchetypeEntity)) -> bool; - -type QueryEntityIter<'query> = Filter< - Flatten<Map<ArchetypeRefIter<'query>, ComponentIterMapFn>>, - ComponentIterFilterFn, ->; diff --git a/ecs/src/query/options.rs b/ecs/src/query/options.rs deleted file mode 100644 index 772d091..0000000 --- a/ecs/src/query/options.rs +++ /dev/null @@ -1,59 +0,0 @@ -use std::marker::PhantomData; - -use hashbrown::HashSet; - -use crate::component::Component; -use crate::EntityComponent; - -/// Query options. -pub trait Options -{ - fn entity_filter<'component>(components: &'component [EntityComponent]) -> bool; -} - -impl Options for () -{ - fn entity_filter<'component>(_components: &'component [EntityComponent]) -> bool - { - true - } -} - -pub struct With<ComponentT> -where - ComponentT: Component, -{ - _pd: PhantomData<ComponentT>, -} - -impl<ComponentT> Options for With<ComponentT> -where - ComponentT: Component, -{ - fn entity_filter<'component>(components: &'component [EntityComponent]) -> bool - { - let ids_set = components - .into_iter() - .map(|component| component.id) - .collect::<HashSet<_>>(); - - ids_set.contains(&ComponentT::id()) - } -} - -pub struct Not<OptionsT> -where - OptionsT: Options, -{ - _pd: PhantomData<OptionsT>, -} - -impl<OptionsT> Options for Not<OptionsT> -where - OptionsT: Options, -{ - fn entity_filter<'component>(components: &'component [EntityComponent]) -> bool - { - !OptionsT::entity_filter(components) - } -} diff --git a/ecs/src/relationship.rs b/ecs/src/relationship.rs deleted file mode 100644 index 143b589..0000000 --- a/ecs/src/relationship.rs +++ /dev/null @@ -1,538 +0,0 @@ -use std::any::type_name; -use std::marker::PhantomData; - -use ecs_macros::Component; - -use crate::component::storage::Storage as ComponentStorage; -use crate::component::{ - Component, - FromLockedOptional as FromLockedOptionalComponent, - FromOptional as FromOptionalComponent, - FromOptionalMut as FromOptionalMutComponent, -}; -use crate::lock::{Error as LockError, Lock, ReadGuard, WriteGuard}; -use crate::system::{ComponentRef, ComponentRefMut}; -use crate::uid::{Kind as UidKind, Uid}; -use crate::World; - -/// A relationship to one or more targets. -#[derive(Debug, Component)] -#[component( - ref_type = Relation<'component, Kind, ComponentT>, - ref_mut_type = RelationMut<'component, Kind, ComponentT>, -)] -pub struct Relationship<Kind, ComponentT: Component> -where - Kind: 'static, -{ - entity_uid: SingleOrMultiple<Uid>, - _pd: PhantomData<(Kind, ComponentT)>, -} - -impl<Kind, ComponentT> Relationship<Kind, ComponentT> -where - ComponentT: Component, -{ - /// Creates a new `Relationship` with a single target. - #[must_use] - pub fn new(entity_uid: Uid) -> Self - { - debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - - Self { - entity_uid: SingleOrMultiple::Single(entity_uid), - _pd: PhantomData, - } - } - - /// Creates a new `Relationship` with multiple targets. - #[must_use] - pub fn new_multiple(entity_uids: impl IntoIterator<Item = Uid>) -> Self - { - let uids = entity_uids.into_iter().collect::<Vec<_>>(); - - for euid in &uids { - debug_assert_eq!(euid.kind(), UidKind::Entity); - } - - Self { - entity_uid: SingleOrMultiple::Multiple(uids), - _pd: PhantomData, - } - } -} - -pub struct RelationMut<'rel_comp, Kind, ComponentT> -where - Kind: 'static, - ComponentT: Component, -{ - component_storage_lock: ReadGuard<'static, ComponentStorage>, - relationship_comp: ComponentRefMut<'rel_comp, Relationship<Kind, ComponentT>>, -} - -impl<'rel_comp, Kind, ComponentT> FromOptionalMutComponent<'rel_comp> - for RelationMut<'rel_comp, Kind, ComponentT> -where - ComponentT: Component, -{ - fn from_optional_mut_component( - optional_component: Option< - crate::lock::WriteGuard<'rel_comp, Box<dyn Component>>, - >, - world: &'rel_comp World, - ) -> Self - { - let relationship_comp = - ComponentRefMut::<Relationship<Kind, ComponentT>>::from_optional_mut_component( - optional_component, - world, - ); - - let component_storage_lock = world - .data - .component_storage - .read_nonblock() - .expect("Failed to aquire read-only component storage lock"); - - Self { - relationship_comp, - // SAFETY: The component lock is not used for longer than the original - // lifetime - component_storage_lock: unsafe { component_storage_lock.upgrade_lifetime() }, - } - } -} - -impl<'rel_comp, Kind, ComponentT> FromOptionalMutComponent<'rel_comp> - for Option<RelationMut<'rel_comp, Kind, ComponentT>> -where - ComponentT: Component, -{ - fn from_optional_mut_component( - optional_component: Option<WriteGuard<'rel_comp, Box<dyn Component>>>, - world: &'rel_comp World, - ) -> Self - { - optional_component.map(|component| { - RelationMut::from_optional_mut_component(Some(component), world) - }) - } -} - -impl<'rel_comp, Kind, ComponentT> FromLockedOptionalComponent<'rel_comp> - for RelationMut<'rel_comp, Kind, ComponentT> -where - ComponentT: Component, -{ - fn from_locked_optional_component( - optional_component: Option<&'rel_comp crate::lock::Lock<Box<dyn Component>>>, - world: &'rel_comp World, - ) -> Result<Self, LockError> - { - Ok(Self::from_optional_mut_component( - optional_component - .map(|lock| lock.write_nonblock()) - .transpose()?, - world, - )) - } -} - -impl<'rel_comp, Kind, ComponentT> FromLockedOptionalComponent<'rel_comp> - for Option<RelationMut<'rel_comp, Kind, ComponentT>> -where - ComponentT: Component, -{ - fn from_locked_optional_component( - optional_component: Option<&'rel_comp Lock<Box<dyn Component>>>, - world: &'rel_comp World, - ) -> Result<Self, crate::lock::Error> - { - optional_component - .map(|component| { - RelationMut::from_locked_optional_component(Some(component), world) - }) - .transpose() - } -} - -impl<'rel_comp, Kind, ComponentT> RelationMut<'rel_comp, Kind, ComponentT> -where - ComponentT: Component, -{ - /// Returns the component of the target at the specified index. - /// - /// # Panics - /// Will panic if the entity does not exist in the archetype it belongs to. This - /// should hopefully never happend. - #[must_use] - pub fn get(&self, index: usize) -> Option<ComponentRefMut<'_, ComponentT>> - { - let target = self.get_target(index)?; - - let archetype = self.component_storage_lock.get_entity_archetype(*target)?; - - let entity = archetype - .get_entity(*target) - .expect("Target entity is gone from archetype"); - - let component_index = archetype.get_index_for_component(ComponentT::id())?; - - let component = ComponentRefMut::new( - entity - .get_component(component_index)? - .component - .write_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to aquire read-write lock of component {}", - type_name::<ComponentT>() - ) - }), - ); - - Some(component) - } - - /// Returns a reference to the target at the specified index. - #[must_use] - pub fn get_target(&self, index: usize) -> Option<&Uid> - { - match &self.relationship_comp.entity_uid { - SingleOrMultiple::Single(entity_uid) if index == 0 => Some(entity_uid), - SingleOrMultiple::Multiple(entity_uids) => entity_uids.get(index), - SingleOrMultiple::Single(_) => None, - } - } - - /// Returns a mutable reference to the target at the specified index. - #[must_use] - pub fn get_target_mut(&mut self, index: usize) -> Option<&mut Uid> - { - match &mut self.relationship_comp.entity_uid { - SingleOrMultiple::Single(entity_uid) if index == 0 => Some(entity_uid), - SingleOrMultiple::Multiple(entity_uids) => entity_uids.get_mut(index), - SingleOrMultiple::Single(_) => None, - } - } - - /// Adds a target to the relationship. - pub fn add_target(&mut self, entity_uid: Uid) - { - debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - - match &mut self.relationship_comp.entity_uid { - SingleOrMultiple::Single(prev_entity_uid) => { - self.relationship_comp.entity_uid = - SingleOrMultiple::Multiple(vec![*prev_entity_uid, entity_uid]); - } - SingleOrMultiple::Multiple(entity_uids) => entity_uids.push(entity_uid), - } - } - - /// Removes a target to the relationship, returning it. - pub fn remove_target(&mut self, index: usize) -> Option<Uid> - { - match &mut self.relationship_comp.entity_uid { - SingleOrMultiple::Single(entity_uid) => { - let prev_entity_uid = *entity_uid; - - self.relationship_comp.entity_uid = - SingleOrMultiple::Multiple(Vec::new()); - - Some(prev_entity_uid) - } - SingleOrMultiple::Multiple(entity_uids) => { - if index >= entity_uids.len() { - return None; - } - - Some(entity_uids.remove(index)) - } - } - } - - #[must_use] - pub fn target_count(&self) -> usize - { - match &self.relationship_comp.entity_uid { - SingleOrMultiple::Single(_) => 1, - SingleOrMultiple::Multiple(entity_uids) => entity_uids.len(), - } - } - - /// Returns a iterator of the components of the targets of this relationship. - #[must_use] - pub fn iter(&self) -> TargetComponentIterMut<'_, 'rel_comp, Kind, ComponentT> - { - TargetComponentIterMut { relation: self, index: 0 } - } -} - -impl<'relationship, 'rel_comp, Kind, ComponentT> IntoIterator - for &'relationship RelationMut<'rel_comp, Kind, ComponentT> -where - 'relationship: 'rel_comp, - ComponentT: Component, -{ - type IntoIter = TargetComponentIterMut<'relationship, 'rel_comp, Kind, ComponentT>; - type Item = ComponentRefMut<'rel_comp, ComponentT>; - - fn into_iter(self) -> Self::IntoIter - { - self.iter() - } -} - -/// Iterator of the components of the targets of a relationship. -pub struct TargetComponentIterMut<'relationship, 'rel_comp, Kind, ComponentT> -where - Kind: 'static, - ComponentT: Component, -{ - relation: &'relationship RelationMut<'rel_comp, Kind, ComponentT>, - index: usize, -} - -impl<'relationship, 'rel_comp, Kind, ComponentT> Iterator - for TargetComponentIterMut<'relationship, 'rel_comp, Kind, ComponentT> -where - 'relationship: 'rel_comp, - Kind: 'static, - ComponentT: Component, -{ - type Item = ComponentRefMut<'rel_comp, ComponentT>; - - fn next(&mut self) -> Option<Self::Item> - { - let index = self.index; - - self.index += 1; - - self.relation.get(index) - } -} - -#[derive(Debug)] -enum SingleOrMultiple<Value> -{ - Single(Value), - Multiple(Vec<Value>), -} - -pub struct Relation<'rel_comp, Kind, ComponentT> -where - Kind: 'static, - ComponentT: Component, -{ - component_storage_lock: ReadGuard<'static, ComponentStorage>, - relationship_comp: ComponentRef<'rel_comp, Relationship<Kind, ComponentT>>, -} - -impl<'rel_comp, Kind, ComponentT> FromOptionalComponent<'rel_comp> - for Relation<'rel_comp, Kind, ComponentT> -where - ComponentT: Component, -{ - fn from_optional_component( - optional_component: Option<ReadGuard<'rel_comp, Box<dyn Component>>>, - world: &'rel_comp World, - ) -> Self - { - let relationship_comp = - ComponentRef::<Relationship<Kind, ComponentT>>::from_optional_component( - optional_component, - world, - ); - - let component_storage_lock = world - .data - .component_storage - .read_nonblock() - .expect("Failed to aquire read-only component storage lock"); - - Self { - relationship_comp, - // SAFETY: The component lock is not used for longer than the original - // lifetime - component_storage_lock: unsafe { component_storage_lock.upgrade_lifetime() }, - } - } -} - -impl<'rel_comp, Kind, ComponentT> FromOptionalComponent<'rel_comp> - for Option<Relation<'rel_comp, Kind, ComponentT>> -where - ComponentT: Component, -{ - fn from_optional_component( - optional_component: Option<ReadGuard<'rel_comp, Box<dyn Component>>>, - world: &'rel_comp World, - ) -> Self - { - optional_component - .map(|component| Relation::from_optional_component(Some(component), world)) - } -} - -impl<'rel_comp, Kind, ComponentT> FromLockedOptionalComponent<'rel_comp> - for Relation<'rel_comp, Kind, ComponentT> -where - ComponentT: Component, -{ - fn from_locked_optional_component( - optional_component: Option<&'rel_comp Lock<Box<dyn Component>>>, - world: &'rel_comp World, - ) -> Result<Self, LockError> - { - Ok(Self::from_optional_component( - optional_component - .map(|lock| lock.read_nonblock()) - .transpose()?, - world, - )) - } -} - -impl<'rel_comp, Kind, ComponentT> FromLockedOptionalComponent<'rel_comp> - for Option<Relation<'rel_comp, Kind, ComponentT>> -where - ComponentT: Component, -{ - fn from_locked_optional_component( - optional_component: Option<&'rel_comp Lock<Box<dyn Component>>>, - world: &'rel_comp World, - ) -> Result<Self, crate::lock::Error> - { - optional_component - .map(|component| { - Relation::from_locked_optional_component(Some(component), world) - }) - .transpose() - } -} - -impl<'rel_comp, Kind, ComponentT> Relation<'rel_comp, Kind, ComponentT> -where - ComponentT: Component, -{ - /// Returns the component of the target at the specified index. - /// - /// # Panics - /// Will panic if the entity does not exist in the archetype it belongs to. This - /// should hopefully never happend. - #[must_use] - pub fn get(&self, index: usize) -> Option<ComponentRef<'_, ComponentT>> - { - let target = self.get_target(index)?; - - let archetype = self.component_storage_lock.get_entity_archetype(*target)?; - - let entity = archetype - .get_entity(*target) - .expect("Target entity is gone from archetype"); - - let component_index = archetype.get_index_for_component(ComponentT::id())?; - - let component = ComponentRef::new( - entity - .get_component(component_index)? - .component - .read_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to aquire read-write lock of component {}", - type_name::<ComponentT>() - ) - }), - ); - - Some(component) - } - - /// Returns a reference to the target at the specified index. - #[must_use] - pub fn get_target(&self, index: usize) -> Option<&Uid> - { - match &self.relationship_comp.entity_uid { - SingleOrMultiple::Single(entity_uid) if index == 0 => Some(entity_uid), - SingleOrMultiple::Multiple(entity_uids) => entity_uids.get(index), - SingleOrMultiple::Single(_) => None, - } - } - - #[must_use] - pub fn target_count(&self) -> usize - { - match &self.relationship_comp.entity_uid { - SingleOrMultiple::Single(_) => 1, - SingleOrMultiple::Multiple(entity_uids) => entity_uids.len(), - } - } - - pub fn target_uids(&self) -> impl Iterator<Item = Uid> + '_ - { - (0..self.target_count()) - .map_while(|target_index| self.get_target(target_index).copied()) - } - - /// Returns a iterator of the components of the targets of this relationship. - #[must_use] - pub fn iter(&self) -> TargetComponentIter<'_, 'rel_comp, Kind, ComponentT> - { - TargetComponentIter { relation: self, index: 0 } - } -} - -impl<'relationship, 'rel_comp, Kind, ComponentT> IntoIterator - for &'relationship Relation<'rel_comp, Kind, ComponentT> -where - 'relationship: 'rel_comp, - ComponentT: Component, -{ - type IntoIter = TargetComponentIter<'relationship, 'rel_comp, Kind, ComponentT>; - type Item = ComponentRef<'rel_comp, ComponentT>; - - fn into_iter(self) -> Self::IntoIter - { - self.iter() - } -} - -/// Iterator of the components of the targets of a relationship. -pub struct TargetComponentIter<'relationship, 'rel_comp, Kind, ComponentT> -where - Kind: 'static, - ComponentT: Component, -{ - relation: &'relationship Relation<'rel_comp, Kind, ComponentT>, - index: usize, -} - -impl<'relationship, 'rel_comp, Kind, ComponentT> Iterator - for TargetComponentIter<'relationship, 'rel_comp, Kind, ComponentT> -where - 'relationship: 'rel_comp, - Kind: 'static, - ComponentT: Component, -{ - type Item = ComponentRef<'rel_comp, ComponentT>; - - fn next(&mut self) -> Option<Self::Item> - { - let index = self.index; - - self.index += 1; - - self.relation.get(index) - } -} - -/// Relationship kind denoting a dependency to another entity -#[derive(Debug, Default, Clone, Copy)] -pub struct DependsOn; - -/// Relationship kind denoting being the child of another entity. -#[derive(Debug, Default, Clone, Copy)] -pub struct ChildOf; diff --git a/ecs/src/sole.rs b/ecs/src/sole.rs deleted file mode 100644 index a35b520..0000000 --- a/ecs/src/sole.rs +++ /dev/null @@ -1,185 +0,0 @@ -use std::any::{type_name, Any}; -use std::fmt::Debug; -use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; -use std::sync::{Arc, Weak}; - -use crate::lock::{Lock, WriteGuard}; -use crate::system::{Param as SystemParam, System}; -use crate::type_name::TypeName; -use crate::World; - -/// A type which has a single instance and is shared globally. -pub trait Sole: Any + TypeName -{ - fn drop_last(&self) -> bool; - - fn as_any_mut(&mut self) -> &mut dyn Any; - - fn as_any(&self) -> &dyn Any; -} - -impl dyn Sole -{ - pub fn downcast_mut<Real: 'static>(&mut self) -> Option<&mut Real> - { - self.as_any_mut().downcast_mut() - } - - pub fn downcast_ref<Real: 'static>(&self) -> Option<&Real> - { - self.as_any().downcast_ref() - } -} - -impl Debug for dyn Sole -{ - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result - { - formatter.debug_struct("Sole").finish_non_exhaustive() - } -} - -impl TypeName for Box<dyn Sole> -{ - fn type_name(&self) -> &'static str - { - self.as_ref().type_name() - } -} - -/// Holds a reference to a globally shared singleton value. -#[derive(Debug)] -pub struct Single<'world, SoleT: Sole> -{ - sole: WriteGuard<'world, Box<dyn Sole>>, - sole_weak: Weak<Lock<Box<dyn Sole>>>, - _ph: PhantomData<SoleT>, -} - -impl<'world, SoleT> Single<'world, SoleT> -where - SoleT: Sole, -{ - /// Returns a struct which holds a weak reference to the [`World`] that `Single` - /// references and that can be used to aquire a new `Single` if the referenced - /// [`World`] is still alive. - #[must_use] - pub fn to_weak_ref(&self) -> SingleWeakRef<SoleT> - { - SingleWeakRef { - sole: self.sole_weak.clone(), - _ph: PhantomData, - } - } - - fn new(sole: &'world Arc<Lock<Box<dyn Sole>>>) -> Self - { - Self { - sole: sole.write_nonblock().unwrap_or_else(|_| { - panic!( - "Failed to aquire read-write lock to single component {}", - type_name::<SoleT>() - ) - }), - sole_weak: Arc::downgrade(sole), - _ph: PhantomData, - } - } -} - -impl<'world, SoleT> SystemParam<'world> for Single<'world, SoleT> -where - SoleT: Sole, -{ - type Input = (); - - fn initialize<SystemImpl>( - _system: &mut impl System<'world, SystemImpl>, - _input: Self::Input, - ) - { - } - - fn new<SystemImpl>( - _system: &'world impl System<'world, SystemImpl>, - world: &'world World, - ) -> Self - { - let sole = world.data.sole_storage.get::<SoleT>().unwrap_or_else(|| { - panic!("Sole {} was not found in world", type_name::<SoleT>()) - }); - - Self::new(sole) - } -} - -impl<'world, SoleT> Deref for Single<'world, SoleT> -where - SoleT: Sole, -{ - type Target = SoleT; - - fn deref(&self) -> &Self::Target - { - self.sole.downcast_ref().unwrap() - } -} - -impl<'world, SoleT> DerefMut for Single<'world, SoleT> -where - SoleT: Sole, -{ - fn deref_mut(&mut self) -> &mut Self::Target - { - self.sole.downcast_mut().unwrap() - } -} - -#[derive(Debug, Clone)] -pub struct SingleWeakRef<SoleT> -where - SoleT: Sole, -{ - sole: Weak<Lock<Box<dyn Sole>>>, - _ph: PhantomData<SoleT>, -} - -impl<SoleT> SingleWeakRef<SoleT> -where - SoleT: Sole, -{ - /// Returns a struct which can be used to retrieve a [`Single`]. - /// - /// Returns [`None`] if the referenced [`World`] has been dropped. - #[must_use] - pub fn access(&self) -> Option<SingleRef<'_, SoleT>> - { - Some(SingleRef { - sole: self.sole.upgrade()?, - _pd: PhantomData, - }) - } -} - -/// Intermediate between [`Single`] and [`SingleWeakRef`]. Contains a strong reference to -/// a world which is not allowed direct access to. -#[derive(Debug, Clone)] -pub struct SingleRef<'weak_ref, SoleT> -where - SoleT: Sole, -{ - sole: Arc<Lock<Box<dyn Sole>>>, - _pd: PhantomData<&'weak_ref SoleT>, -} - -impl<'weak_ref, SoleT> SingleRef<'weak_ref, SoleT> -where - SoleT: Sole, -{ - #[must_use] - pub fn to_single(&self) -> Single<'_, SoleT> - { - Single::new(&self.sole) - } -} diff --git a/ecs/src/stats.rs b/ecs/src/stats.rs deleted file mode 100644 index 56a5c32..0000000 --- a/ecs/src/stats.rs +++ /dev/null @@ -1,8 +0,0 @@ -use ecs_macros::Sole; - -#[derive(Debug, Default, Sole)] -#[non_exhaustive] -pub struct Stats -{ - pub current_tick: u64, -} diff --git a/ecs/src/system.rs b/ecs/src/system.rs deleted file mode 100644 index b410d8f..0000000 --- a/ecs/src/system.rs +++ /dev/null @@ -1,410 +0,0 @@ -use std::any::{type_name, Any}; -use std::convert::Infallible; -use std::fmt::Debug; -use std::marker::PhantomData; -use std::ops::{Deref, DerefMut}; - -use ecs_macros::Component; -use seq_macro::seq; - -use crate::component::{ - Component, - FromLockedOptional as FromLockedOptionalComponent, - FromOptional as FromOptionalComponent, - FromOptionalMut as FromOptionalMutComponent, -}; -use crate::lock::{ - Error as LockError, - Lock, - MappedReadGuard, - MappedWriteGuard, - ReadGuard, - WriteGuard, -}; -use crate::tuple::{ReduceElement as TupleReduceElement, Tuple}; -use crate::World; - -pub mod stateful; - -pub trait System<'world, Impl>: 'static -{ - type Input; - - #[must_use] - fn initialize(self, input: Self::Input) -> Self; - - fn run<'this>(&'this self, world: &'world World) - where - 'this: 'world; - - fn into_type_erased(self) -> TypeErased; - - fn get_local_component_mut<LocalComponent: Component>( - &self, - ) -> Option<ComponentRefMut<LocalComponent>>; - - fn set_local_component<LocalComponent: Component>( - &mut self, - local_component: LocalComponent, - ); -} - -macro_rules! impl_system { - ($c: tt) => { - seq!(I in 0..$c { - impl<'world, Func, #(TParam~I,)*> System<'world, fn(#(TParam~I,)*)> - for Func - where - Func: Fn(#(TParam~I,)*) + Copy + 'static, - #(TParam~I: Param<'world, Input = ()>,)* - { - type Input = Infallible; - - fn initialize(self, _input: Self::Input) -> Self - { - self - } - - fn run<'this>(&'this self, world: &'world World) - where - 'this: 'world - { - let func = *self; - - func(#({ - TParam~I::new(self, world) - },)*); - } - - fn into_type_erased(self) -> TypeErased - { - TypeErased { - data: Box::new(self), - run: Box::new(|data, world| { - // SAFETY: The caller of TypeErased::run ensures the lifetime - // is correct - let data = unsafe { &*std::ptr::from_ref(data) }; - - let me = data - .downcast_ref::<Func>() - .expect("Function downcast failed"); - - // SAFETY: The caller of TypeErased::run ensures the lifetime - // is correct - let world = unsafe { &*std::ptr::from_ref(world) }; - - me.run(world); - }), - } - } - - fn get_local_component_mut<LocalComponent: Component>( - &self, - ) -> Option<ComponentRefMut<LocalComponent>> - { - panic!("System does not have any local components"); - } - - fn set_local_component<LocalComponent: Component>( - &mut self, - _local_component: LocalComponent, - ) { - panic!("System does not have any local components"); - } - } - }); - }; -} - -seq!(C in 1..16 { - impl_system!(C); -}); - -pub trait Into<Impl> -{ - type System; - - fn into_system(self) -> Self::System; -} - -pub struct TypeErased -{ - data: Box<dyn Any>, - run: Box<TypeErasedRunFn>, -} - -impl TypeErased -{ - /// Runs the system. - /// - /// # Safety - /// `world_data` must live at least as long as the [`World`] the system belongs to. - pub unsafe fn run(&self, world: &World) - { - // You have to dereference for downcasting to work for some reason - let data = &*self.data; - - (self.run)(data, world); - } -} - -impl Debug for TypeErased -{ - fn fmt(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result - { - formatter.debug_struct("TypeErased").finish_non_exhaustive() - } -} - -/// Function in [`TypeErased`] used to run the system. -type TypeErasedRunFn = dyn Fn(&dyn Any, &World); - -/// A parameter to a [`System`]. -pub trait Param<'world> -{ - type Input; - - fn initialize<SystemImpl>( - system: &mut impl System<'world, SystemImpl>, - input: Self::Input, - ); - - fn new<SystemImpl>( - system: &'world impl System<'world, SystemImpl>, - world: &'world World, - ) -> Self; -} - -/// A type which can be used as input to a [`System`]. -pub trait Input: 'static {} - -/// Component tuple reducing operation to get the parameters that takes input. -pub struct ParamWithInputFilter; - -impl<InputT: Input, Accumulator> TupleReduceElement<Accumulator, ParamWithInputFilter> - for InputT -where - Accumulator: Tuple, -{ - type Return = Accumulator::WithElementAtEnd<Self>; -} - -impl<Accumulator> TupleReduceElement<Accumulator, ParamWithInputFilter> for () -{ - type Return = Accumulator; -} - -#[derive(Debug)] -pub struct ComponentRefMut<'a, ComponentT: Component> -{ - inner: MappedWriteGuard<'a, ComponentT>, - _ph: PhantomData<ComponentT>, -} - -impl<'a, ComponentT: Component> ComponentRefMut<'a, ComponentT> -{ - pub(crate) fn new(inner: WriteGuard<'a, Box<dyn Component>>) -> Self - { - Self { - inner: inner.map(|component| { - let component_type_name = component.type_name(); - - component.downcast_mut::<ComponentT>().unwrap_or_else(|| { - panic!( - "Cannot downcast component {component_type_name} to type {}", - type_name::<ComponentT>() - ); - }) - }), - _ph: PhantomData, - } - } -} - -impl<'component, ComponentT: Component> FromOptionalMutComponent<'component> - for ComponentRefMut<'component, ComponentT> -{ - fn from_optional_mut_component( - inner: Option<WriteGuard<'component, Box<dyn Component>>>, - _world: &'component World, - ) -> Self - { - Self::new(inner.unwrap_or_else(|| { - panic!( - "Component {} was not found in entity", - type_name::<ComponentT>() - ); - })) - } -} - -impl<'component, ComponentT: Component> FromLockedOptionalComponent<'component> - for ComponentRefMut<'component, ComponentT> -{ - fn from_locked_optional_component( - optional_component: Option<&'component crate::lock::Lock<Box<dyn Component>>>, - world: &'component World, - ) -> Result<Self, LockError> - { - Ok(Self::from_optional_mut_component( - optional_component - .map(|lock| lock.write_nonblock()) - .transpose()?, - world, - )) - } -} - -impl<'comp, ComponentT> FromOptionalMutComponent<'comp> - for Option<ComponentRefMut<'comp, ComponentT>> -where - ComponentT: Component, -{ - fn from_optional_mut_component( - optional_component: Option<WriteGuard<'comp, Box<dyn Component>>>, - _world: &'comp World, - ) -> Self - { - optional_component.map(|component| ComponentRefMut::new(component)) - } -} - -impl<'comp, ComponentT> FromLockedOptionalComponent<'comp> - for Option<ComponentRefMut<'comp, ComponentT>> -where - ComponentT: Component, -{ - fn from_locked_optional_component( - optional_component: Option<&'comp Lock<Box<dyn Component>>>, - _world: &'comp World, - ) -> Result<Self, LockError> - { - optional_component - .map(|lock| Ok(ComponentRefMut::new(lock.write_nonblock()?))) - .transpose() - } -} - -impl<'a, ComponentT: Component> Deref for ComponentRefMut<'a, ComponentT> -{ - type Target = ComponentT; - - fn deref(&self) -> &Self::Target - { - &self.inner - } -} - -impl<'a, ComponentT: Component> DerefMut for ComponentRefMut<'a, ComponentT> -{ - fn deref_mut(&mut self) -> &mut Self::Target - { - &mut self.inner - } -} - -#[derive(Debug)] -pub struct ComponentRef<'a, ComponentT: Component> -{ - inner: MappedReadGuard<'a, ComponentT>, - _ph: PhantomData<ComponentT>, -} - -impl<'a, ComponentT: Component> ComponentRef<'a, ComponentT> -{ - pub(crate) fn new(inner: ReadGuard<'a, Box<dyn Component>>) -> Self - { - Self { - inner: inner.map(|component| { - component.downcast_ref::<ComponentT>().unwrap_or_else(|| { - panic!( - "Cannot downcast component {} to type {}", - component.type_name(), - type_name::<ComponentT>() - ); - }) - }), - _ph: PhantomData, - } - } -} - -impl<'component, ComponentT: Component> FromOptionalComponent<'component> - for ComponentRef<'component, ComponentT> -{ - fn from_optional_component( - inner: Option<ReadGuard<'component, Box<dyn Component>>>, - _world: &'component World, - ) -> Self - { - Self::new(inner.unwrap_or_else(|| { - panic!( - "Component {} was not found in entity", - type_name::<ComponentT>() - ); - })) - } -} - -impl<'component, ComponentT: Component> FromLockedOptionalComponent<'component> - for ComponentRef<'component, ComponentT> -{ - fn from_locked_optional_component( - optional_component: Option<&'component crate::lock::Lock<Box<dyn Component>>>, - world: &'component World, - ) -> Result<Self, LockError> - { - Ok(Self::from_optional_component( - optional_component - .map(|lock| lock.read_nonblock()) - .transpose()?, - world, - )) - } -} - -impl<'comp, ComponentT> FromOptionalComponent<'comp> - for Option<ComponentRef<'comp, ComponentT>> -where - ComponentT: Component, -{ - fn from_optional_component( - optional_component: Option<ReadGuard<'comp, Box<dyn Component>>>, - _world: &'comp World, - ) -> Self - { - optional_component.map(|component| ComponentRef::new(component)) - } -} - -impl<'comp, ComponentT> FromLockedOptionalComponent<'comp> - for Option<ComponentRef<'comp, ComponentT>> -where - ComponentT: Component, -{ - fn from_locked_optional_component( - optional_component: Option<&'comp Lock<Box<dyn Component>>>, - _world: &'comp World, - ) -> Result<Self, LockError> - { - optional_component - .map(|lock| Ok(ComponentRef::new(lock.read_nonblock()?))) - .transpose() - } -} - -impl<'a, ComponentT: Component> Deref for ComponentRef<'a, ComponentT> -{ - type Target = ComponentT; - - fn deref(&self) -> &Self::Target - { - &self.inner - } -} - -#[derive(Debug, Component)] -pub(crate) struct SystemComponent -{ - pub(crate) system: TypeErased, -} diff --git a/ecs/src/system/stateful.rs b/ecs/src/system/stateful.rs deleted file mode 100644 index 80ac346..0000000 --- a/ecs/src/system/stateful.rs +++ /dev/null @@ -1,157 +0,0 @@ -use std::any::{Any, TypeId}; -use std::panic::{RefUnwindSafe, UnwindSafe}; - -use hashbrown::HashMap; -use seq_macro::seq; - -use crate::component::Component; -use crate::lock::Lock; -use crate::system::{ - ComponentRefMut, - Into as IntoSystem, - Param, - ParamWithInputFilter, - System, - TypeErased, -}; -use crate::tuple::{ - Reduce as TupleReduce, - Tuple, - WithAllElemLtStatic as TupleWithAllElemLtStatic, -}; -use crate::uid::Uid; -use crate::World; - -/// A stateful system. -pub struct Stateful<Func> -{ - func: Func, - local_components: HashMap<Uid, Lock<Box<dyn Component>>>, -} - -macro_rules! impl_system { - ($c: tt) => { - seq!(I in 0..$c { - impl<'world, Func, #(TParam~I,)*> System<'world, fn(&'world (), #(TParam~I,)*)> - for Stateful<Func> - where - Func: Fn(#(TParam~I,)*) + Copy + RefUnwindSafe + UnwindSafe + 'static, - #(TParam~I: Param<'world>,)* - #(TParam~I::Input: 'static,)* - (#(TParam~I::Input,)*): TupleReduce< - ParamWithInputFilter, - Out: Tuple<InOptions: TupleWithAllElemLtStatic> - >, - { - type Input = - <(#(TParam~I::Input,)*) as TupleReduce<ParamWithInputFilter>>::Out; - - fn initialize(mut self, input: Self::Input) -> Self - { - let mut option_input = input.into_in_options(); - - let mut index = 0; - - #( - if TypeId::of::<TParam~I::Input>() != - TypeId::of::<()>() - { - let input = option_input - .get_mut::<Option<TParam~I::Input>>(index) - .expect("Input element index out of range") - .take() - .expect("Input element is already taken"); - - TParam~I::initialize( - &mut self, - input - ); - - #[allow(unused_assignments)] - { - index += 1; - } - } - )* - - self - } - - fn run<'this>(&'this self, world: &'world World) - where - 'this: 'world - { - let func = self.func; - - func(#({ - TParam~I::new(self, &world) - },)*); - } - - fn into_type_erased(self) -> TypeErased - { - TypeErased { - data: Box::new(self), - run: Box::new(|data, world| { - // SAFETY: The caller of TypeErased::run ensures the lifetime - // is correct - let data = unsafe { &*std::ptr::from_ref::<dyn Any>(data) }; - - let me = data.downcast_ref::<Self>().unwrap(); - - // SAFETY: The caller of TypeErased::run ensures the lifetime - // is correct - let world = unsafe { &*std::ptr::from_ref(world) }; - - me.run(world); - }), - } - } - - fn get_local_component_mut<LocalComponent: Component>( - &self, - ) -> Option<ComponentRefMut<LocalComponent>> - { - let local_component = self.local_components - .get(&LocalComponent::id())? - .write_nonblock() - .expect("Failed to aquire read-write local component lock"); - - Some(ComponentRefMut::new(local_component)) - } - - fn set_local_component<LocalComponent: Component>( - &mut self, - local_component: LocalComponent, - ) - { - self.local_components - .insert( - LocalComponent::id(), - Lock::new(Box::new(local_component)) - ); - } - } - - impl<Func, #(TParam~I,)*> IntoSystem<fn(#(TParam~I,)*)> - for Func - where - Func: Fn(#(TParam~I,)*) + Copy + 'static, - { - type System = Stateful<Func>; - - fn into_system(self) -> Self::System - { - Self::System { - func: self, - local_components: HashMap::new(), - } - } - } - }); - }; -} - -seq!(C in 1..16 { - impl_system!(C); -}); diff --git a/ecs/src/tuple.rs b/ecs/src/tuple.rs deleted file mode 100644 index def25a0..0000000 --- a/ecs/src/tuple.rs +++ /dev/null @@ -1,238 +0,0 @@ -use std::any::TypeId; - -use paste::paste; -use seq_macro::seq; -use util_macros::sub; - -pub trait Tuple: sealed::Sealed -{ - /// `Self` with the given type added as the last element. - /// - /// `(String, i32, u8)::WithElementAtEnd<Path> = (String, i32, u8, Path)` - /// - /// # Important note - /// If `Self` has 16 elements, this will be `()`. The reason for this is that the - /// `Tuple` trait is only implemented for tuples with up to and including 16 elements. - type WithElementAtEnd<NewElem>: Tuple; - - /// `Self` without the last element. - /// - /// `(u16, AtomicU8)::WithoutLastElement = (u16,)` - type WithoutLastElement: Tuple; - - /// The last element of `Self`. - type LastElement; - - /// Self with all elements wrapped in [`Option`]. - type InOptions: Tuple; - - /// Pops the last element from this tuple, returning the new tuple and the popped - /// element. - fn pop_last(self) -> (Self::WithoutLastElement, Self::LastElement); - - /// Converts this tuple so that all elements are wrapped in [`Option`]. - fn into_in_options(self) -> Self::InOptions; -} - -/// A tuple with element types that all have the lifetime `'static`. -pub trait WithAllElemLtStatic: Tuple + sealed::Sealed -{ - /// Returns the element at the given index. - fn get_mut<Element: 'static>(&mut self, index: usize) -> Option<&mut Element>; -} - -/// Using the type system, reduces the elements of a tuple to a single one. Each element -/// determines itself how it is handled. -pub trait Reduce<Operation> -{ - type Out; -} - -pub trait ReduceElement<Accumulator, Operation> -{ - type Return; -} - -macro_rules! tuple_reduce_elem_tuple { - (overflow) => { - () - }; - - ($index: tt) => { - paste! { - [<Elem $index>]::Return - } - }; -} - -macro_rules! elem_type_by_index { - (overflow) => { - () - }; - - ($index: tt) => { - paste! { - [<Elem $index>] - } - }; -} - -macro_rules! elem_by_index { - (overflow) => { - () - }; - - ($index: tt, $self: ident) => { - $self.$index - }; -} - -macro_rules! all_except_last { - (start $($rest: tt)*) => { - all_except_last!(@[] $($rest)*) - }; - - (@[$($included_elem: ident,)*] $elem: ident $($rest: tt)+) => { - all_except_last!(@[$($included_elem,)* $elem,] $($rest)*) - }; - - (@[$($included_elem: expr,)*] ($elem: expr) $($rest: tt)+) => { - all_except_last!(@[$($included_elem,)* $elem,] $($rest)*) - }; - - (@[$($included_elem: ident,)*] $elem: ident) => { - ($($included_elem,)*) - }; - - (@[$($included_elem: expr,)*] $elem: expr) => { - ($($included_elem,)*) - }; - - (@[]) => { - () - }; -} - -macro_rules! impl_tuple_traits { - ($cnt: tt) => { - seq!(I in 0..$cnt { - impl<#(Elem~I,)*> Tuple for (#(Elem~I,)*) - { - type WithElementAtEnd<NewElem> = (#(Elem~I,)* NewElem,); - - type WithoutLastElement = all_except_last!(start #(Elem~I)*); - - type LastElement = sub!($cnt - 1, elem_type_by_index); - - type InOptions = (#(Option<Elem~I>,)*); - - fn pop_last(self) -> (Self::WithoutLastElement, Self::LastElement) - { - ( - all_except_last!(start #((self.I))*), - sub!($cnt - 1, elem_by_index, (self)) - ) - } - - fn into_in_options(self) -> Self::InOptions - { - #![allow(clippy::unused_unit)] - (#(Some(self.I),)*) - } - } - - impl<#(Elem~I: 'static,)*> WithAllElemLtStatic for (#(Elem~I,)*) - { - fn get_mut<Element: 'static>(&mut self, index: usize) -> Option<&mut Element> - { - match index { - #( - I => { - assert!(TypeId::of::<Element>() == TypeId::of::<Elem~I>()); - - // SAFETY: It is checked above that the type is correct - Some(unsafe { &mut *(&raw mut self.I).cast::<Element>() }) - } - )* - _ => None - } - } - } - - impl<#(Elem~I,)*> sealed::Sealed for (#(Elem~I,)*) - { - } - - paste! { - impl<Operation, #(Elem~I,)*> Reduce<Operation> for (#(Elem~I,)*) - where - #( - Elem~I: ReduceElement< - sub!(I - 1, tuple_reduce_elem_tuple), Operation - >, - )* - { - type Out = sub!($cnt - 1, tuple_reduce_elem_tuple); - } - } - }); - }; -} - -seq!(N in 0..16 { - impl_tuple_traits!(N); -}); - -seq!(I in 0..16 { - impl<#(Elem~I,)*> Tuple for (#(Elem~I,)*) - { - type WithElementAtEnd<NewElem> = (); - - type WithoutLastElement = all_except_last!(start #(Elem~I)*); - - type LastElement = Elem15; - - type InOptions = (#(Option<Elem~I>,)*); - - fn pop_last(self) -> (Self::WithoutLastElement, Self::LastElement) - { - ( - all_except_last!(start #((self.I))*), - self.15 - ) - } - - fn into_in_options(self) -> Self::InOptions - { - #![allow(clippy::unused_unit)] - (#(Some(self.I),)*) - } - } - - impl<#(Elem~I: 'static,)*> WithAllElemLtStatic for (#(Elem~I,)*) - { - fn get_mut<Element: 'static>(&mut self, index: usize) -> Option<&mut Element> - { - match index { - #( - I => { - assert!(TypeId::of::<Element>() == TypeId::of::<Elem~I>()); - - // SAFETY: It is checked above that the type is correct - Some(unsafe { &mut *(&raw mut self.I).cast::<Element>() }) - } - )* - _ => None - } - } - } - - impl<#(Elem~I,)*> sealed::Sealed for (#(Elem~I,)*) - { - } -}); - -mod sealed -{ - pub trait Sealed {} -} diff --git a/ecs/src/type_name.rs b/ecs/src/type_name.rs deleted file mode 100644 index 54179be..0000000 --- a/ecs/src/type_name.rs +++ /dev/null @@ -1,15 +0,0 @@ -use std::any::type_name; - -pub trait TypeName -{ - /// Returns the name of this type. - fn type_name(&self) -> &'static str; -} - -impl<Item> TypeName for Vec<Item> -{ - fn type_name(&self) -> &'static str - { - type_name::<Self>() - } -} diff --git a/ecs/src/uid.rs b/ecs/src/uid.rs deleted file mode 100644 index bcef73e..0000000 --- a/ecs/src/uid.rs +++ /dev/null @@ -1,64 +0,0 @@ -use std::fmt::{Debug, Formatter}; -use std::mem::transmute; -use std::sync::atomic::{AtomicU32, Ordering}; - -use crate::util::{gen_mask_64, BitMask, NumberExt}; - -static NEXT: AtomicU32 = AtomicU32::new(1); - -const ID_BITS: BitMask<u64> = BitMask::new(gen_mask_64!(32..=63)); -const KIND_BITS: BitMask<u64> = BitMask::new(gen_mask_64!(0..=1)); - -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[repr(u8)] -pub enum Kind -{ - Entity = 2, - Component = 1, -} - -/// Unique entity/component ID. -#[derive(Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -pub struct Uid -{ - inner: u64, -} - -impl Uid -{ - /// Returns a new unique entity/component ID. - pub fn new_unique(kind: Kind) -> Self - { - let id = NEXT.fetch_add(1, Ordering::Relaxed); - - Self { - inner: ID_BITS.field_prep(id as u64) | KIND_BITS.field_prep(kind as u64), - } - } - - #[must_use] - pub fn id(&self) -> u32 - { - self.inner.field_get(ID_BITS) as u32 - } - - #[must_use] - pub fn kind(&self) -> Kind - { - // SAFETY: The kind bits cannot be invalid since they are set using the Kind enum - // in the new_unique function - unsafe { transmute(self.inner.field_get(KIND_BITS) as u8) } - } -} - -impl Debug for Uid -{ - fn fmt(&self, formatter: &mut Formatter<'_>) -> std::fmt::Result - { - formatter - .debug_struct("Uid") - .field("id", &self.id()) - .field("kind", &self.kind()) - .finish_non_exhaustive() - } -} diff --git a/ecs/src/util.rs b/ecs/src/util.rs deleted file mode 100644 index 0273b18..0000000 --- a/ecs/src/util.rs +++ /dev/null @@ -1,155 +0,0 @@ -use std::ops::BitAnd; - -pub trait Array<Item>: - AsRef<[Item]> - + AsMut<[Item]> - + IntoIterator<Item = Item> - + Into<Vec<Item>> - + Sortable<Item = Item> - + sealed::Sealed -{ -} - -impl<Item, const CNT: usize> Array<Item> for [Item; CNT] {} - -impl<Item, const CNT: usize> sealed::Sealed for [Item; CNT] {} - -pub trait Sortable -{ - type Item; - - fn sort_by_key_b<Key, Func>(&mut self, func: Func) - where - Func: FnMut(&Self::Item) -> Key, - Key: Ord; -} - -impl<Item> Sortable for [Item] -{ - type Item = Item; - - fn sort_by_key_b<Key, Func>(&mut self, func: Func) - where - Func: FnMut(&Self::Item) -> Key, - Key: Ord, - { - self.sort_by_key(func); - } -} - -impl<Item, const LENGTH: usize> Sortable for [Item; LENGTH] -{ - type Item = Item; - - fn sort_by_key_b<Key, Func>(&mut self, func: Func) - where - Func: FnMut(&Self::Item) -> Key, - Key: Ord, - { - self.sort_by_key(func); - } -} - -impl<Item> Sortable for Vec<Item> -{ - type Item = Item; - - fn sort_by_key_b<Key, Func>(&mut self, func: Func) - where - Func: FnMut(&Self::Item) -> Key, - Key: Ord, - { - self.sort_by_key(func); - } -} - -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct BitMask<Value> -{ - mask: Value, -} - -impl BitMask<u64> -{ - #[must_use] - pub const fn new(mask: u64) -> Self - { - Self { mask } - } - - pub const fn value(self) -> u64 - { - self.mask - } - - /// Prepares a bitfield value in the range of bits specified by this `BitMask`. - #[must_use] - pub const fn field_prep(self, field_value: u64) -> u64 - { - ((field_value) << self.mask.trailing_zeros()) & (self.mask) - } -} - -impl BitAnd<u64> for BitMask<u64> -{ - type Output = u64; - - fn bitand(self, rhs: u64) -> Self::Output - { - self.mask & rhs - } -} - -pub trait NumberExt: Sized -{ - /// Returns a range of bits (field) specified by the provided [`BitMask`]. - fn field_get(self, field_mask: BitMask<Self>) -> Self; -} - -impl NumberExt for u64 -{ - fn field_get(self, field_mask: BitMask<Self>) -> Self - { - (field_mask & self) >> field_mask.value().trailing_zeros() - } -} - -macro_rules! gen_mask_64 { - ($low: literal..=$high: literal) => { - const { - if $high <= $low { - panic!("High bit index cannot be less than or equal to low bit index"); - } - - (((!0u64) - (1u64 << ($low)) + 1) - & (!0u64 >> (u64::BITS as u64 - 1 - ($high)))) - } - }; -} - -pub(crate) use gen_mask_64; - -mod sealed -{ - pub trait Sealed {} -} - -#[cfg(test)] -mod tests -{ - - use super::BitMask; - use crate::util::NumberExt; - - #[test] - fn field_get_works() - { - assert_eq!(0b11011u64.field_get(BitMask::new(0b11100)), 0b00110); - } - - #[test] - fn bitmask_field_prep_works() - { - assert_eq!(BitMask::new(0b11000).field_prep(3), 0b11000); - } -} |
