summaryrefslogtreecommitdiff
path: root/ecs
diff options
context:
space:
mode:
Diffstat (limited to 'ecs')
-rw-r--r--ecs/Cargo.toml17
-rw-r--r--ecs/examples/event_loop.rs97
-rw-r--r--ecs/examples/extension.rs77
-rw-r--r--ecs/examples/multiple_queries.rs85
-rw-r--r--ecs/examples/optional_component.rs86
-rw-r--r--ecs/examples/relationship.rs48
-rw-r--r--ecs/examples/simple.rs42
-rw-r--r--ecs/examples/with_local.rs77
-rw-r--r--ecs/examples/with_sole.rs59
-rw-r--r--ecs/src/actions.rs146
-rw-r--r--ecs/src/archetype.rs61
-rw-r--r--ecs/src/component.rs333
-rw-r--r--ecs/src/component/local.rs62
-rw-r--r--ecs/src/component/storage.rs621
-rw-r--r--ecs/src/entity.rs32
-rw-r--r--ecs/src/event.rs96
-rw-r--r--ecs/src/event/component.rs124
-rw-r--r--ecs/src/event/start.rs7
-rw-r--r--ecs/src/extension.rs59
-rw-r--r--ecs/src/lib.rs532
-rw-r--r--ecs/src/lock.rs162
-rw-r--r--ecs/src/private.rs2
-rw-r--r--ecs/src/query.rs273
-rw-r--r--ecs/src/query/options.rs66
-rw-r--r--ecs/src/relationship.rs418
-rw-r--r--ecs/src/sole.rs186
-rw-r--r--ecs/src/stats.rs8
-rw-r--r--ecs/src/system.rs316
-rw-r--r--ecs/src/system/stateful.rs165
-rw-r--r--ecs/src/tuple.rs212
-rw-r--r--ecs/src/type_name.rs15
-rw-r--r--ecs/src/uid.rs43
-rw-r--r--ecs/src/util.rs48
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);
- }
-}