diff options
Diffstat (limited to 'ecs')
33 files changed, 0 insertions, 4575 deletions
diff --git a/ecs/Cargo.toml b/ecs/Cargo.toml deleted file mode 100644 index 342f087..0000000 --- a/ecs/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -name = "ecs" -version = "0.1.0" -edition = "2021" - -[features] -debug = ["dep:tracing"] - -[dependencies] -seq-macro = "0.3.5" -paste = "1.0.14" -thiserror = "1.0.49" -tracing = { version = "0.1.39", optional = true } -linkme = "0.3.29" -ecs-macros = { path = "../ecs-macros" } -util-macros = { path = "../util-macros" } - diff --git a/ecs/examples/event_loop.rs b/ecs/examples/event_loop.rs deleted file mode 100644 index 8d8d84f..0000000 --- a/ecs/examples/event_loop.rs +++ /dev/null @@ -1,97 +0,0 @@ -use ecs::actions::Actions; -use ecs::event::Event; -use ecs::{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<(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<(Health, Name)>) -{ - for (mut health, name) in &query { - health.health += 1; - - println!("Feeded {} which gained 1 health", name.name); - } -} - -fn age(query: Query<(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); - } -} - -#[derive(Debug)] -struct EventA; - -impl Event for EventA {} - -#[derive(Debug)] -struct EventB; - -impl Event for EventB {} - -#[derive(Debug)] -struct EventC; - -impl Event for EventC {} - -fn main() -{ - let mut world = World::new(); - - world.register_system(EventA, sheer); - world.register_system(EventB, feed); - world.register_system(EventC, age); - - world.create_entity(( - Wool { remaining: 30 }, - Health { health: 3 }, - Name { name: "Bessy" }, - )); - - world.event_loop::<(EventA, EventB, EventC)>(); -} diff --git a/ecs/examples/extension.rs b/ecs/examples/extension.rs deleted file mode 100644 index 2022b05..0000000 --- a/ecs/examples/extension.rs +++ /dev/null @@ -1,77 +0,0 @@ -use ecs::actions::Actions; -use ecs::event::Event; -use ecs::extension::{Collector as ExtensionCollector, Extension}; -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, -} - -#[derive(Debug)] -struct Update; - -impl Event for Update {} - -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, 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.emit(Update); - - world.perform_queued_actions(); - } -} diff --git a/ecs/examples/multiple_queries.rs b/ecs/examples/multiple_queries.rs deleted file mode 100644 index 2736bce..0000000 --- a/ecs/examples/multiple_queries.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::fmt::Display; - -use ecs::event::start::Start as StartEvent; -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<(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(StartEvent, 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.emit(StartEvent); -} diff --git a/ecs/examples/optional_component.rs b/ecs/examples/optional_component.rs deleted file mode 100644 index e47bf2e..0000000 --- a/ecs/examples/optional_component.rs +++ /dev/null @@ -1,86 +0,0 @@ -use ecs::event::Event; -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, 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; - } -} - -#[derive(Debug)] -struct PettingTime; - -impl Event for PettingTime {} - -fn main() -{ - let mut world = World::new(); - - world.register_system(PettingTime, 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.emit(PettingTime); -} diff --git a/ecs/examples/relationship.rs b/ecs/examples/relationship.rs deleted file mode 100644 index e8fb327..0000000 --- a/ecs/examples/relationship.rs +++ /dev/null @@ -1,48 +0,0 @@ -use ecs::event::start::Start as StartEvent; -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(StartEvent, 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.emit(StartEvent); -} diff --git a/ecs/examples/simple.rs b/ecs/examples/simple.rs deleted file mode 100644 index 4057c84..0000000 --- a/ecs/examples/simple.rs +++ /dev/null @@ -1,42 +0,0 @@ -use ecs::event::start::Start as StartEvent; -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(StartEvent, 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.emit(StartEvent); -} diff --git a/ecs/examples/with_local.rs b/ecs/examples/with_local.rs deleted file mode 100644 index 5890b90..0000000 --- a/ecs/examples/with_local.rs +++ /dev/null @@ -1,77 +0,0 @@ -use ecs::component::local::Local; -use ecs::event::Event; -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; - } -} - -#[derive(Debug)] -struct Update; - -impl Event for Update {} - -fn main() -{ - let mut world = World::new(); - - world.register_system( - Update, - say_hello - .into_system() - .initialize((SayHelloState { cnt: 0 },)), - ); - - world.register_system( - Update, - 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.emit(Update); - - println!("Haha"); - - world.emit(Update); -} diff --git a/ecs/examples/with_sole.rs b/ecs/examples/with_sole.rs deleted file mode 100644 index a387bea..0000000 --- a/ecs/examples/with_sole.rs +++ /dev/null @@ -1,59 +0,0 @@ -use ecs::event::Event; -use ecs::sole::Single; -use ecs::{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); -} - -#[derive(Debug)] -struct EventA; - -impl Event for EventA {} - -#[derive(Debug)] -struct EventB; - -impl Event for EventB {} - -fn main() -{ - let mut world = World::new(); - - world.register_system(EventA, count_ammo); - world.register_system(EventB, 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.emit(EventA); - - world.emit(EventB); -} diff --git a/ecs/src/actions.rs b/ecs/src/actions.rs deleted file mode 100644 index f7b00d3..0000000 --- a/ecs/src/actions.rs +++ /dev/null @@ -1,146 +0,0 @@ -use std::marker::PhantomData; -use std::sync::{Arc, Weak}; - -use crate::component::{ - Component, - Metadata as ComponentMetadata, - Sequence as ComponentSequence, -}; -use crate::system::{NoInitParamFlag, 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> -{ - /// Adds a spawning a new entity to the action queue. - pub fn spawn<Comps: ComponentSequence>(&mut self, components: Comps) - { - self.action_queue.push(Action::Spawn(components.into_vec())); - } - - /// Adds component(s) to a entity. - pub fn add_components<Comps>(&mut self, entity_uid: Uid, components: Comps) - where - Comps: ComponentSequence, - { - debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - - self.action_queue - .push(Action::AddComponents(entity_uid, components.into_vec())); - } - - /// Removes component(s) from a entity. - pub fn remove_components<Comps>(&mut self, entity_uid: Uid) - where - Comps: ComponentSequence, - { - debug_assert_eq!(entity_uid.kind(), UidKind::Entity); - - self.action_queue - .push(Action::RemoveComponents(entity_uid, Comps::metadata())); - } - - /// Adds stopping the loop in [`Engine::event_loop`] at the next opportune time to the - /// action queue. - 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), - } - } -} - -unsafe impl<'world> SystemParam<'world> for Actions<'world> -{ - type Flags = NoInitParamFlag; - 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) - } -} - -/// A action for a [`System`] to perform. -#[derive(Debug)] -pub(crate) enum Action -{ - Spawn(Vec<Box<dyn Component>>), - AddComponents(Uid, Vec<Box<dyn Component>>), - RemoveComponents(Uid, Vec<ComponentMetadata>), - Stop, -} diff --git a/ecs/src/archetype.rs b/ecs/src/archetype.rs deleted file mode 100644 index d2ee36a..0000000 --- a/ecs/src/archetype.rs +++ /dev/null @@ -1,61 +0,0 @@ -use std::hash::{DefaultHasher, Hash, Hasher}; - -use crate::component::{ - IsOptional as ComponentIsOptional, - Metadata as ComponentMetadata, -}; -use crate::uid::Uid; - -/// 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 - { - debug_assert!( - components_metadata.as_ref().len() > 0, - "Cannot create a archetype ID from a empty component metadata list" - ); - - 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" - ); - - Self::new( - components_metadata - .as_ref() - .iter() - .filter_map(|component_metadata| { - if component_metadata.is_optional == ComponentIsOptional::Yes { - return None; - } - - Some(component_metadata.id) - }), - ) - } - - /// Returns the ID of a archetype with the given components. - fn new(component_ids: impl IntoIterator<Item = Uid>) -> Self - { - let mut hasher = DefaultHasher::new(); - - for component_id in component_ids { - component_id.hash(&mut hasher); - } - - let hash = hasher.finish(); - - Self { hash } - } -} diff --git a/ecs/src/component.rs b/ecs/src/component.rs deleted file mode 100644 index a9894b7..0000000 --- a/ecs/src/component.rs +++ /dev/null @@ -1,333 +0,0 @@ -use std::any::{type_name, Any}; -use std::fmt::Debug; - -use seq_macro::seq; - -use crate::lock::{ReadGuard, WriteGuard}; -use crate::system::{ComponentRef, ComponentRefMut, Input as SystemInput}; -use crate::type_name::TypeName; -use crate::uid::Uid; -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> - where - Self: Sized; - - type Ref<'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; - - #[doc(hidden)] - fn as_any_mut(&mut self) -> &mut dyn Any; - - #[doc(hidden)] - fn as_any(&self) -> &dyn Any; - - /// Whether the component `self` is optional. Returns the same value as - /// [`Component::is_optional`]. - fn self_is_optional(&self) -> IsOptional - { - IsOptional::No - } - - /// Returns whether this component is optional. - #[must_use] - fn is_optional() -> IsOptional - where - Self: Sized, - { - IsOptional::No - } -} - -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, -{ - type Component = ComponentT; - type Ref<'component> = Option<ComponentRef<'component, ComponentT>>; - type RefMut<'component> = Option<ComponentRefMut<'component, ComponentT>>; - - fn id() -> Uid - { - ComponentT::id() - } - - fn self_id(&self) -> Uid - { - Self::id() - } - - fn as_any_mut(&mut self) -> &mut dyn Any - { - self - } - - fn as_any(&self) -> &dyn Any - { - self - } - - fn self_is_optional(&self) -> IsOptional - { - Self::is_optional() - } - - fn is_optional() -> IsOptional - { - IsOptional::Yes - } -} - -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 -{ - type MutRefs<'component> - where - Self: 'component; - - type Refs<'component> - where - Self: 'component; - - fn into_vec(self) -> Vec<Box<dyn Component>>; - - fn metadata() -> Vec<Metadata>; - - fn from_components_mut<'component>( - components: impl Iterator<Item = &'component EntityComponent>, - world: &'component World, - lock_component: fn( - entity_component: &EntityComponent, - ) -> WriteGuard<'_, Box<dyn Component>>, - ) -> Self::MutRefs<'component>; - - fn from_components<'component>( - components: impl Iterator<Item = &'component EntityComponent>, - world: &'component World, - lock_component: fn( - entity_component: &EntityComponent, - ) -> ReadGuard<'_, Box<dyn Component>>, - ) -> Self::Refs<'component>; -} - -/// [`Component`] metadata. -#[derive(Debug, Clone)] -#[non_exhaustive] -pub struct Metadata -{ - pub id: Uid, - pub is_optional: IsOptional, -} - -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(), - } - } -} - -/// Whether or not a `Component` is optional. -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -pub enum IsOptional -{ - Yes, - No, -} - -impl From<bool> for IsOptional -{ - fn from(is_optional: bool) -> Self - { - if is_optional { - return IsOptional::Yes; - } - - IsOptional::No - } -} - -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; -} - -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>,)* - { - type MutRefs<'component> = (#(Comp~I::RefMut<'component>,)*) - where Self: 'component; - - type Refs<'component> = (#(Comp~I::Ref<'component>,)*) - where Self: 'component; - - fn into_vec(self) -> Vec<Box<dyn Component>> - { - Vec::from_iter([#(Box::new(self.I) as Box<dyn Component>,)*]) - } - - fn metadata() -> Vec<Metadata> - { - vec![ - #( - Metadata { - id: Comp~I::id(), - is_optional: Comp~I::is_optional() - }, - )* - ] - } - - fn from_components_mut<'component>( - components: impl Iterator<Item = &'component EntityComponent>, - world: &'component World, - lock_component: fn( - entity_component: &EntityComponent, - ) -> WriteGuard<'_, Box<dyn Component>>, - ) -> Self::MutRefs<'component> - { - #( - let mut comp_~I: Option<WriteGuard<Box<dyn Component>>> = None; - )* - - for comp in components { - #( - if comp.id == Comp~I::Component::id() { - comp_~I = Some(lock_component(comp)); - continue; - } - )* - } - - (#( - Comp~I::RefMut::from_optional_mut_component(comp_~I, world), - )*) - } - - fn from_components<'component>( - components: impl Iterator<Item = &'component EntityComponent>, - world: &'component World, - lock_component: fn( - entity_component: &EntityComponent, - ) -> ReadGuard<'_, Box<dyn Component>>, - ) -> Self::Refs<'component> - { - - #( - let mut comp_~I: Option<ReadGuard<Box<dyn Component>>> = None; - )* - - for comp in components { - #( - if comp.id == Comp~I::Component::id() { - comp_~I = Some(lock_component(comp)); - continue; - } - )* - } - - (#( - Comp~I::Ref::from_optional_component(comp_~I, world), - )*) - } - } - }); - }; -} - -seq!(C in 0..=64 { - inner!(C); -}); diff --git a/ecs/src/component/local.rs b/ecs/src/component/local.rs deleted file mode 100644 index 20627bf..0000000 --- a/ecs/src/component/local.rs +++ /dev/null @@ -1,62 +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>, -} - -unsafe impl<'world, LocalComponent> SystemParam<'world> for Local<'world, LocalComponent> -where - LocalComponent: Component, -{ - type Flags = (); - 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 ffd682e..0000000 --- a/ecs/src/component/storage.rs +++ /dev/null @@ -1,621 +0,0 @@ -use std::any::type_name; -use std::borrow::Borrow; -use std::cell::RefCell; -use std::collections::{HashMap, HashSet}; -use std::slice::Iter as SliceIter; -use std::vec::IntoIter as OwnedVecIter; - -use crate::archetype::Id as ArchetypeId; -use crate::component::{ - Component, - IsOptional as ComponentIsOptional, - Metadata as ComponentMetadata, -}; -use crate::type_name::TypeName; -use crate::uid::Uid; -use crate::util::Sortable; -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 find_entities<CompMetadataList>( - &self, - mut components_metadata: CompMetadataList, - ) -> ArchetypeRefIter<'_> - where - CompMetadataList: Sortable<Item = ComponentMetadata>, - CompMetadataList: AsRef<[ComponentMetadata]>, - { - components_metadata.sort_by_key_b(|component_metadata| component_metadata.id); - - let archetype_id = ArchetypeId::from_components_metadata(&components_metadata); - - // This looks stupid but the borrow checker complains otherwise - if self.archetype_lookup.borrow().contains_key(&archetype_id) { - return self.iter_archetypes_by_lookup(archetype_id); - } - - let comp_ids_set = create_non_opt_component_id_set(components_metadata.as_ref()); - - let matching_archetype_indices = self - .archetypes - .iter() - .enumerate() - .filter_map(|(index, archetype)| { - if archetype.component_ids_is_superset(&comp_ids_set) { - return Some(index); - } - - None - }) - .collect(); - - self.archetype_lookup.borrow_mut().insert( - archetype_id, - ArchetypeLookupEntry { - component_ids: comp_ids_set, - archetype_indices: matching_archetype_indices, - }, - ); - - 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.find_archetype_index_with_entity(*archetype_id, entity_uid)?; - - self.archetypes.get(archetype_index) - } - - #[cfg_attr(feature = "debug", 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()); - - #[cfg(feature = "debug")] - tracing::debug!( - "Pushing entity with components: ({})", - components - .iter() - .map(|component| component.type_name()) - .collect::<Vec<_>>() - .join(", ") - ); - - 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, &comp_ids_set, &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); - - archetype - .entity_lookup - .insert(entity_uid, archetype.entities.len() - 1); - - 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.find_archetype_index_with_entity(*archetype_id, entity_uid)?; - - 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.find_archetype_index_with_entity(*archetype_id, entity_uid)?; - - 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, - comp_ids_set: &HashSet<Uid>, - components: &[Box<dyn Component>], - ) -> usize - { - let mut archetype_lookup = self.archetype_lookup.borrow_mut(); - - let lookup_entry = archetype_lookup.entry(archetype_id).or_insert_with(|| { - ArchetypeLookupEntry { - component_ids: comp_ids_set.clone(), - archetype_indices: Vec::with_capacity(1), - } - }); - - if lookup_entry.archetype_indices.is_empty() { - self.archetypes.push(Archetype::new( - components.iter().map(|component| component.self_id()), - )); - - lookup_entry - .archetype_indices - .push(self.archetypes.len() - 1); - } - - // 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 find_archetype_index_with_entity( - &self, - archetype_id: ArchetypeId, - entity_uid: Uid, - ) -> Option<usize> - { - let archetype_lookup = self.archetype_lookup.borrow_mut(); - - let archetype_lookup_entry = archetype_lookup.get(&archetype_id)?; - - // TODO: Also have a hashmap for precise archetype ID -> archetype index lookup. - // This way is slow - archetype_lookup_entry - .archetype_indices - .iter() - .find(|archetype_index| { - let Some(archetype) = self.archetypes.get(**archetype_index) else { - return false; - }; - - archetype.has_entity(entity_uid) - }) - .copied() - } - - 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, - } - } -} - -/// 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>, - 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(), - 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 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 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(), - }); - } - - pub fn take_entity(&mut self, entity_uid: Uid) -> Option<ArchetypeEntity> - { - let entity_index = self.entity_lookup.remove(&entity_uid)?; - - let entity = self.entities.remove(entity_index); - - for index in self.entity_lookup.values_mut() { - if *index > entity_index { - *index -= 1; - } - } - - Some(entity) - } - - fn has_entity(&self, entity_uid: Uid) -> bool - { - self.entity_lookup.contains_key(&entity_uid) - } -} - -#[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 == ComponentIsOptional::Yes { - 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, - IsOptional as ComponentIsOptional, - 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: ComponentIsOptional::No, - }, - ComponentMetadata { - id: Hookshot::id(), - is_optional: ComponentIsOptional::No, - }, - ]; - - 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 1a4edcc..0000000 --- a/ecs/src/event.rs +++ /dev/null @@ -1,96 +0,0 @@ -use std::any::TypeId; -use std::fmt::Debug; -use std::hash::{DefaultHasher, Hash, Hasher}; - -use seq_macro::seq; - -pub mod component; - -pub trait Event: Debug + 'static -{ - /// Returns the ID of this event. - #[must_use] - fn id() -> Id - where - Self: Sized, - { - Id::new::<Self, ()>(None) - } -} - -pub mod start; - -/// The ID of a [`Event`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] -pub struct Id -{ - inner: TypeId, - extra: Option<u64>, -} - -impl Id -{ - #[must_use] - pub fn new<EventT, Extra>(extra: Option<Extra>) -> Self - where - EventT: Event, - Extra: Hash, - { - Self { - inner: TypeId::of::<EventT>(), - extra: extra.map(|extra| { - let mut hasher = DefaultHasher::new(); - - extra.hash(&mut hasher); - - hasher.finish() - }), - } - } -} - -pub trait Ids -{ - type Iter<'a>: Iterator<Item = &'a Id> - where - Self: 'a; - - fn iter(&self) -> Self::Iter<'_>; -} - -/// A sequence of events. -pub trait Sequence -{ - type Ids: Ids; - - fn ids() -> Self::Ids; -} - -macro_rules! impl_sequence { - ($c: tt) => { - seq!(I in 0..=$c { - impl Ids for [Id; $c + 1] - { - type Iter<'a> = std::slice::Iter<'a, Id>; - - fn iter(&self) -> Self::Iter<'_> { - self.into_iter() - } - } - - impl<#(Event~I: Event,)*> Sequence for (#(Event~I,)*) { - type Ids = [Id; $c + 1]; - - fn ids() -> Self::Ids { - [#( - Event~I::id(), - )*] - } - } - }); - }; -} - -seq!(C in 0..=64 { - impl_sequence!(C); -}); diff --git a/ecs/src/event/component.rs b/ecs/src/event/component.rs deleted file mode 100644 index 8b066a7..0000000 --- a/ecs/src/event/component.rs +++ /dev/null @@ -1,124 +0,0 @@ -//! Component events. - -use std::fmt::{Debug, Formatter}; -use std::marker::PhantomData; - -use ecs_macros::Component; - -use crate::component::Component; -use crate::uid::Uid; -use crate::event::{Event, Id}; -use crate::tuple::{ReduceElement as TupleReduceElement, With as TupleWith}; - -/// Event emitted when: -/// a) A entity with component `ComponentT` is spawned. -/// b) A component `ComponentT` is added to a entity. -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 } - } -} - -impl<ComponentT> Event for Added<ComponentT> -where - ComponentT: Component, -{ - fn id() -> Id - where - Self: Sized, - { - Id::new::<Added<ComponentForId>, _>(Some(ComponentT::id())) - } -} - -/// Event emitted when a `ComponentT` component is removed from a entity. -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 } - } -} - -impl<ComponentT> Event for Removed<ComponentT> -where - ComponentT: Component, -{ - fn id() -> Id - where - Self: Sized, - { - Id::new::<Removed<ComponentForId>, _>(Some(ComponentT::id())) - } -} - -#[must_use] -pub fn create_added_id(component_id: Uid) -> Id -{ - Id::new::<Added<ComponentForId>, _>(Some(component_id)) -} - -#[must_use] -pub fn create_removed_id(component_id: Uid) -> Id -{ - Id::new::<Removed<ComponentForId>, _>(Some(component_id)) -} - -pub struct TypeTransformComponentsToAddedEvents; - -impl<ComponentT: Component, Accumulator> - TupleReduceElement<Accumulator, TypeTransformComponentsToAddedEvents> for ComponentT -where - Accumulator: TupleWith<Added<Self>>, -{ - type Return = Accumulator::With; -} - -#[derive(Debug, Component)] -struct ComponentForId; diff --git a/ecs/src/event/start.rs b/ecs/src/event/start.rs deleted file mode 100644 index 248dd50..0000000 --- a/ecs/src/event/start.rs +++ /dev/null @@ -1,7 +0,0 @@ -use crate::event::Event; - -/// Start event. -#[derive(Debug, Clone, Copy)] -pub struct Start; - -impl Event for Start {} diff --git a/ecs/src/extension.rs b/ecs/src/extension.rs deleted file mode 100644 index a945d89..0000000 --- a/ecs/src/extension.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::component::Sequence as ComponentSequence; -use crate::event::component::TypeTransformComponentsToAddedEvents; -use crate::event::{Event, Sequence as EventSequence}; -use crate::sole::Sole; -use crate::system::System; -use crate::tuple::Reduce as TupleReduce; -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, EventT, SystemImpl>( - &'this mut self, - event: EventT, - system: impl System<'this, SystemImpl>, - ) where - EventT: Event, - { - self.world.register_system(event, system); - } - - /// Adds a entity to the [`World`]. - pub fn add_entity<Comps>(&mut self, components: Comps) - where - Comps: ComponentSequence + TupleReduce<TypeTransformComponentsToAddedEvents>, - Comps::Out: EventSequence, - { - 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 78e526f..0000000 --- a/ecs/src/lib.rs +++ /dev/null @@ -1,532 +0,0 @@ -#![deny(clippy::all, clippy::pedantic)] - -use std::any::{type_name, TypeId}; -use std::cell::RefCell; -use std::collections::HashMap; -use std::fmt::Debug; -use std::mem::ManuallyDrop; -use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::Arc; - -use crate::actions::Action; -use crate::component::storage::Storage as ComponentStorage; -use crate::component::{Component, Sequence as ComponentSequence}; -use crate::entity::CREATE_STATIC_ENTITIES; -use crate::event::component::{ - create_added_id as create_component_added_event_id, - create_removed_id as create_component_removed_event_id, - TypeTransformComponentsToAddedEvents, -}; -use crate::event::start::Start as StartEvent; -use crate::event::{Event, Id as EventId, Ids, Sequence as EventSequence}; -use crate::extension::{Collector as ExtensionCollector, Extension}; -use crate::lock::{Lock, WriteGuard}; -use crate::query::options::Options as QueryOptions; -use crate::sole::Sole; -use crate::stats::Stats; -use crate::system::{System, TypeErased as TypeErasedSystem}; -use crate::tuple::Reduce as TupleReduce; -use crate::type_name::TypeName; -use crate::uid::{Kind as UidKind, Uid}; - -pub mod actions; -pub mod component; -pub mod entity; -pub mod event; -pub mod extension; -pub mod lock; -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; - -#[doc(hidden)] -pub mod private; - -mod archetype; -mod util; - -pub use ecs_macros::{Component, Sole}; - -pub use crate::query::Query; - -#[derive(Debug, Default)] -pub struct World -{ - systems: Vec<TypeErasedSystem>, - data: WorldData, - stop: AtomicBool, -} - -impl World -{ - #[must_use] - pub fn new() -> Self - { - let mut world = Self::default(); - - world.add_sole(Stats::default()).ok(); - - 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 + TupleReduce<TypeTransformComponentsToAddedEvents>, - Comps::Out: EventSequence, - { - let entity_uid = Uid::new_unique(UidKind::Entity); - - self.create_entity_with_uid(components, entity_uid); - - entity_uid - } - - #[cfg_attr(feature = "debug", tracing::instrument(skip_all))] - #[doc(hidden)] - pub fn create_entity_with_uid<Comps>(&self, components: Comps, entity_uid: Uid) - where - Comps: ComponentSequence + TupleReduce<TypeTransformComponentsToAddedEvents>, - Comps::Out: EventSequence, - { - 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_vec()) - { - #[cfg(feature = "debug")] - tracing::error!("Failed to create entity: {err}"); - - return; - }; - - for component_added_event_id in <Comps::Out as EventSequence>::ids().iter() { - self.emit_event_by_id(*component_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, EventT, SystemImpl>( - &'this mut self, - event: EventT, - system: impl System<'this, SystemImpl>, - ) where - EventT: Event, - { - self.systems.push(system.into_type_erased()); - - self.data - .events - .entry(EventT::id()) - .or_default() - .push(self.systems.len() - 1); - - drop(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); - } - - /// Emits a event, running all systems listening to the event for each compatible - /// entity. - /// - /// # Panics - /// Will panic if a system has dissapeared. - pub fn emit<EventT>(&self, event: EventT) - where - EventT: Event, - { - self.emit_event_by_id(EventT::id()); - - drop(event); - } - - pub fn query<Comps, OptionsT>(&self) -> Query<Comps, OptionsT> - where - Comps: ComponentSequence, - OptionsT: QueryOptions, - { - Query::new(self) - } - - /// Peforms the actions that have been queued up using [`Actions`]. - /// - /// # Panics - /// Will panic if a mutable internal lock cannot be acquired. - #[cfg_attr(feature = "debug", tracing::instrument(skip_all))] - pub 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) => { - let mut component_storage_lock = self.lock_component_storage_rw(); - - let component_ids = components - .iter() - .map(|component| component.self_id()) - .collect::<Vec<_>>(); - - #[allow(unused_variables)] - if let Err(err) = component_storage_lock - .push_entity(Uid::new_unique(UidKind::Entity), components) - { - #[cfg(feature = "debug")] - 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 component_id in component_ids { - self.emit_event_by_id(create_component_added_event_id( - component_id, - )); - } - } - Action::AddComponents(entity_uid, components) => { - let mut component_storage_lock = self.lock_component_storage_rw(); - - let component_ids = components - .iter() - .map(|component| component.self_id()) - .collect::<Vec<_>>(); - - 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 component_id in component_ids { - self.emit_event_by_id(create_component_added_event_id( - component_id, - )); - } - } - Action::RemoveComponents(entity_uid, components_metadata) => { - 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 component_metadata in components_metadata { - self.emit_event_by_id(create_component_removed_event_id( - component_metadata.id, - )); - } - } - Action::Stop => { - self.stop.store(true, Ordering::Relaxed); - } - } - } - } - - /// A event loop which runs until a stop is issued with [`Flags::stop`]. Before the - /// loop begins, [`StartEvent`] is emitted. - /// - /// # Panics - /// Will panic if a internal lock cannot be acquired. - pub fn event_loop<EventSeq: EventSequence>(&self) - { - for create_static_entity in CREATE_STATIC_ENTITIES { - create_static_entity(self); - } - - self.emit(StartEvent); - - let event_seq = EventSeq::ids(); - - loop { - for event_id in event_seq.iter() { - self.emit_event_by_id(*event_id); - } - - self.perform_queued_actions(); - - if self.stop.load(Ordering::Relaxed) { - break; - } - - 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; - } - } - - fn emit_event_by_id(&self, event_id: EventId) - { - let Some(system_indices) = self.data.events.get(&event_id) else { - return; - }; - - for system_index in system_indices { - let system = self.systems.get(*system_index).unwrap(); - - // SAFETY: The world lives long enough - unsafe { - 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") - } -} - -#[derive(Debug, Default)] -pub struct WorldData -{ - events: HashMap<EventId, Vec<usize>>, - 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 { - #[cfg(feature = "debug")] - tracing::debug!( - "Sole {} pushed to dropping last queue", - sole.sole.read_nonblock().unwrap().type_name() - ); - - soles_to_drop_last.push(sole); - continue; - } - - #[cfg(feature = "debug")] - tracing::debug!( - "Dropping sole {}", - sole.sole.read_nonblock().unwrap().type_name() - ); - - unsafe { - ManuallyDrop::drop(sole); - } - } - - for sole in &mut soles_to_drop_last { - #[cfg(feature = "debug")] - tracing::debug!( - "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 fbc6842..0000000 --- a/ecs/src/lock.rs +++ /dev/null @@ -1,162 +0,0 @@ -use std::mem::transmute; -use std::ops::{Deref, DerefMut}; -use std::sync::{PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard, TryLockError}; - -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().or_else(|err| match err { - TryLockError::WouldBlock => Err(Error::Unavailable), - TryLockError::Poisoned(poison_err) => Ok(poison_err.into_inner()), - })?; - - #[cfg(feature = "debug")] - 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().or_else(|err| match err { - TryLockError::WouldBlock => Err(Error::Unavailable), - TryLockError::Poisoned(poison_err) => Ok(poison_err.into_inner()), - })?; - - #[cfg(feature = "debug")] - 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() - .unwrap_or_else(PoisonError::into_inner) - } -} - -#[derive(Debug, thiserror::Error)] -pub enum Error -{ - #[error("Lock is unavailable")] - Unavailable, -} - -#[derive(Debug)] -pub struct ReadGuard<'guard, Value> -where - Value: TypeName, -{ - inner: RwLockReadGuard<'guard, Value>, -} - -impl<'guard, Value> ReadGuard<'guard, Value> -where - Value: TypeName, -{ - /// 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) - { - #[cfg(feature = "debug")] - tracing::trace!("Dropped 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> 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) - { - #[cfg(feature = "debug")] - tracing::trace!("Dropped mutable lock to value of type {}", self.type_name()); - } -} 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 f3318bd..0000000 --- a/ecs/src/query.rs +++ /dev/null @@ -1,273 +0,0 @@ -use std::iter::{Filter, Flatten, Map}; -use std::marker::PhantomData; - -use crate::component::storage::{ - Archetype, - ArchetypeEntity, - ArchetypeRefIter, - EntityIter, - Storage as ComponentStorage, -}; -use crate::component::{ - Component, - Metadata as ComponentMetadata, - Sequence as ComponentSequence, -}; -use crate::lock::{ReadGuard, WriteGuard}; -use crate::query::options::Options; -use crate::system::{ - NoInitParamFlag as NoInitSystemParamFlag, - Param as SystemParam, - System, -}; -use crate::uid::Uid; -use crate::{EntityComponent, World}; - -pub mod options; - -#[derive(Debug)] -pub struct Query<'world, Comps, OptionsT = ()> -where - Comps: ComponentSequence, -{ - world: &'world World, - component_storage: ReadGuard<'world, ComponentStorage>, - _pd: PhantomData<(Comps, OptionsT)>, -} - -impl<'world, Comps, OptionsT> Query<'world, Comps, OptionsT> -where - Comps: ComponentSequence, - OptionsT: Options, -{ - /// Iterates over the entities matching this query. - #[must_use] - pub fn iter_mut( - &'world self, - ) -> ComponentIterMut<'world, Comps, QueryEntityIter<'world>> - { - #[cfg(feature = "debug")] - tracing::debug!("Searching for {}", std::any::type_name::<Comps>()); - - #[allow(clippy::map_flatten)] - ComponentIterMut { - world: self.world, - entities: self - .component_storage - .find_entities(Comps::metadata()) - .map(Archetype::entities as ComponentIterMapFn) - .flatten() - .filter(|entity| OptionsT::entity_filter(entity.components())), - comps_pd: PhantomData, - } - } - - /// Iterates over the entities matching this query. - #[must_use] - pub fn iter(&'world self) -> ComponentIter<'world, Comps, QueryEntityIter<'world>> - { - #[cfg(feature = "debug")] - tracing::debug!("Searching for {}", std::any::type_name::<Comps>()); - - #[allow(clippy::map_flatten)] - ComponentIter { - world: self.world, - entities: self - .component_storage - .find_entities(Comps::metadata()) - .map(Archetype::entities as ComponentIterMapFn) - .flatten() - .filter(|entity| OptionsT::entity_filter(entity.components())), - comps_pd: PhantomData, - } - } - - /// Iterates over the entities matching this query and has the provided extra - /// component. - #[must_use] - pub fn iter_with_extra_comps( - &'world self, - extra_components: impl IntoIterator<Item = ComponentMetadata>, - ) -> ComponentIter<'world, Comps, QueryEntityIter<'world>> - { - #[cfg(feature = "debug")] - tracing::debug!( - "Searching for {} + extra components", - std::any::type_name::<Comps>() - ); - - #[allow(clippy::map_flatten)] - ComponentIter { - world: self.world, - entities: self - .component_storage - .find_entities( - Comps::metadata() - .into_iter() - .chain(extra_components) - .collect::<Vec<_>>(), - ) - .map(Archetype::entities as ComponentIterMapFn) - .flatten() - .filter(|entity| OptionsT::entity_filter(entity.components())), - 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.component_storage - .find_entities(Comps::metadata()) - .flat_map(|archetype| archetype.entities()) - .filter(|entity| OptionsT::entity_filter(entity.components())) - .nth(entity_index)? - .uid(), - ) - } - - pub(crate) fn new(world: &'world World) -> Self - { - Self { - world, - component_storage: world - .data - .component_storage - .read_nonblock() - .expect("Failed to acquire read-only component storage lock"), - _pd: PhantomData, - } - } -} - -impl<'world, Comps, OptionsT> IntoIterator for &'world Query<'world, Comps, OptionsT> -where - Comps: ComponentSequence, - OptionsT: Options, -{ - type IntoIter = ComponentIterMut<'world, Comps, QueryEntityIter<'world>>; - type Item = Comps::MutRefs<'world>; - - fn into_iter(self) -> Self::IntoIter - { - self.iter_mut() - } -} - -unsafe impl<'world, Comps, OptionsT> SystemParam<'world> - for Query<'world, Comps, OptionsT> -where - Comps: ComponentSequence, - OptionsT: Options, -{ - type Flags = NoInitSystemParamFlag; - 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) - } -} - -type ComponentIterMapFn = for<'a> fn(&'a Archetype) -> EntityIter<'a>; - -type ComponentIterFilterFn = for<'a, 'b> fn(&'a &'b ArchetypeEntity) -> bool; - -type QueryEntityIter<'world> = Filter< - Flatten<Map<ArchetypeRefIter<'world>, ComponentIterMapFn>>, - ComponentIterFilterFn, ->; - -pub struct ComponentIterMut<'world, Comps, EntityIter> -where - EntityIter: Iterator<Item = &'world ArchetypeEntity>, -{ - world: &'world World, - entities: EntityIter, - comps_pd: PhantomData<Comps>, -} - -impl<'world, Comps, EntityIter> Iterator for ComponentIterMut<'world, Comps, EntityIter> -where - Comps: ComponentSequence + 'world, - EntityIter: Iterator<Item = &'world ArchetypeEntity>, -{ - type Item = Comps::MutRefs<'world>; - - fn next(&mut self) -> Option<Self::Item> - { - Some(Comps::from_components_mut( - self.entities.next()?.components().iter(), - self.world, - lock_component_rw, - )) - } -} - -fn lock_component_rw( - entity_component: &EntityComponent, -) -> WriteGuard<'_, Box<dyn Component>> -{ - entity_component - .component - .write_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to acquire read-write lock to component {}", - entity_component.name - ); - }) -} - -pub struct ComponentIter<'world, Comps, EntityIter> -where - EntityIter: Iterator<Item = &'world ArchetypeEntity>, -{ - world: &'world World, - entities: EntityIter, - comps_pd: PhantomData<Comps>, -} - -impl<'world, Comps, EntityIter> Iterator for ComponentIter<'world, Comps, EntityIter> -where - Comps: ComponentSequence + 'world, - EntityIter: Iterator<Item = &'world ArchetypeEntity>, -{ - type Item = Comps::Refs<'world>; - - fn next(&mut self) -> Option<Self::Item> - { - Some(Comps::from_components( - self.entities.next()?.components().iter(), - self.world, - lock_component_ro, - )) - } -} - -fn lock_component_ro( - entity_component: &EntityComponent, -) -> ReadGuard<'_, Box<dyn Component>> -{ - entity_component - .component - .read_nonblock() - .unwrap_or_else(|_| { - panic!( - "Failed to acquire read-write lock to component {}", - entity_component.name - ); - }) -} diff --git a/ecs/src/query/options.rs b/ecs/src/query/options.rs deleted file mode 100644 index bbbe0a8..0000000 --- a/ecs/src/query/options.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::collections::HashSet; -use std::marker::PhantomData; - -use crate::component::Component; -use crate::EntityComponent; - -/// Query options. -pub trait Options -{ - fn entity_filter<'component>( - components: impl IntoIterator<Item = &'component EntityComponent>, - ) -> bool; -} - -impl Options for () -{ - fn entity_filter<'component>( - _: impl IntoIterator<Item = &'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: impl IntoIterator<Item = &'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: impl IntoIterator<Item = &'component EntityComponent>, - ) -> bool - { - !OptionsT::entity_filter(components) - } -} diff --git a/ecs/src/relationship.rs b/ecs/src/relationship.rs deleted file mode 100644 index 0ebd9c2..0000000 --- a/ecs/src/relationship.rs +++ /dev/null @@ -1,418 +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, - FromOptional as FromOptionalComponent, - FromOptionalMut as FromOptionalMutComponent, -}; -use crate::lock::ReadGuard; -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> 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> 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(), - } - } - - /// 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) - } -} diff --git a/ecs/src/sole.rs b/ecs/src/sole.rs deleted file mode 100644 index 084a06b..0000000 --- a/ecs/src/sole.rs +++ /dev/null @@ -1,186 +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::{NoInitParamFlag, 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, - } - } -} - -unsafe impl<'world, SoleT> SystemParam<'world> for Single<'world, SoleT> -where - SoleT: Sole, -{ - type Flags = NoInitParamFlag; - 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 046d25b..0000000 --- a/ecs/src/system.rs +++ /dev/null @@ -1,316 +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 std::panic::{RefUnwindSafe, UnwindSafe}; - -use seq_macro::seq; - -use crate::component::{ - Component, - FromOptional as FromOptionalComponent, - FromOptionalMut as FromOptionalMutComponent, -}; -use crate::lock::{ReadGuard, WriteGuard}; -use crate::tuple::{ReduceElement as TupleReduceElement, With as TupleWith}; -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 + RefUnwindSafe + UnwindSafe + 'static, - #(TParam~I: Param<'world, Flags = NoInitParamFlag>,)* - { - 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 + RefUnwindSafe + UnwindSafe>, - 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) + RefUnwindSafe + UnwindSafe; - -/// A parameter to a [`System`]. -pub unsafe trait Param<'world> -{ - type Input; - type Flags; - - 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; -} - -pub struct NoInitParamFlag {} - -/// 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: TupleWith<Self>, -{ - type Return = Accumulator::With; -} - -impl<Accumulator> TupleReduceElement<Accumulator, ParamWithInputFilter> for () -{ - type Return = Accumulator; -} - -#[derive(Debug)] -pub struct ComponentRefMut<'a, ComponentT: Component> -{ - inner: WriteGuard<'a, Box<dyn Component>>, - _ph: PhantomData<ComponentT>, -} - -impl<'a, ComponentT: Component> ComponentRefMut<'a, ComponentT> -{ - pub(crate) fn new(inner: WriteGuard<'a, Box<dyn Component>>) -> Self - { - Self { inner, _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 { - inner: inner.unwrap_or_else(|| { - panic!( - "Component {} was not found in entity", - type_name::<ComponentT>() - ); - }), - _ph: PhantomData, - } - } -} - -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<'a, ComponentT: Component> Deref for ComponentRefMut<'a, ComponentT> -{ - type Target = ComponentT; - - fn deref(&self) -> &Self::Target - { - self.inner.downcast_ref().unwrap() - } -} - -impl<'a, ComponentT: Component> DerefMut for ComponentRefMut<'a, ComponentT> -{ - fn deref_mut(&mut self) -> &mut Self::Target - { - self.inner.downcast_mut().unwrap() - } -} - -#[derive(Debug)] -pub struct ComponentRef<'a, ComponentT: Component> -{ - inner: ReadGuard<'a, Box<dyn Component>>, - _ph: PhantomData<ComponentT>, -} - -impl<'a, ComponentT: Component> ComponentRef<'a, ComponentT> -{ - pub(crate) fn new(inner: ReadGuard<'a, Box<dyn Component>>) -> Self - { - Self { inner, _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 { - inner: inner.unwrap_or_else(|| { - panic!( - "Component {} was not found in entity", - type_name::<ComponentT>() - ); - }), - _ph: PhantomData, - } - } -} - -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<'a, ComponentT: Component> Deref for ComponentRef<'a, ComponentT> -{ - type Target = ComponentT; - - fn deref(&self) -> &Self::Target - { - self.inner.downcast_ref().unwrap() - } -} diff --git a/ecs/src/system/stateful.rs b/ecs/src/system/stateful.rs deleted file mode 100644 index 536e6ed..0000000 --- a/ecs/src/system/stateful.rs +++ /dev/null @@ -1,165 +0,0 @@ -use std::any::{type_name, Any, TypeId}; -use std::collections::HashMap; -use std::panic::{RefUnwindSafe, UnwindSafe}; - -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::{ - IntoInOptions as TupleIntoInOptions, - Reduce as TupleReduce, - TakeOptionElementResult as TupleTakeOptionElementResult, - WithOptionElements as TupleWithOptionElements, -}; -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>, - <(#(TParam~I::Input,)*) as TupleReduce<ParamWithInputFilter>>::Out: - TupleIntoInOptions - { - 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(); - - #( - if TypeId::of::<TParam~I::Input>() != - TypeId::of::<()>() - { - let input = match option_input.take::<TParam~I::Input>() { - TupleTakeOptionElementResult::Found(input) => input, - TupleTakeOptionElementResult::NotFound => { - panic!( - "Parameter input {} not found", - type_name::<TParam~I::Input>() - ); - } - TupleTakeOptionElementResult::AlreadyTaken => { - panic!( - concat!( - "Parameter {} is already initialized. ", - "System cannot contain multiple inputs with ", - "the same type", - ), - type_name::<TParam~I>() - ); - - } - }; - - TParam~I::initialize( - &mut self, - input - ); - } - )* - - 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 1434592..0000000 --- a/ecs/src/tuple.rs +++ /dev/null @@ -1,212 +0,0 @@ -use std::any::TypeId; -use std::mem::{transmute_copy, ManuallyDrop}; - -use paste::paste; -use seq_macro::seq; -use util_macros::sub; - -/// Used to append a element to a tuple type. -pub trait With<OtherElem> -{ - type With; -} - -/// Used to remove the last element of a tuple type. -/// -/// For example: `(u32, String, PathBuf)` becomes `(u32, String)`. -pub trait WithoutLast -{ - type Return; -} - -/// Used to make all elements of a tuple type wrapped in [`Option`]. -pub trait IntoInOptions -{ - type InOptions: WithOptionElements; - - fn into_in_options(self) -> Self::InOptions; -} - -/// A tuple with all elements wrapped in [`Option`]. -pub trait WithOptionElements -{ - fn take<Element: 'static>(&mut self) -> TakeOptionElementResult<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; -} - -/// The result of trying to [`take`] a element from a implementation of -/// [`WithOptionElements`]. -/// -/// [`take`]: WithOptionElements::take -pub enum TakeOptionElementResult<Element> -{ - /// The element was succesfully taken. - Found(Element), - - /// The element is not a element of the tuple. - NotFound, - - /// The element has already been taken - AlreadyTaken, -} - -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 - }; -} - -pub trait Pop: WithoutLast -{ - type LastElem; - - fn pop(self) -> (<Self as WithoutLast>::Return, Self::LastElem); -} - -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<OtherElem, #(Elem~I,)*> With<OtherElem> for (#(Elem~I,)*) - { - type With = (#(Elem~I,)* OtherElem,); - } - - impl<#(Elem~I,)*> WithoutLast for (#(Elem~I,)*) - { - type Return = all_except_last!(start #(Elem~I)*); - } - - impl<#(Element~I: 'static,)*> IntoInOptions for (#(Element~I,)*) - { - type InOptions = (#(Option<Element~I>,)*); - - fn into_in_options(self) -> Self::InOptions - { - #![allow(clippy::unused_unit)] - (#(Some(self.I),)*) - } - } - - impl<#(Element~I: 'static,)*> WithOptionElements for (#(Option<Element~I>,)*) - { - fn take<Element: 'static>(&mut self) - -> TakeOptionElementResult<Element> - { - #( - if TypeId::of::<Element~I>() == TypeId::of::<Element>() { - let input = match self.I.take() { - Some(input) => ManuallyDrop::new(input), - None => { - return TakeOptionElementResult::AlreadyTaken; - } - }; - - return TakeOptionElementResult::Found( - // SAFETY: It can be transmuted safely since it is the - // same type and the type is 'static - unsafe { transmute_copy(&input) } - ); - } - )* - - TakeOptionElementResult::NotFound - } - } - - 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); - } - } - - impl<#(Elem~I,)*> Pop for (#(Elem~I,)*) - { - type LastElem = sub!($cnt - 1, elem_type_by_index); - - fn pop(self) -> (<Self as WithoutLast>::Return, Self::LastElem) - { - ( - all_except_last!(start #((self.I))*), - sub!($cnt - 1, elem_by_index, (self)) - ) - } - } - }); - }; -} - -seq!(N in 0..16 { - impl_tuple_traits!(N); -}); 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 0e5d88a..0000000 --- a/ecs/src/uid.rs +++ /dev/null @@ -1,43 +0,0 @@ -use std::mem::transmute; -use std::sync::atomic::{AtomicU32, Ordering}; - -static NEXT: AtomicU32 = AtomicU32::new(1); - -// Bit 0 and 1 for the kind -const KIND_BITS: u64 = 0x03; - -#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)] -#[repr(u8)] -pub enum Kind -{ - Entity = 2, - Component = 1, -} - -/// Unique entity/component ID. -#[derive(Debug, 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_part = NEXT.fetch_add(1, Ordering::Relaxed); - - Self { - inner: (u64::from(id_part) << 32) | kind as u64, - } - } - - #[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 & KIND_BITS) as u8) } - } -} diff --git a/ecs/src/util.rs b/ecs/src/util.rs deleted file mode 100644 index 4480fc8..0000000 --- a/ecs/src/util.rs +++ /dev/null @@ -1,48 +0,0 @@ -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); - } -} |
