Skip to content

Commit

Permalink
feat(accessor): derive traits for AccessSingle
Browse files Browse the repository at this point in the history
  • Loading branch information
SOF3 committed Oct 7, 2023
1 parent 1d40f3d commit 9e72f30
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 49 deletions.
9 changes: 9 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
38 changes: 29 additions & 9 deletions src/comp/any.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ pub(crate) trait DepGetterInner<A: Archetype> {
}

macro_rules! impl_simple_init_fn {
($($deps:ident),* $(,)?) => {
($($deps:ident)*) => {
impl<
A: Archetype, C: comp::SimpleOrIsotope<A>,
$($deps: comp::Simple<A>,)*
Expand Down Expand Up @@ -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)]
Expand Down
4 changes: 2 additions & 2 deletions src/system/access.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
2 changes: 1 addition & 1 deletion src/system/access/isotope.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
5 changes: 5 additions & 0 deletions src/system/access/iter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ pub trait ZipChunked<A: Archetype>: Zip<A> {
/// - 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<A: Archetype> {
/// The [`Zip`] type that this is converted into.
type IntoZip: Zip<A>;
Expand Down
31 changes: 24 additions & 7 deletions src/system/access/iter/tuple_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
);
86 changes: 56 additions & 30 deletions src/system/access/single.rs
Original file line number Diff line number Diff line change
@@ -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 _};
Expand All @@ -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<A, C, StorageRef> {
pub struct Single<A, C, StorageRef> {
storage: StorageRef,
_ph: PhantomData<(A, C)>,
}

impl<A, C, StorageRef> AccessSingle<A, C, StorageRef> {
impl<A, C, StorageRef> Single<A, C, StorageRef> {
pub(crate) fn new(storage: StorageRef) -> Self { Self { storage, _ph: PhantomData } }
}

impl<A, C, StorageRef> AccessSingle<A, C, StorageRef>
#[derive_trait(pub Get<A: Archetype, C: comp::SimpleOrIsotope<A>>)]
impl<A, C, StorageRef> Single<A, C, StorageRef>
where
A: Archetype,
C: comp::SimpleOrIsotope<A>,
StorageRef: ops::Deref + Sync,
StorageRef::Target: Storage<RawEntity = A::RawEntity, Comp = C>,
{
Expand All @@ -31,15 +38,16 @@ where
}

/// Iterates over all initialized components in this storage.
pub fn iter(&self) -> impl Iterator<Item = (entity::TempRef<A>, &C)> {
pub fn iter<'t>(&'t self) -> impl Iterator<Item = (entity::TempRef<'t, A>, &'t C)> + 't {
self.storage.iter().map(|(entity, comp)| (entity::TempRef::new(entity), comp))
}
}

impl<A, C, StorageRef> AccessSingle<A, C, StorageRef>
#[derive_trait(pub MustGet<A: Archetype, C: comp::SimpleOrIsotope<A> + comp::Must<A>>)]
impl<A, C, StorageRef> Single<A, C, StorageRef>
where
A: Archetype,
C: comp::Must<A>,
C: comp::SimpleOrIsotope<A> + comp::Must<A>,
StorageRef: ops::Deref + Sync,
StorageRef::Target: Storage<RawEntity = A::RawEntity, Comp = C>,
{
Expand Down Expand Up @@ -83,9 +91,11 @@ where
}
}

impl<A, C, StorageRef> AccessSingle<A, C, StorageRef>
#[derive_trait(pub GetChunked<A: Archetype, C: comp::SimpleOrIsotope<A>>)]
impl<A, C, StorageRef> Single<A, C, StorageRef>
where
A: Archetype,
C: comp::SimpleOrIsotope<A>,
StorageRef: ops::Deref + Sync,
StorageRef::Target: storage::Chunked<RawEntity = A::RawEntity, Comp = C>,
{
Expand All @@ -101,10 +111,11 @@ where
}
}

impl<A, C, StorageRef> AccessSingle<A, C, StorageRef>
#[derive_trait(pub MustGetChunked<A: Archetype, C: comp::SimpleOrIsotope<A> + comp::Must<A>>)]
impl<A, C, StorageRef> Single<A, C, StorageRef>
where
A: Archetype,
C: comp::Must<A>,
C: comp::SimpleOrIsotope<A> + comp::Must<A>,
StorageRef: ops::Deref + Sync,
StorageRef::Target: storage::Chunked<RawEntity = A::RawEntity, Comp = C>,
{
Expand All @@ -128,9 +139,11 @@ where
}
}

impl<A, C, StorageRef> AccessSingle<A, C, StorageRef>
#[derive_trait(pub GetMut<A: Archetype, C: comp::SimpleOrIsotope<A>>)]
impl<A, C, StorageRef> Single<A, C, StorageRef>
where
A: Archetype,
C: comp::SimpleOrIsotope<A>,
StorageRef: ops::DerefMut + Sync,
StorageRef::Target: storage::Access<RawEntity = A::RawEntity, Comp = C>,
{
Expand All @@ -139,21 +152,24 @@ where
///
/// Note that this function returns `Option<&mut C>`, not `&mut Option<C>`.
/// 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<Archetype = A>) -> 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<Item = (entity::TempRef<A>, &mut C)> {
pub fn iter_mut<'t>(
&'t mut self,
) -> impl Iterator<Item = (entity::TempRef<'t, A>, &'t mut C)> + 't {
self.storage.iter_mut().map(|(entity, comp)| (entity::TempRef::new(entity), comp))
}
}

