Making an ecs, I've been trying to create entities from a few components, using any number of these for user simplicity :
pub fn create_entity_with_1<C: Component<C> 'static>(&mut self, component: C) -> Entity {
// C is a component
let result: Entity = Entity {
id: self.last_entity_id,
};
self.last_entity_id = 1;
// add the component, as we just created the entity we can fast push in the packed array
self.components.add_comp_to_last(&result, component);
return result;
}
pub fn create_entity_with_2<C1: Component<C1> 'static,
C2: Component<C2> 'static>
(&mut self, component_1: C1,
component_2: C2) -> Entity {
// C is a component
let result: Entity = Entity {
id: self.last_entity_id,
};
self.last_entity_id = 1;
// add the component, as we just created the entity we can fast push in the packed array
self.components.add_comp_to_last(&result, component_1);
self.components.add_comp_to_last(&result, component_2);
return result;
}
Clearly, if I extend this to more components, the pattern of this function will always be the same, and I don't want to have 15 of these.
Is there a way to write a generic taking arbitrary number of generic components ?
Alternatively, I've seen The legion ecs does this taking a tuple of components, but I can't figure out how to unpack tuples of any sizes.
CodePudding user response:
You can do that with a macro:
macro_rules! create_entity_fns {
(
$first_fn_name:ident $first_generic:ident
$( $fn_name:ident $generic:ident )*
) => {
#[allow(non_snake_case)]
pub fn $first_fn_name<
$first_generic: Component<$first_generic> 'static,
$( $generic: Component<$generic> 'static, )*
>(
&mut self,
$first_generic: $first_generic,
$( $generic: $generic, )*
) -> Entity {
let result = Entity { id: self.last_entity_id };
self.last_entity_id = 1;
self.components.add_to_last(&result, $first_generic);
$( self.components.add_to_last(&result, $generic); )*
result
}
create_entity_fns!( $( $fn_name $generic )* );
};
() => {};
}
impl Foo {
create_entity_fns!(
// Notice the swapped order!
// ...
create_entity_with_4 C4
create_entity_with_3 C3
create_entity_with_2 C2
create_entity_with_1 C1
);
}
For each invocation we create a function and recurse to the next invocation with one less parameters.