diff --git a/quill/api/src/hlist.rs b/quill/api/src/hlist.rs new file mode 100644 index 000000000..49bda1fc3 --- /dev/null +++ b/quill/api/src/hlist.rs @@ -0,0 +1,174 @@ +use std::marker::PhantomData; + +pub struct HCons { + pub head: Head, + pub tail: Tail, +} + +pub trait HList: Sized { + type Tuple: Tuple; + + fn flatten(self) -> Self::Tuple; +} + +pub trait Tuple: Sized { + type HList: HList; + + fn hlist(self) -> Self::HList; +} + +impl HList for () { + type Tuple = (); + + #[inline] + fn flatten(self) -> Self::Tuple {} +} + +impl Tuple for () { + type HList = (); + + #[inline] + fn hlist(self) -> Self::HList {} +} + +macro_rules! HList { + () => { () }; + ($head:ty $(,$tail:ty)* $(,)?) => { + HCons<$head, HList!($($tail),*)> + }; +} + +macro_rules! hlist_pat { + () => { () }; + ($head:ident $(,$tail:ident)* $(,)?) => { + HCons { + head: $head, + tail: hlist_pat!($($tail),*) + } + }; +} + +macro_rules! impl_tuple { + ($head:ident $(,$tail:ident)* $(,)?) => { + impl<$head $(,$tail)*> HList for HList!($head $(,$tail)*) { + type Tuple = ($head, $($tail),*); + + #[inline] + fn flatten(self) -> Self::Tuple { + #[allow(non_snake_case)] + let hlist_pat!($head, $($tail),*) = self; + ($head, $($tail),*) + } + } + + impl<$head $(,$tail)*> Tuple for ($head, $($tail),*) { + type HList = HCons<$head, <($($tail,)*) as Tuple>::HList>; + + #[inline] + fn hlist(self) -> Self::HList { + #[allow(non_snake_case)] + let ($head, $($tail),*) = self; + HCons { + head: $head, + tail: ($($tail,)*).hlist(), + } + } + } + }; +} + +macro_rules! smaller_tuples_too { + ($macro:ident, $head:ident $(,)?) => { + $macro!($head); + }; + ($macro:ident, $head:ident, $($tail:ident),* $(,)?) => { + $macro!($head, $($tail),*); + smaller_tuples_too!($macro, $($tail),*); + }; +} + +smaller_tuples_too!( + impl_tuple, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, + T19, T20 +); + +pub trait Plucker { + type Remainder; + + fn pluck(self) -> (Target, Self::Remainder); +} + +pub trait PluckerRef { + fn pluck(&self) -> &Target; +} + +pub trait PluckerMut { + fn pluck(&mut self) -> &mut Target; +} + +pub struct Here(); + +impl Plucker for HCons { + type Remainder = Tail; + + #[inline] + fn pluck(self) -> (Target, Self::Remainder) { + (self.head, self.tail) + } +} + +impl PluckerRef for HCons<&'_ Target, Tail> { + #[inline] + fn pluck(&self) -> &Target { + &self.head + } +} + +impl PluckerMut for HCons<&'_ mut Target, Tail> { + #[inline] + fn pluck(&mut self) -> &mut Target { + &mut self.head + } +} + +pub struct There(PhantomData); + +impl Plucker> for HCons +where + Tail: Plucker, +{ + type Remainder = HCons>::Remainder>; + + #[inline] + fn pluck(self) -> (Target, Self::Remainder) { + let (target, tail_remainder): (Target, >::Remainder) = + >::pluck(self.tail); + ( + target, + HCons { + head: self.head, + tail: tail_remainder, + }, + ) + } +} + +impl PluckerRef> for HCons +where + Tail: PluckerRef, +{ + #[inline] + fn pluck(&self) -> &Target { + >::pluck(&self.tail) + } +} + +impl PluckerMut> for HCons +where + Tail: PluckerMut, +{ + #[inline] + fn pluck(&mut self) -> &mut Target { + >::pluck(&mut self.tail) + } +} diff --git a/quill/api/src/lib.rs b/quill/api/src/lib.rs index 658995958..3b6d43727 100644 --- a/quill/api/src/lib.rs +++ b/quill/api/src/lib.rs @@ -4,12 +4,15 @@ pub mod entities; mod entity; mod entity_builder; mod game; +pub mod hlist; pub mod query; +pub mod send_message; mod setup; pub use entity::{Entity, EntityId}; pub use entity_builder::EntityBuilder; pub use game::Game; +pub use hlist::*; pub use setup::Setup; #[doc(inline)] diff --git a/quill/api/src/query.rs b/quill/api/src/query.rs index 64da4919e..7c8170ed7 100644 --- a/quill/api/src/query.rs +++ b/quill/api/src/query.rs @@ -4,7 +4,7 @@ use std::{marker::PhantomData, mem::MaybeUninit}; use quill_common::{entity::QueryData, Component, HostComponent, PointerMut}; -use crate::{Entity, EntityId}; +use crate::{Entity, EntityId, Tuple}; /// A type that can be used for a query. /// @@ -65,24 +65,19 @@ where macro_rules! impl_query_tuple { ($($query:ident),* $(,)?) => { impl <$($query: Query),*> Query for ($($query,)*) { - type Item = ($($query::Item),*); + type Item = ($($query::Item,)*); fn add_component_types(types: &mut Vec) { - $( - $query::add_component_types(types); - )* + $($query::add_component_types(types);)* } unsafe fn get_unchecked(data: &QueryData, component_index: &mut usize, component_offsets: &mut [usize]) -> Self::Item { - ( - $( - $query::get_unchecked(data, component_index, component_offsets) - ),* - ) + ($($query::get_unchecked(data, component_index, component_offsets),)*) } } } } +impl_query_tuple!(A); impl_query_tuple!(A, B); impl_query_tuple!(A, B, C); impl_query_tuple!(A, B, C, D); @@ -137,6 +132,7 @@ where impl Iterator for QueryIter where Q: Query, + ::Item: Tuple, { type Item = (Entity, Q::Item); diff --git a/quill/api/src/send_message.rs b/quill/api/src/send_message.rs new file mode 100644 index 000000000..43cc809c3 --- /dev/null +++ b/quill/api/src/send_message.rs @@ -0,0 +1,17 @@ +use quill_common::entities::Player; + +use crate::{Entity, PluckerRef, Tuple}; + +pub trait SendMessage { + fn send_message(&self, message: &str); +} + +impl SendMessage for (&'_ Entity, T) +where + T: Tuple, + ::HList: PluckerRef, +{ + fn send_message(&self, _message: &str) { + // let _player: &Player = PluckerRef::::pluck(self.1.hlist()); + } +} diff --git a/quill/example-plugins/block-place/src/lib.rs b/quill/example-plugins/block-place/src/lib.rs index fa1be6692..651d890bf 100644 --- a/quill/example-plugins/block-place/src/lib.rs +++ b/quill/example-plugins/block-place/src/lib.rs @@ -16,7 +16,7 @@ impl Plugin for BlockPlace { } fn system(_plugin: &mut BlockPlace, game: &mut Game) { - for (_entity, _event) in game.query::<&BlockPlacementEvent>() { + for (_entity, _event) in game.query::<(&BlockPlacementEvent,)>() { println!("A client has placed a block!"); } } diff --git a/quill/example-plugins/query-entities/src/lib.rs b/quill/example-plugins/query-entities/src/lib.rs index c5851b0af..791d137e4 100644 --- a/quill/example-plugins/query-entities/src/lib.rs +++ b/quill/example-plugins/query-entities/src/lib.rs @@ -1,7 +1,11 @@ //! An example plugin that spawns 10,000 entities //! on startup, then moves them each tick using a query. -use quill::{entities::PiglinBrute, EntityInit, Game, Plugin, Position}; +use quill::{ + entities::{PiglinBrute, Player}, + send_message::SendMessage, + EntityInit, Game, Plugin, Position, +}; use rand::Rng; quill::plugin!(QueryEntities); @@ -47,4 +51,8 @@ fn query_system(plugin: &mut QueryEntities, game: &mut Game) { ..position }); } + + for (entity, (player,)) in game.query::<(&Player,)>() { + (&entity, (&player,)).send_message("foo"); + } }