impl<A, C, StorageRef> AccessSingle<A, C, StorageRef>
#[derive_trait(pub MustGetMut<A: Archetype, C: comp::SimpleOrIsotope<A> + comp::Must<A>>)]
impl<A, C, StorageRef> Single<A, C, StorageRef>
where
A: Archetype,
C: comp::Must<A>,
C: comp::SimpleOrIsotope<A> + comp::Must<A>,
StorageRef: ops::DerefMut + Sync,
StorageRef::Target: storage::Access<RawEntity = A::RawEntity, Comp = C>,
{
Expand All @@ -177,9 +193,11 @@ where
}
}

impl<A, C, StorageRef> AccessSingle<A, C, StorageRef>
#[derive_trait(pub Set<A: Archetype, C: comp::SimpleOrIsotope<A>>)]
impl<A, C, StorageRef> Single<A, C, StorageRef>
where
A: Archetype,
C: comp::SimpleOrIsotope<A>,
StorageRef: ops::DerefMut + Sync,
StorageRef::Target: Storage<RawEntity = A::RawEntity, Comp = C>,
{
Expand All @@ -190,25 +208,31 @@ where
pub fn set(&mut self, entity: impl entity::Ref<Archetype = A>, value: Option<C>) -> Option<C> {
self.storage.set(entity.id(), value)
}
}

impl<A, C, StorageRef> Single<A, C, StorageRef>
where
A: Archetype,
C: comp::SimpleOrIsotope<A>,
StorageRef: ops::DerefMut + Sync,
StorageRef::Target: Storage<RawEntity = A::RawEntity, Comp = C>,
{
/// 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<A, C, util::OwnedDeref<<StorageRef::Target as Storage>::Partition<'_>>> {
AccessSingle {
storage: util::OwnedDeref(self.storage.as_partition()),
_ph: PhantomData,
}
) -> Single<A, C, util::OwnedDeref<<StorageRef::Target as Storage>::Partition<'_>>> {
Single { storage: util::OwnedDeref(self.storage.as_partition()), _ph: PhantomData }
}
}

impl<A, C, StorageRef> AccessSingle<A, C, StorageRef>
#[derive_trait(pub MustSet<A: Archetype, C: comp::SimpleOrIsotope<A> + comp::Must<A>>)]
impl<A, C, StorageRef> Single<A, C, StorageRef>
where
A: Archetype,
C: comp::Must<A>,
C: comp::SimpleOrIsotope<A> + comp::Must<A>,
StorageRef: ops::DerefMut + Sync,
StorageRef::Target: Storage<RawEntity = A::RawEntity, Comp = C>,
{
Expand All @@ -229,9 +253,10 @@ where
}
}

impl<'t, A, C, StorageT> AccessSingle<A, C, util::OwnedDeref<StorageT>>
impl<'t, A, C, StorageT> Single<A, C, util::OwnedDeref<StorageT>>
where
A: Archetype,
C: comp::SimpleOrIsotope<A>,
StorageT: storage::Partition<'t, RawEntity = A::RawEntity, Comp = C>,
{
/// Splits the accessor into two partitions.
Expand Down Expand Up @@ -260,10 +285,10 @@ where
}
}

impl<'t, A, C, StorageT> AccessSingle<A, C, util::OwnedDeref<StorageT>>
impl<'t, A, C, StorageT> Single<A, C, util::OwnedDeref<StorageT>>
where
A: Archetype,
C: comp::Must<A>,
C: comp::SimpleOrIsotope<A> + comp::Must<A>,
StorageT: storage::Partition<'t, RawEntity = A::RawEntity, Comp = C>,
{
/// Gets the component value of an entity accessible by this partition,
Expand Down Expand Up @@ -292,10 +317,11 @@ where
}
}

impl<A, C, StorageRef> AccessSingle<A, C, StorageRef>
#[derive_trait(pub GetMutChunked<A: Archetype, C: comp::SimpleOrIsotope<A> + comp::Must<A>>)]
impl<A, C, StorageRef> Single<A, C, StorageRef>
where
A: Archetype,
C: comp::Must<A>,
C: comp::SimpleOrIsotope<A> + comp::Must<A>,
StorageRef: ops::DerefMut + Sync,
StorageRef::Target: storage::Chunked<RawEntity = A::RawEntity, Comp = C>,
for<'u> <StorageRef::Target as Storage>::Partition<'u>: storage::PartitionChunked<'u>,
Expand Down Expand Up @@ -328,10 +354,10 @@ where
}
}

impl<'t, A, C, StorageT> AccessSingle<A, C, util::OwnedDeref<StorageT>>
impl<'t, A, C, StorageT> Single<A, C, util::OwnedDeref<StorageT>>
where
A: Archetype,
C: comp::Must<A>,
C: comp::SimpleOrIsotope<A> + comp::Must<A>,
StorageT: storage::PartitionChunked<'t, RawEntity = A::RawEntity, Comp = C>,
{
/// Returns the chunk of components as a mutable slice,
Expand Down

0 comments on commit 9e72f30

Please sign in to comment.