From 4632dd8e9e95a377993ef677a157202fda8072f9 Mon Sep 17 00:00:00 2001 From: Dominik Kaiser Date: Tue, 2 Jun 2026 23:23:57 +0200 Subject: Implement ECS --- src/query.rs | 444 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 444 insertions(+) create mode 100644 src/query.rs (limited to 'src/query.rs') diff --git a/src/query.rs b/src/query.rs new file mode 100644 index 0000000..658185b --- /dev/null +++ b/src/query.rs @@ -0,0 +1,444 @@ +use super::Entity; +use super::component::{Component, ComponentStorage}; + +pub trait Query<'a, W> { + type Item; + fn run(world: &'a W) -> impl Iterator; +} + +pub trait QueryMut<'a, W> { + type Item; + fn run_mut(world: &'a mut W) -> impl Iterator; +} + +impl<'a, W, A> Query<'a, W> for A +where + W: ComponentStorage, + A: Component + 'a, +{ + type Item = &'a A; + fn run(world: &'a W) -> impl Iterator { + ComponentStorage::::storage(world).iter().map(|(_, a)| a) + } +} + +impl<'a, W, A> QueryMut<'a, W> for A +where + W: ComponentStorage, + A: Component + 'a, +{ + type Item = &'a mut A; + + fn run_mut(world: &'a mut W) -> impl Iterator { + let a_ptr = >::storage_ptr(world); + + unsafe { + let a_ref = &mut *a_ptr; + a_ref.iter_mut().map(|(_, a_comp)| a_comp) + } + } +} + +impl<'a, W, A> Query<'a, W> for (A,) +where + W: ComponentStorage, + A: Component + 'a, +{ + type Item = &'a A; + fn run(world: &'a W) -> impl Iterator { + ComponentStorage::::storage(world).iter().map(|(_, a)| a) + } +} + +impl<'a, W, A> QueryMut<'a, W> for (A,) +where + W: ComponentStorage, + A: Component + 'a, +{ + type Item = &'a mut A; + + fn run_mut(world: &'a mut W) -> impl Iterator { + let a_ptr = >::storage_ptr(world); + + unsafe { + let a_ref = &mut *a_ptr; + a_ref.iter_mut().map(|(_, a_comp)| a_comp) + } + } +} + +impl<'a, W, A> Query<'a, W> for (Entity, A) +where + W: ComponentStorage, + A: Component + 'a, +{ + type Item = (Entity, &'a A); + fn run(world: &'a W) -> impl Iterator { + ComponentStorage::::storage(world).iter() + } +} + +macro_rules! impl_query { + ( + $first:ident + $(, $rest:ident)+ + ) => { + #[allow(non_snake_case)] + impl<'a, W, $first, $($rest),+> Query<'a, W> + for ($first, $($rest),+) + where + $first: Component + 'a, + $( + $rest: Component + 'a, + )+ + W: ComponentStorage<$first> + $(+ ComponentStorage<$rest>)+, + { + type Item = ( + &'a $first, + $( + &'a $rest, + )+ + ); + + fn run(world: &'a W) -> impl Iterator { + let first_storage = + >::storage(world); + + $( + let $rest = + >::storage(world); + )+ + + first_storage.iter().filter_map(move |(entity, first_comp)| { + $( + let $rest = $rest.get(entity)?; + )+ + + Some(( + first_comp, + $( + $rest, + )+ + )) + }) + } + } + + #[allow(non_snake_case)] + impl<'a, W, $first, $($rest),+> Query<'a, W> + for (Entity, $first, $($rest),+) + where + $first: Component + 'a, + $( + $rest: Component + 'a, + )+ + W: ComponentStorage<$first> + $(+ ComponentStorage<$rest>)+, + { + type Item = ( + Entity, + &'a $first, + $( + &'a $rest, + )+ + ); + + fn run(world: &'a W) -> impl Iterator { + let first_storage = + >::storage(world); + + $( + let $rest = + >::storage(world); + )+ + + first_storage.iter().filter_map(move |(entity, first_comp)| { + $( + let $rest = $rest.get(entity)?; + )+ + + Some(( + entity, + first_comp, + $( + $rest, + )+ + )) + }) + } + } + }; +} + +macro_rules! impl_query_mut { + ( + $first:ident + $(, $rest:ident)* + ) => { + #[allow(non_snake_case)] + impl<'a, W, $first, $($rest),*> QueryMut<'a, W> + for ($first, $($rest),*) + where + $first: Component + 'a, + $( + $rest: Component + 'a, + )* + W: ComponentStorage<$first> + $(+ ComponentStorage<$rest>)*, + { + type Item = ( + &'a mut $first, + $( + &'a mut $rest, + )* + ); + + fn run_mut(world: &'a mut W) -> impl Iterator { + let first_ptr = + >::storage_ptr(world); + + $( + let $rest = + >::storage_ptr(world); + )* + + unsafe { + let first_ref = &mut *first_ptr; + + first_ref.iter_mut().filter_map(move |(entity, first_comp)| { + $( + let $rest = + (*$rest).get_mut(entity)?; + )* + + Some(( + first_comp, + $( + $rest, + )* + )) + }) + } + } + } + + #[allow(non_snake_case)] + impl<'a, W, $first, $($rest),*> QueryMut<'a, W> + for (Entity, $first, $($rest),*) + where + $first: Component + 'a, + $( + $rest: Component + 'a, + )* + W: ComponentStorage<$first> + $(+ ComponentStorage<$rest>)*, + { + type Item = ( + Entity, + &'a mut $first, + $( + &'a mut $rest, + )* + ); + + fn run_mut(world: &'a mut W) -> impl Iterator { + let first_ptr = + >::storage_ptr(world); + + $( + let $rest = + >::storage_ptr(world); + )* + + unsafe { + let first_ref = &mut *first_ptr; + + first_ref.iter_mut().filter_map(move |(entity, first_comp)| { + $( + let $rest = + (*$rest).get_mut(entity)?; + )* + + Some(( + entity, + first_comp, + $( + $rest, + )* + )) + }) + } + } + } + }; +} + +macro_rules! impl_query_mut_opt { + ( + $first:ident + $(, $req:ident)* + => + $($opt:ident ?),* $(,)? + ) => { + #[allow(non_snake_case)] + impl<'a, W, $first, $($req,)* $($opt,)*> QueryMut<'a, W> + for ( + $first, + $($req,)* + $(Option<$opt>,)* + ) + where + W: ComponentStorage<$first> + $(+ ComponentStorage<$req>)* + $(+ ComponentStorage<$opt>)*, + $first: Component + 'a, + $( + $req: Component + 'a, + )* + $( + $opt: Component + 'a, + )* + { + type Item = ( + &'a mut $first, + $( + &'a mut $req, + )* + $( + Option<&'a mut $opt>, + )* + ); + + fn run_mut(world: &'a mut W) -> impl Iterator { + let first_ptr = + >::storage_ptr(world); + + $( + let $req = + >::storage_ptr(world); + )* + + $( + let $opt = + >::storage_ptr(world); + )* + + unsafe { + let first_ref = &mut *first_ptr; + + first_ref.iter_mut().filter_map(move |(entity, first_comp)| { + $( + let $req = + (*$req).get_mut(entity)?; + )* + + Some(( + first_comp, + $( + $req, + )* + $( + (*$opt).get_mut(entity), + )* + )) + }) + } + } + } + + #[allow(non_snake_case)] + impl<'a, W, $first, $($req,)* $($opt,)*> QueryMut<'a, W> + for ( + Entity, + $first, + $($req,)* + $(Option<$opt>,)* + ) + where + W: ComponentStorage<$first> + $(+ ComponentStorage<$req>)* + $(+ ComponentStorage<$opt>)*, + $first: Component + 'a, + $( + $req: Component + 'a, + )* + $( + $opt: Component + 'a, + )* + { + type Item = ( + Entity, + &'a mut $first, + $( + &'a mut $req, + )* + $( + Option<&'a mut $opt>, + )* + ); + + fn run_mut(world: &'a mut W) -> impl Iterator { + let first_ptr = + >::storage_ptr(world); + + $( + let $req = + >::storage_ptr(world); + )* + + $( + let $opt = + >::storage_ptr(world); + )* + + unsafe { + let first_ref = &mut *first_ptr; + + first_ref.iter_mut().filter_map(move |(entity, first_comp)| { + $( + let $req = + (*$req).get_mut(entity)?; + )* + + Some(( + entity, + first_comp, + $( + $req, + )* + $( + (*$opt).get_mut(entity), + )* + )) + }) + } + } + } + }; +} + +impl_query!(A, B); +impl_query!(A, B, C); +impl_query!(A, B, C, D); +impl_query!(A, B, C, D, E); +impl_query!(A, B, C, D, E, F); + +impl_query_mut!(A, B); +impl_query_mut!(A, B, C); +impl_query_mut!(A, B, C, D); +impl_query_mut!(A, B, C, D, E); +impl_query_mut!(A, B, C, D, E, F); + +impl_query_mut_opt!(A => B?); +impl_query_mut_opt!(A, B => C?); +impl_query_mut_opt!(A, B, C => D?); +impl_query_mut_opt!(A, B, C, D => E?); +impl_query_mut_opt!(A, B, C, D, E => F?); +impl_query_mut_opt!(A => B?, C?); +impl_query_mut_opt!(A, B => C?, D?); +impl_query_mut_opt!(A, B, C => D?, E?); +impl_query_mut_opt!(A, B, C, D => E?, F?); +impl_query_mut_opt!(A => B?, C?, D?); +impl_query_mut_opt!(A, B => C?, D?, E?); +impl_query_mut_opt!(A, B, C => D?, E?, F?); -- cgit v1.2.3