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