summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHampusM <hampus@hampusmat.com>2024-12-10 21:48:10 +0100
committerHampusM <hampus@hampusmat.com>2024-12-13 17:16:34 +0100
commit9e057e9249fb5a8a9f3b2ba00a993049f733c9dd (patch)
tree7f8ca6d56438e83cd1d0da2562d18acbd13e5c80
parentc6de2c7ab9c48223ab307fe0039fae7ab2613e16 (diff)
refactor(ecs): improve system init param retrieval
-rw-r--r--ecs/src/system/stateful.rs46
-rw-r--r--ecs/src/tuple.rs115
2 files changed, 75 insertions, 86 deletions
diff --git a/ecs/src/system/stateful.rs b/ecs/src/system/stateful.rs
index 536e6ed..5eae1da 100644
--- a/ecs/src/system/stateful.rs
+++ b/ecs/src/system/stateful.rs
@@ -1,4 +1,4 @@
-use std::any::{type_name, Any, TypeId};
+use std::any::{Any, TypeId};
use std::collections::HashMap;
use std::panic::{RefUnwindSafe, UnwindSafe};
@@ -15,10 +15,9 @@ use crate::system::{
TypeErased,
};
use crate::tuple::{
- IntoInOptions as TupleIntoInOptions,
Reduce as TupleReduce,
- TakeOptionElementResult as TupleTakeOptionElementResult,
- WithOptionElements as TupleWithOptionElements,
+ Tuple,
+ WithAllElemLtStatic as TupleWithAllElemLtStatic,
};
use crate::uid::Uid;
use crate::World;
@@ -39,9 +38,10 @@ macro_rules! impl_system {
Func: Fn(#(TParam~I,)*) + Copy + RefUnwindSafe + UnwindSafe + 'static,
#(TParam~I: Param<'world>,)*
#(TParam~I::Input: 'static,)*
- (#(TParam~I::Input,)*): TupleReduce<ParamWithInputFilter>,
- <(#(TParam~I::Input,)*) as TupleReduce<ParamWithInputFilter>>::Out:
- TupleIntoInOptions
+ (#(TParam~I::Input,)*): TupleReduce<
+ ParamWithInputFilter,
+ Out: Tuple<InOptions: TupleWithAllElemLtStatic>
+ >,
{
type Input =
<(#(TParam~I::Input,)*) as TupleReduce<ParamWithInputFilter>>::Out;
@@ -50,35 +50,27 @@ macro_rules! impl_system {
{
let mut option_input = input.into_in_options();
+ let mut index = 0;
+
#(
if TypeId::of::<TParam~I::Input>() !=
TypeId::of::<()>()
{
- let input = match option_input.take::<TParam~I::Input>() {
- TupleTakeOptionElementResult::Found(input) => input,
- TupleTakeOptionElementResult::NotFound => {
- panic!(
- "Parameter input {} not found",
- type_name::<TParam~I::Input>()
- );
- }
- TupleTakeOptionElementResult::AlreadyTaken => {
- panic!(
- concat!(
- "Parameter {} is already initialized. ",
- "System cannot contain multiple inputs with ",
- "the same type",
- ),
- type_name::<TParam~I>()
- );
-
- }
- };
+ 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;
+ }
}
)*
diff --git a/ecs/src/tuple.rs b/ecs/src/tuple.rs
index b16160c..def25a0 100644
--- a/ecs/src/tuple.rs
+++ b/ecs/src/tuple.rs
@@ -1,5 +1,4 @@
use std::any::TypeId;
-use std::mem::{transmute_copy, ManuallyDrop};
use paste::paste;
use seq_macro::seq;
@@ -24,23 +23,22 @@ pub trait Tuple: sealed::Sealed
/// 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);
-}
-
-/// Used to make all elements of a tuple type wrapped in [`Option`].
-pub trait IntoInOptions
-{
- type InOptions: WithOptionElements;
+ /// Converts this tuple so that all elements are wrapped in [`Option`].
fn into_in_options(self) -> Self::InOptions;
}
-/// A tuple with all elements wrapped in [`Option`].
-pub trait WithOptionElements
+/// A tuple with element types that all have the lifetime `'static`.
+pub trait WithAllElemLtStatic: Tuple + sealed::Sealed
{
- fn take<Element: 'static>(&mut self) -> TakeOptionElementResult<Element>;
+ /// 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
@@ -55,22 +53,6 @@ pub trait ReduceElement<Accumulator, Operation>
type Return;
}
-/// The result of trying to [`take`] a element from a implementation of
-/// [`WithOptionElements`].
-///
-/// [`take`]: WithOptionElements::take
-pub enum TakeOptionElementResult<Element>
-{
- /// The element was succesfully taken.
- Found(Element),
-
- /// The element is not a element of the tuple.
- NotFound,
-
- /// The element has already been taken
- AlreadyTaken,
-}
-
macro_rules! tuple_reduce_elem_tuple {
(overflow) => {
()
@@ -134,7 +116,7 @@ macro_rules! all_except_last {
macro_rules! impl_tuple_traits {
($cnt: tt) => {
seq!(I in 0..$cnt {
- impl< #(Elem~I,)*> Tuple for (#(Elem~I,)*)
+ impl<#(Elem~I,)*> Tuple for (#(Elem~I,)*)
{
type WithElementAtEnd<NewElem> = (#(Elem~I,)* NewElem,);
@@ -142,6 +124,8 @@ macro_rules! impl_tuple_traits {
type LastElement = sub!($cnt - 1, elem_type_by_index);
+ type InOptions = (#(Option<Elem~I>,)*);
+
fn pop_last(self) -> (Self::WithoutLastElement, Self::LastElement)
{
(
@@ -149,15 +133,6 @@ macro_rules! impl_tuple_traits {
sub!($cnt - 1, elem_by_index, (self))
)
}
- }
-
- impl< #(Elem~I,)*> sealed::Sealed for (#(Elem~I,)*)
- {
- }
-
- impl<#(Element~I: 'static,)*> IntoInOptions for (#(Element~I,)*)
- {
- type InOptions = (#(Option<Element~I>,)*);
fn into_in_options(self) -> Self::InOptions
{
@@ -166,32 +141,28 @@ macro_rules! impl_tuple_traits {
}
}
- impl<#(Element~I: 'static,)*> WithOptionElements for (#(Option<Element~I>,)*)
+ impl<#(Elem~I: 'static,)*> WithAllElemLtStatic for (#(Elem~I,)*)
{
- fn take<Element: 'static>(&mut self)
- -> TakeOptionElementResult<Element>
+ fn get_mut<Element: 'static>(&mut self, index: usize) -> Option<&mut Element>
{
- #(
- if TypeId::of::<Element~I>() == TypeId::of::<Element>() {
- let input = match self.I.take() {
- Some(input) => ManuallyDrop::new(input),
- None => {
- return TakeOptionElementResult::AlreadyTaken;
- }
- };
-
- return TakeOptionElementResult::Found(
- // SAFETY: It can be transmuted safely since it is the
- // same type and the type is 'static
- unsafe { transmute_copy(&input) }
- );
- }
- )*
-
- TakeOptionElementResult::NotFound
+ 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
@@ -213,7 +184,7 @@ seq!(N in 0..16 {
});
seq!(I in 0..16 {
- impl< #(Elem~I,)*> Tuple for (#(Elem~I,)*)
+ impl<#(Elem~I,)*> Tuple for (#(Elem~I,)*)
{
type WithElementAtEnd<NewElem> = ();
@@ -221,6 +192,8 @@ seq!(I in 0..16 {
type LastElement = Elem15;
+ type InOptions = (#(Option<Elem~I>,)*);
+
fn pop_last(self) -> (Self::WithoutLastElement, Self::LastElement)
{
(
@@ -228,9 +201,33 @@ seq!(I in 0..16 {
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,)*)
+ impl<#(Elem~I,)*> sealed::Sealed for (#(Elem~I,)*)
{
}
});