From 9e72f30c148820282161d6eabc3bf14ad03c8486 Mon Sep 17 00:00:00 2001 From: SOFe Date: Sat, 7 Oct 2023 17:55:57 +0800 Subject: [PATCH] feat(accessor): derive traits for AccessSingle --- Cargo.toml | 9 +++ src/comp/any.rs | 38 +++++++++--- src/system/access.rs | 4 +- src/system/access/isotope.rs | 2 +- src/system/access/iter.rs | 5 ++ src/system/access/iter/tuple_impls.rs | 31 +++++++--- src/system/access/single.rs | 86 +++++++++++++++++---------- 7 files changed, 126 insertions(+), 49 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 33f0aaacde..cf9a60b0f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,11 +27,20 @@ rayon = "1.5.2" static_assertions = "1.1.0" strum = {version = "0.24.0", optional = true} xias = "0.3.0" +derive-trait = "0.0.1" [features] default = ["debug-entity-rc"] debug-entity-rc = [] # Enable entity refcounting in debug mode. release-entity-rc = [] # Enable entity refcounting in debug mode. +tuple-impl-32-zip = ["tuple-impl-24-zip"] +tuple-impl-24-zip = ["tuple-impl-16-zip"] +tuple-impl-16-zip = ["tuple-impl-8-zip"] +tuple-impl-8-zip = [] +tuple-impl-32-init-fn = ["tuple-impl-24-init-fn"] +tuple-impl-24-init-fn = ["tuple-impl-16-init-fn"] +tuple-impl-16-init-fn = ["tuple-impl-8-init-fn"] +tuple-impl-8-init-fn = [] internal-bench = ["env_logger", "strum"] # Internal feature: enable benchmarking utils. [dev-dependencies] diff --git a/src/comp/any.rs b/src/comp/any.rs index a91eb18f83..d7df090504 100644 --- a/src/comp/any.rs +++ b/src/comp/any.rs @@ -106,7 +106,7 @@ pub(crate) trait DepGetterInner { } macro_rules! impl_simple_init_fn { - ($($deps:ident),* $(,)?) => { + ($($deps:ident)*) => { impl< A: Archetype, C: comp::SimpleOrIsotope, $($deps: comp::Simple,)* @@ -142,17 +142,37 @@ macro_rules! impl_simple_init_fn { } macro_rules! impl_simple_init_fn_accumulate { - () => { - impl_simple_init_fn!(); + ($feature:literal $first:ident $($rest:tt)*) => { + impl_simple_init_fn_accumulate!($feature $($rest)*); + #[cfg(feature = $feature)] + impl_simple_init_fn_accumulate!(@MIXED $first $($rest)*); + }; + ($outer_feature:literal $inner_feature:literal $($rest:tt)*) => { + impl_simple_init_fn_accumulate!($inner_feature $($rest)*); + }; + ($outer_feature:literal @ALWAYS $($rest:tt)*) => { + impl_simple_init_fn_accumulate!(@ALWAYS $($rest)*); + }; + (@ALWAYS $first:ident $($rest:tt)*) => { + impl_simple_init_fn_accumulate!(@ALWAYS $($rest)*); + impl_simple_init_fn!($first $($rest)*); + }; + (@ALWAYS) => { + #[allow(unused_variables)] + const _: () = { + impl_simple_init_fn!(); + }; + }; + (@MIXED $($idents_front:ident)* $($feature:literal $($idents_feature:ident)*)* @ALWAYS $($idents_always:ident)*) => { + impl_simple_init_fn!($($idents_front)* $($($idents_feature)*)* $($idents_always)*); }; - ($first:ident $(, $rest:ident)* $(,)?) => { - impl_simple_init_fn_accumulate!($($rest),*); - impl_simple_init_fn!($first $(, $rest)*); - } } impl_simple_init_fn_accumulate!( - P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15, P16, P17, P18, P19, P20, P21, - P22, P23, P24, P25, P26, P27, P28, P29, P30, P31, P32, + "tuple-impl-32-init-fn" T1 T2 T3 T4 T5 T6 T7 T8 + "tuple-impl-24-init-fn" T9 T10 T11 T12 T13 T14 T15 T16 + "tuple-impl-16-init-fn" T17 T18 T19 T20 T21 T22 T23 T24 + "tuple-impl-8-init-fn" T25 T26 T27 T28 + @ALWAYS T29 T30 T31 T32 ); #[cfg(test)] diff --git a/src/system/access.rs b/src/system/access.rs index c1a15a121f..803afe5517 100644 --- a/src/system/access.rs +++ b/src/system/access.rs @@ -1,7 +1,7 @@ //! Access component storages in the world. -mod single; -pub use single::AccessSingle; +pub mod single; +pub use single::Single as AccessSingle; mod isotope; pub use isotope::AccessIsotope; diff --git a/src/system/access/isotope.rs b/src/system/access/isotope.rs index 6e78c9f960..171d736b0b 100644 --- a/src/system/access/isotope.rs +++ b/src/system/access/isotope.rs @@ -2,7 +2,7 @@ use std::marker::PhantomData; use std::{any, fmt, ops}; use crate::storage::Access as _; -use crate::system::access::AccessSingle; +use crate::system::AccessSingle; use crate::{comp, entity, Archetype, Storage as _}; /// Accesses multiple storages for the same isotope. diff --git a/src/system/access/iter.rs b/src/system/access/iter.rs index a0d04da707..519f406d64 100644 --- a/src/system/access/iter.rs +++ b/src/system/access/iter.rs @@ -40,6 +40,11 @@ pub trait ZipChunked: Zip { /// - Any of the above wrapped with [`Try`] for [optional](comp::Presence::Optional) components. /// - Tuples of `Zip` implementors, including other tuples. /// - Structs of `Zip` fields that use the [`Zip`](crate::zip) derive macro. +/// +/// The default configuration only implements for tuples of up to 4 elements. +/// To use larger tuples at the cost of slower compile time, +/// use the feature `"tuple-impl-{n}-zip"`, +/// where `{n}` is `8`, `16`, `24` or `32`. pub trait IntoZip { /// The [`Zip`] type that this is converted into. type IntoZip: Zip; diff --git a/src/system/access/iter/tuple_impls.rs b/src/system/access/iter/tuple_impls.rs index c8e43c3ee8..d9e97c9f84 100644 --- a/src/system/access/iter/tuple_impls.rs +++ b/src/system/access/iter/tuple_impls.rs @@ -62,19 +62,36 @@ macro_rules! impl_zip_for_tuple { } macro_rules! impl_zip_for_tuple_accumulate { - () => { + ($feature:literal $first:ident $($rest:tt)*) => { + impl_zip_for_tuple_accumulate!($feature $($rest)*); + #[cfg(feature = $feature)] + impl_zip_for_tuple_accumulate!(@MIXED $first $($rest)*); + }; + ($outer_feature:literal $inner_feature:literal $($rest:tt)*) => { + impl_zip_for_tuple_accumulate!($inner_feature $($rest)*); + }; + ($outer_feature:literal @ALWAYS $($rest:tt)*) => { + impl_zip_for_tuple_accumulate!(@ALWAYS $($rest)*); + }; + (@ALWAYS $first:ident $($rest:tt)*) => { + impl_zip_for_tuple_accumulate!(@ALWAYS $($rest)*); + impl_zip_for_tuple!($first $($rest)*); + }; + (@ALWAYS) => { #[allow(unused_variables)] const _: () = { impl_zip_for_tuple!(); }; }; - ($first:ident $($rest:ident)*) => { - impl_zip_for_tuple_accumulate!($($rest)*); - impl_zip_for_tuple!($first $($rest)*); - } + (@MIXED $($idents_front:ident)* $($feature:literal $($idents_feature:ident)*)* @ALWAYS $($idents_always:ident)*) => { + impl_zip_for_tuple!($($idents_front)* $($($idents_feature)*)* $($idents_always)*); + }; } impl_zip_for_tuple_accumulate!( - P1 P2 P3 P4 P5 P6 P7 P8 P9 P10 P11 P12 P13 P14 P15 P16 - P17 P18 P19 P20 P21 P22 P23 P24 P25 P26 P27 P28 P29 P30 P31 P32 + "tuple-impl-32-zip" T1 T2 T3 T4 T5 T6 T7 T8 + "tuple-impl-24-zip" T9 T10 T11 T12 T13 T14 T15 T16 + "tuple-impl-16-zip" T17 T18 T19 T20 T21 T22 T23 T24 + "tuple-impl-8-zip" T25 T26 T27 T28 + @ALWAYS T29 T30 T31 T32 ); diff --git a/src/system/access/single.rs b/src/system/access/single.rs index b1b85c4120..15d1ed0e34 100644 --- a/src/system/access/single.rs +++ b/src/system/access/single.rs @@ -1,6 +1,11 @@ +//! Traits for accessing a single component storage. +//! +//! See [`AccessSingle`](Single) for documentation. + use std::marker::PhantomData; use std::{any, ops}; +use derive_trait::derive_trait; use rayon::prelude::ParallelIterator; use crate::entity::{self, ealloc, Raw as _}; @@ -9,18 +14,20 @@ use crate::{comp, util, Archetype, Storage}; /// Access a single component storage, i.e. a simple archetyped component /// or an isotope archetyped component for a single discriminant. -pub struct AccessSingle { +pub struct Single { storage: StorageRef, _ph: PhantomData<(A, C)>, } -impl AccessSingle { +impl Single { pub(crate) fn new(storage: StorageRef) -> Self { Self { storage, _ph: PhantomData } } } -impl AccessSingle +#[derive_trait(pub Get>)] +impl Single where A: Archetype, + C: comp::SimpleOrIsotope, StorageRef: ops::Deref + Sync, StorageRef::Target: Storage, { @@ -31,15 +38,16 @@ where } /// Iterates over all initialized components in this storage. - pub fn iter(&self) -> impl Iterator, &C)> { + pub fn iter<'t>(&'t self) -> impl Iterator, &'t C)> + 't { self.storage.iter().map(|(entity, comp)| (entity::TempRef::new(entity), comp)) } } -impl AccessSingle +#[derive_trait(pub MustGet + comp::Must>)] +impl Single where A: Archetype, - C: comp::Must, + C: comp::SimpleOrIsotope + comp::Must, StorageRef: ops::Deref + Sync, StorageRef::Target: Storage, { @@ -83,9 +91,11 @@ where } } -impl AccessSingle +#[derive_trait(pub GetChunked>)] +impl Single where A: Archetype, + C: comp::SimpleOrIsotope, StorageRef: ops::Deref + Sync, StorageRef::Target: storage::Chunked, { @@ -101,10 +111,11 @@ where } } -impl AccessSingle +#[derive_trait(pub MustGetChunked + comp::Must>)] +impl Single where A: Archetype, - C: comp::Must, + C: comp::SimpleOrIsotope + comp::Must, StorageRef: ops::Deref + Sync, StorageRef::Target: storage::Chunked, { @@ -128,9 +139,11 @@ where } } -impl AccessSingle +#[derive_trait(pub GetMut>)] +impl Single where A: Archetype, + C: comp::SimpleOrIsotope, StorageRef: ops::DerefMut + Sync, StorageRef::Target: storage::Access, { @@ -139,21 +152,24 @@ where /// /// Note that this function returns `Option<&mut C>`, not `&mut Option`. /// This means setting the Option itself to `Some`/`None` will not modify any stored value. - /// Use [`set`](AccessSingle::set) to add/remove a component. + /// Use [`set`](Single::set) to add/remove a component. pub fn try_get_mut(&mut self, entity: impl entity::Ref) -> Option<&mut C> { self.storage.get_mut(entity.id()) } /// Iterates over mutable references to all initialized components in this storage. - pub fn iter_mut(&mut self) -> impl Iterator, &mut C)> { + pub fn iter_mut<'t>( + &'t mut self, + ) -> impl Iterator, &'t mut C)> + 't { self.storage.iter_mut().map(|(entity, comp)| (entity::TempRef::new(entity), comp)) } } -impl AccessSingle +#[derive_trait(pub MustGetMut + comp::Must>)] +impl Single where A: Archetype, - C: comp::Must, + C: comp::SimpleOrIsotope + comp::Must, StorageRef: ops::DerefMut + Sync, StorageRef::Target: storage::Access, { @@ -177,9 +193,11 @@ where } } -impl AccessSingle +#[derive_trait(pub Set>)] +impl Single where A: Archetype, + C: comp::SimpleOrIsotope, StorageRef: ops::DerefMut + Sync, StorageRef::Target: Storage, { @@ -190,25 +208,31 @@ where pub fn set(&mut self, entity: impl entity::Ref, value: Option) -> Option { self.storage.set(entity.id(), value) } +} +impl Single +where + A: Archetype, + C: comp::SimpleOrIsotope, + StorageRef: ops::DerefMut + Sync, + StorageRef::Target: Storage, +{ /// Converts the accessor to a mutably borrowed partition that covers all entities. /// /// The actual splitting partitions can be obtained - /// by calling [`split_at`](AccessSingle::split_at) on the returned value. + /// by calling [`split_at`](Single::split_at) on the returned value. pub fn as_partition( &mut self, - ) -> AccessSingle::Partition<'_>>> { - AccessSingle { - storage: util::OwnedDeref(self.storage.as_partition()), - _ph: PhantomData, - } + ) -> Single::Partition<'_>>> { + Single { storage: util::OwnedDeref(self.storage.as_partition()), _ph: PhantomData } } } -impl AccessSingle +#[derive_trait(pub MustSet + comp::Must>)] +impl Single where A: Archetype, - C: comp::Must, + C: comp::SimpleOrIsotope + comp::Must, StorageRef: ops::DerefMut + Sync, StorageRef::Target: Storage, { @@ -229,9 +253,10 @@ where } } -impl<'t, A, C, StorageT> AccessSingle> +impl<'t, A, C, StorageT> Single> where A: Archetype, + C: comp::SimpleOrIsotope, StorageT: storage::Partition<'t, RawEntity = A::RawEntity, Comp = C>, { /// Splits the accessor into two partitions. @@ -260,10 +285,10 @@ where } } -impl<'t, A, C, StorageT> AccessSingle> +impl<'t, A, C, StorageT> Single> where A: Archetype, - C: comp::Must, + C: comp::SimpleOrIsotope + comp::Must, StorageT: storage::Partition<'t, RawEntity = A::RawEntity, Comp = C>, { /// Gets the component value of an entity accessible by this partition, @@ -292,10 +317,11 @@ where } } -impl AccessSingle +#[derive_trait(pub GetMutChunked + comp::Must>)] +impl Single where A: Archetype, - C: comp::Must, + C: comp::SimpleOrIsotope + comp::Must, StorageRef: ops::DerefMut + Sync, StorageRef::Target: storage::Chunked, for<'u> ::Partition<'u>: storage::PartitionChunked<'u>, @@ -328,10 +354,10 @@ where } } -impl<'t, A, C, StorageT> AccessSingle> +impl<'t, A, C, StorageT> Single> where A: Archetype, - C: comp::Must, + C: comp::SimpleOrIsotope + comp::Must, StorageT: storage::PartitionChunked<'t, RawEntity = A::RawEntity, Comp = C>, { /// Returns the chunk of components as a mutable slice,