diff --git a/flecs_ecs/examples/entity_basics.rs b/flecs_ecs/examples/entity_basics.rs index 5c388499..24590ffc 100644 --- a/flecs_ecs/examples/entity_basics.rs +++ b/flecs_ecs/examples/entity_basics.rs @@ -37,13 +37,13 @@ fn main() { alice.remove::(); // Iterate all entities with position - world.each_entity::<(&Position,)>(|entity, pos| { + world.each_entity::<&Position>(|entity, pos| { println!("{} has {:?}", entity.name(), pos); }); // Output // Bob's position: Position { x: 10.0, y: 20.0 } // [Position, Walking, (Identifier,Name)] - // Alice has (Position { x: 10.0, y: 20.0 },) - // Bob has (Position { x: 20.0, y: 30.0 },) + // Alice has Position { x: 10.0, y: 20.0 } + // Bob has Position { x: 20.0, y: 30.0 } } diff --git a/flecs_ecs/examples/observer_basics.rs b/flecs_ecs/examples/observer_basics.rs index 8924b068..a46d3b90 100644 --- a/flecs_ecs/examples/observer_basics.rs +++ b/flecs_ecs/examples/observer_basics.rs @@ -6,11 +6,11 @@ fn main() { // Create an observer for three events world - .observer_builder::<(&Position,)>() + .observer_builder::<&Position>() .add_event::() //or .add_event_id(OnAdd::ID) .add_event::() .add_event::() - .on_each_iter(|it, index, (pos,)| { + .on_each_iter(|it, index, pos| { if it.event() == flecs::OnAdd::ID { // No assumptions about the component value should be made here. If // a ctor for the component was registered it will be called before diff --git a/flecs_ecs/examples/observer_custom_event.rs b/flecs_ecs/examples/observer_custom_event.rs index fe2d841f..7ba80378 100644 --- a/flecs_ecs/examples/observer_custom_event.rs +++ b/flecs_ecs/examples/observer_custom_event.rs @@ -10,9 +10,9 @@ fn main() { // Create an observer for three events world - .observer_builder::<(&Position,)>() + .observer_builder::<&Position>() .add_event::() - .on_each_iter(|it, index, (_pos,)| { + .on_each_iter(|it, index, _pos| { println!( " - {}: {}: {}", it.event().name(), diff --git a/flecs_ecs/examples/observer_yield_existing.rs b/flecs_ecs/examples/observer_yield_existing.rs index 449a23e6..76753795 100644 --- a/flecs_ecs/examples/observer_yield_existing.rs +++ b/flecs_ecs/examples/observer_yield_existing.rs @@ -21,10 +21,10 @@ fn main() { // Create an observer for three events world - .observer_builder::<(&Position,)>() + .observer_builder::<&Position>() .add_event::() .yield_existing(true) - .on_each_iter(|it, index, (pos,)| { + .on_each_iter(|it, index, pos| { println!( " - {}: {}: {}: {{ {}, {} }}", it.event().name(), diff --git a/flecs_ecs/examples/prefab_basics.rs b/flecs_ecs/examples/prefab_basics.rs index a143c47c..e57179a6 100644 --- a/flecs_ecs/examples/prefab_basics.rs +++ b/flecs_ecs/examples/prefab_basics.rs @@ -45,7 +45,7 @@ fn main() { println!("after set: {:?}", d_inst); // Prefab components can be iterated like regular components: - world.each_entity::<(&Defence,)>(|entity, (d,)| { + world.each_entity::<&Defence>(|entity, d| { println!("{}: {}", entity.path().unwrap(), d.value); }); diff --git a/flecs_ecs/examples/query_change_tracking.rs b/flecs_ecs/examples/query_change_tracking.rs index f7164a27..0e28054c 100644 --- a/flecs_ecs/examples/query_change_tracking.rs +++ b/flecs_ecs/examples/query_change_tracking.rs @@ -23,7 +23,7 @@ pub fn main() { // Each query has its own private dirty state which is reset only when the // query is iterated. - let query_read = world.query::<(&Position,)>(); + let query_read = world.query::<&Position>(); // Create a query that writes the component based on a Dirty state. let query_write = world diff --git a/flecs_ecs/examples/query_find_entity.rs b/flecs_ecs/examples/query_find_entity.rs index 21a41782..9f862d11 100644 --- a/flecs_ecs/examples/query_find_entity.rs +++ b/flecs_ecs/examples/query_find_entity.rs @@ -15,9 +15,9 @@ fn main() { .set(Position { x: 20.0, y: 30.0 }); // Create a simple query for component Position - let query = world.query::<(&Position,)>(); + let query = world.query::<&Position>(); - let entity: Option = query.find(|(pos,)| (pos.x - 20.0).abs() < f32::EPSILON); + let entity: Option = query.find(|pos| (pos.x - 20.0).abs() < f32::EPSILON); if let Some(entity) = entity { println!("Entity found: {:?}", entity.path().unwrap()); diff --git a/flecs_ecs/examples/query_group_by.rs b/flecs_ecs/examples/query_group_by.rs index 16637d4e..8191f6d8 100644 --- a/flecs_ecs/examples/query_group_by.rs +++ b/flecs_ecs/examples/query_group_by.rs @@ -9,7 +9,7 @@ fn main() { world.component::(); let query = world - .query_builder::<(&Position,)>() + .query_builder::<&Position>() .group_by::() .build(); @@ -44,7 +44,7 @@ fn main() { println!(); - query.iter(|it, (pos,)| { + query.iter(|it, pos| { let group = world.new_entity_from_id(it.group_id()); println!( "Group: {:?} - Table: [{:?}]", diff --git a/flecs_ecs/examples/query_group_by_custom.rs b/flecs_ecs/examples/query_group_by_custom.rs index e7e551bb..4aae7a14 100644 --- a/flecs_ecs/examples/query_group_by_custom.rs +++ b/flecs_ecs/examples/query_group_by_custom.rs @@ -32,7 +32,7 @@ fn main() { // Grouped query let query = world - .query_builder::<(&Position,)>() + .query_builder::<&Position>() .group_by_fn::(Some(callback_group_by_relationship)) .build(); @@ -82,7 +82,7 @@ fn main() { // - table [Position, Tag, (Group, Third)] // - query.iter(|it, (pos,)| { + query.iter(|it, pos| { let group = world.new_entity_from_id(it.group_id()); println!( "Group: {:?} - Table: [{:?}]", diff --git a/flecs_ecs/examples/query_group_iter.rs b/flecs_ecs/examples/query_group_iter.rs index 5dc2c099..f6355f09 100644 --- a/flecs_ecs/examples/query_group_iter.rs +++ b/flecs_ecs/examples/query_group_iter.rs @@ -97,7 +97,7 @@ fn main() { .add::(); let query = world - .query_builder::<(&Npc,)>() + .query_builder::<&Npc>() .group_by::() .build(); diff --git a/flecs_ecs/examples/query_hierarchy.rs b/flecs_ecs/examples/query_hierarchy.rs index db35f74a..4fd34a17 100644 --- a/flecs_ecs/examples/query_hierarchy.rs +++ b/flecs_ecs/examples/query_hierarchy.rs @@ -76,11 +76,11 @@ fn main() { //TODO: pair wrapper class to clean up, beautify this API world - .filter_builder::<(&Position,)>() + .filter_builder::<&Position>() .term_at(1) .select_second::() .build() - .each_entity(|entity, (position,)| { + .each_entity(|entity, position| { println!( "Entity {} is at ({}, {})", entity.name(), diff --git a/flecs_ecs/examples/query_sorting.rs b/flecs_ecs/examples/query_sorting.rs index 2cf14a3b..763bb68a 100644 --- a/flecs_ecs/examples/query_sorting.rs +++ b/flecs_ecs/examples/query_sorting.rs @@ -13,8 +13,8 @@ extern "C" fn compare_position( (p1.x > p2.x) as i32 - (p1.x < p2.x) as i32 } -fn print_query(query: &Query<'_, (&Position,)>) { - query.each(|(pos,)| println!("{:?}", pos)); +fn print_query(query: &Query<'_, &Position>) { + query.each(|pos| println!("{:?}", pos)); } fn main() { @@ -29,15 +29,15 @@ fn main() { // Create a sorted system let sys = world - .system_builder::<(&Position,)>() + .system_builder::<&Position>() .order_by(compare_position) - .on_each(|(pos,)| { + .on_each(|pos| { println!("{:?}", pos); }); // Create a sorted query let query = world - .query_builder::<(&Position,)>() + .query_builder::<&Position>() .order_by(compare_position) .build(); diff --git a/flecs_ecs/examples/query_wildcard.rs b/flecs_ecs/examples/query_wildcard.rs index 842a77b3..fe5bde0a 100644 --- a/flecs_ecs/examples/query_wildcard.rs +++ b/flecs_ecs/examples/query_wildcard.rs @@ -13,7 +13,7 @@ fn main() { // Create a query that matches edible components let query = world - .query_builder::<(&Eats,)>() + .query_builder::<&Eats>() .term_at(1) // Change first argument to (Eats, *) // alternative you can do `.select_second_id(flecs::Wildcard::ID)`` @@ -32,7 +32,7 @@ fn main() { // Iterate the query with a flecs::iter. This makes it possible to inspect // the pair that we are currently matched with. - query.each_iter(|it, index, (eats,)| { + query.each_iter(|it, index, eats| { let entity = it.entity(index); let food = it.pair(1).unwrap().second(); diff --git a/flecs_ecs/examples/query_with.rs b/flecs_ecs/examples/query_with.rs index 0cdeed94..91db21e5 100644 --- a/flecs_ecs/examples/query_with.rs +++ b/flecs_ecs/examples/query_with.rs @@ -13,7 +13,7 @@ fn main() { // This is useful for things like tags, which because they don't have a // value are less useful to pass to the each/iter functions as argument. let query = world - .query_builder::<(&Position,)>() + .query_builder::<&Position>() .with_type::<&Npc>() .build(); @@ -34,7 +34,7 @@ fn main() { .set(Position { x: 10.0, y: 20.0 }); // Note how the Npc tag is not part of the each signature - query.each_entity(|entity, (pos,)| { + query.each_entity(|entity, pos| { println!("Entity {}: {:?}", entity.name(), pos); }); diff --git a/flecs_ecs/examples/query_without.rs b/flecs_ecs/examples/query_without.rs index b3cd0b80..4e2402a3 100644 --- a/flecs_ecs/examples/query_without.rs +++ b/flecs_ecs/examples/query_without.rs @@ -16,7 +16,7 @@ fn main() { // The without method is short for: // .term().not_() let query = world - .query_builder::<(&Position,)>() + .query_builder::<&Position>() .without_type::<&Npc>() .build(); @@ -36,7 +36,7 @@ fn main() { .add::(); // Note how the Npc tag is not part of the each signature - query.each_entity(|entity, (pos,)| { + query.each_entity(|entity, pos| { println!("Entity {}: {:?}", entity.name(), pos); }); diff --git a/flecs_ecs/examples/relationships_component_data.rs b/flecs_ecs/examples/relationships_component_data.rs index ca7a2751..46f95c3f 100644 --- a/flecs_ecs/examples/relationships_component_data.rs +++ b/flecs_ecs/examples/relationships_component_data.rs @@ -110,12 +110,12 @@ fn main() { // When querying for a relationship component, add the pair type as template // argument to the builder: let query = world - .query_builder::<(&Requires,)>() + .query_builder::<&Requires>() .term_at(1) .select_second::() .build(); - query.each(|(requires,)| { + query.each(|requires| { println!("requires: {} gigawatts", requires.amount); }); diff --git a/flecs_ecs/examples/rules_component_inheritance.rs b/flecs_ecs/examples/rules_component_inheritance.rs index 11cbc3c5..b0559f98 100644 --- a/flecs_ecs/examples/rules_component_inheritance.rs +++ b/flecs_ecs/examples/rules_component_inheritance.rs @@ -55,10 +55,10 @@ fn main() { world.new_entity_named(c"builder_2").add::(); // Create a rule to find all ranged units - let r = world.rule::<(&RangedUnit,)>(); + let r = world.rule::<&RangedUnit>(); // Iterate the rule - r.each_entity(|e, (_,)| { + r.each_entity(|e, _| { println!("Unit {} found", e.name()); }); diff --git a/flecs_ecs/examples/rules_setting_variables.rs b/flecs_ecs/examples/rules_setting_variables.rs index fb6c3fb7..4b137dcc 100644 --- a/flecs_ecs/examples/rules_setting_variables.rs +++ b/flecs_ecs/examples/rules_setting_variables.rs @@ -95,7 +95,7 @@ fn main() { // - find all entities with (Platoon, *), store * in _Platoon // - check if _Platoon has (Player, *), store * in _Player let rule = world - .rule_builder::<(&RangedUnit,)>() + .rule_builder::<&RangedUnit>() .with_type::<&Platoon>() .select_second_name(c"$Platoon") .with_pair_name::<&Player>(c"$Player") @@ -113,7 +113,7 @@ fn main() { // Iterate rule, limit the results to units of MyPlayer rule.iterable() .set_var(player_var, world.lookup_name(c"MyPlayer", true)) - .each_iter(|it, index, (_,)| { + .each_iter(|it, index, _| { let unit = it.entity(index); println!( "Unit {} of class {} in platoon {} for player {}", diff --git a/flecs_ecs/examples/system_mutate_entity.rs b/flecs_ecs/examples/system_mutate_entity.rs index 15dc6989..8c570df4 100644 --- a/flecs_ecs/examples/system_mutate_entity.rs +++ b/flecs_ecs/examples/system_mutate_entity.rs @@ -11,8 +11,8 @@ fn main() { // System that deletes an entity after a timeout expires world - .system_builder::<(&mut Timeout,)>() - .on_each_iter(|it, index, (timeout,)| { + .system_builder::<&mut Timeout>() + .on_each_iter(|it, index, timeout| { timeout.value -= it.delta_time(); if timeout.value <= 0.0 { // Delete the entity @@ -33,8 +33,8 @@ fn main() { // System that prints remaining expiry time world - .system_builder::<(&Timeout,)>() - .on_each_entity(|e, (timeout,)| { + .system_builder::<&Timeout>() + .on_each_entity(|e, timeout| { println!( "PrintExpire: {} has {:.2} seconds left", e.name(), @@ -44,9 +44,9 @@ fn main() { // Observer that triggers when entity is actually deleted world - .observer_builder::<(&Timeout,)>() + .observer_builder::<&Timeout>() .add_event::() - .on_each_entity(|e, (_timeout,)| { + .on_each_entity(|e, _timeout| { println!("Expired: {} actually deleted", e.name()); }); diff --git a/flecs_ecs/examples/system_mutate_entity_handle.rs b/flecs_ecs/examples/system_mutate_entity_handle.rs index 17a2ee01..79598f80 100644 --- a/flecs_ecs/examples/system_mutate_entity_handle.rs +++ b/flecs_ecs/examples/system_mutate_entity_handle.rs @@ -18,8 +18,8 @@ fn main() { // System that deletes an entity after a timeout expires world - .system_builder::<(&mut Timeout,)>() - .on_each_iter(|it, _index, (timeout,)| { + .system_builder::<&mut Timeout>() + .on_each_iter(|it, _index, timeout| { timeout.value -= it.delta_time(); if timeout.value <= 0.0 { // Delete the entity @@ -50,7 +50,7 @@ fn main() { }); // System that prints remaining expiry time - world.system_builder::<(&Timeout,)>().on_each(|(timeout,)| { + world.system_builder::<&Timeout>().on_each(|timeout| { println!( "PrintExpire: {} has {:.2} seconds left", timeout.to_delete.name(), @@ -60,9 +60,9 @@ fn main() { // Observer that triggers when entity is actually deleted world - .observer_builder::<(&Tag,)>() + .observer_builder::<&Tag>() .add_event::() - .on_each_entity(|e, (_tag,)| { + .on_each_entity(|e, _tag| { println!("Expired: {} actually deleted", e.name()); }); diff --git a/flecs_ecs/examples/system_no_readonly.rs b/flecs_ecs/examples/system_no_readonly.rs index 5cc875dc..0dddb710 100644 --- a/flecs_ecs/examples/system_no_readonly.rs +++ b/flecs_ecs/examples/system_no_readonly.rs @@ -25,7 +25,7 @@ fn main() { // Create query to find all waiters without a plate let q_waiter = world - .query_builder::<(&Waiter,)>() + .query_builder::<&Waiter>() .without_pair::<&Plate, flecs::Wildcard>() .build(); @@ -33,7 +33,7 @@ fn main() { // plate assignments are assigned directly (not deferred) to waiters, which // ensures that we won't assign plates to the same waiter more than once. world - .system_builder_named::<(&Plate,)>(c"AssignPlate") + .system_builder_named::<&Plate>(c"AssignPlate") .without_pair::<&Waiter, flecs::Wildcard>() .no_readonly(true) .on_iter_only(move |it| { diff --git a/flecs_ecs/examples/system_pipeline.rs b/flecs_ecs/examples/system_pipeline.rs index e5d8295a..30cd660f 100644 --- a/flecs_ecs/examples/system_pipeline.rs +++ b/flecs_ecs/examples/system_pipeline.rs @@ -15,9 +15,9 @@ fn main() { // Create a system for printing the entity position world - .system_builder::<(&Position,)>() + .system_builder::<&Position>() .kind::() - .on_each_entity(|e, (p,)| { + .on_each_entity(|e, p| { println!("{}: {{ {}, {} }}", e.name(), p.x, p.y); }); diff --git a/flecs_ecs/examples/system_sync_point.rs b/flecs_ecs/examples/system_sync_point.rs index b215a3c9..311f54d6 100644 --- a/flecs_ecs/examples/system_sync_point.rs +++ b/flecs_ecs/examples/system_sync_point.rs @@ -37,8 +37,8 @@ fn main() { // Print resulting Position world - .system_builder_named::<(&Position,)>(c"PrintPosition") - .on_each_entity(|e, (p,)| { + .system_builder_named::<&Position>(c"PrintPosition") + .on_each_entity(|e, p| { println!("{}: {{ {}, {} }}", e.name(), p.x, p.y); }); diff --git a/flecs_ecs/examples/system_sync_point_delete.rs b/flecs_ecs/examples/system_sync_point_delete.rs index 38075c04..22e223a6 100644 --- a/flecs_ecs/examples/system_sync_point_delete.rs +++ b/flecs_ecs/examples/system_sync_point_delete.rs @@ -29,9 +29,9 @@ fn main() { // component could be written by the system. Position itself is added as // const, since inside the system we're only reading it. world - .system_builder_named::<(&Position,)>(c"DeleteEntity") + .system_builder_named::<&Position>(c"DeleteEntity") .write_type::<&flecs::Wildcard>() - .on_each_entity(|e, (p,)| { + .on_each_entity(|e, p| { if p.x >= 3.0 { println!("Delete entity {}", e.name()); e.destruct(); @@ -41,8 +41,8 @@ fn main() { // Print resulting Position. Note that this system will never print entities // that have been deleted by the previous system. world - .system_builder_named::<(&Position,)>(c"PrintPosition") - .on_each_entity(|e, (p,)| { + .system_builder_named::<&Position>(c"PrintPosition") + .on_each_entity(|e, p| { println!("{}: {{ {}, {} }}", e.name(), p.x, p.y); }); diff --git a/flecs_ecs/src/core/iterable.rs b/flecs_ecs/src/core/iterable.rs index ffa1e34f..6cb8a865 100644 --- a/flecs_ecs/src/core/iterable.rs +++ b/flecs_ecs/src/core/iterable.rs @@ -1,3 +1,7 @@ +use std::marker::PhantomData; + +use flecs_ecs_derive::tuples; + use crate::sys::{self, ecs_filter_desc_t, ecs_inout_kind_t, ecs_oper_kind_t}; use super::{ @@ -16,10 +20,67 @@ pub struct ArrayElement { pub is_ref: bool, } -pub struct ComponentsData<'a, T: Iterable<'a>> { - pub array_components: T::ComponentsArray, - pub is_ref_array_components: T::BoolArray, +pub struct ComponentsData<'a, T: Iterable<'a>, const LEN: usize> { + pub array_components: [*mut u8; LEN], + pub is_ref_array_components: [bool; LEN], pub is_any_array_a_ref: bool, + _marker: PhantomData<&'a T>, +} + +pub trait ComponentPointers<'a, T: Iterable<'a>> { + fn new(iter: &IterT) -> Self; + + fn get_tuple(&mut self, index: usize) -> T::TupleType; + + fn get_slice(&mut self, count: usize) -> T::TupleSliceType; +} + +impl<'a, T: Iterable<'a>, const LEN: usize> ComponentPointers<'a, T> + for ComponentsData<'a, T, LEN> +{ + fn new(iter: &IterT) -> Self { + let mut array_components = [std::ptr::null::() as *mut u8; LEN]; + let mut is_ref_array_components = [false; LEN]; + + T::populate_array_ptrs( + iter, + &mut array_components[..], + &mut is_ref_array_components[..], + ); + + let is_any_array_a_ref = is_ref_array_components[0]; + + Self { + array_components, + is_ref_array_components, + is_any_array_a_ref, + _marker: PhantomData::<&T>, + } + } + + fn get_tuple(&mut self, index: usize) -> T::TupleType { + if self.is_any_array_a_ref { + T::create_tuple_with_ref( + &self.array_components[..], + &self.is_ref_array_components[..], + index, + ) + } else { + T::create_tuple(&self.array_components[..], index) + } + } + + fn get_slice(&mut self, count: usize) -> T::TupleSliceType { + if self.is_any_array_a_ref { + T::create_tuple_slices_with_ref( + &self.array_components[..], + &self.is_ref_array_components[..], + count, + ) + } else { + T::create_tuple_slices(&self.array_components[..], count) + } + } } struct Singleton(T); @@ -280,93 +341,59 @@ where } pub trait Iterable<'a>: Sized { - type TupleType: 'a; - type ComponentsArray: 'a + std::ops::Index + std::ops::IndexMut; - type BoolArray: 'a + std::ops::Index + std::ops::IndexMut; - type TupleSliceType: 'a; + type Pointers: ComponentPointers<'a, Self>; + type TupleType; + type TupleSliceType; + + fn create_ptrs(iter: &IterT) -> Self::Pointers { + Self::Pointers::new(iter) + } fn populate(filter: &mut impl Filterable); - fn register_ids_descriptor(world: *mut WorldT, desc: &mut ecs_filter_desc_t); - fn create_array_ptrs_of_components(it: &IterT) -> ComponentsData<'a, Self>; - fn create_tuple(array_components: &Self::ComponentsArray, index: usize) -> Self::TupleType; + fn register_ids_descriptor(world: *mut WorldT, desc: &mut ecs_filter_desc_t) { + Self::register_ids_descriptor_at(world, &mut desc.terms[..], &mut 0); + } + + fn register_ids_descriptor_at( + world: *mut WorldT, + terms: &mut [sys::ecs_term_t], + index: &mut usize, + ); + + fn populate_array_ptrs(it: &IterT, components: &mut [*mut u8], is_ref: &mut [bool]); + + fn create_tuple(array_components: &[*mut u8], index: usize) -> Self::TupleType; fn create_tuple_with_ref( - array_components: &Self::ComponentsArray, - is_ref_array_components: &Self::BoolArray, + array_components: &[*mut u8], + is_ref_array_components: &[bool], index: usize, ) -> Self::TupleType; - fn create_tuple_slices( - array_components: &Self::ComponentsArray, - count: usize, - ) -> Self::TupleSliceType; + fn create_tuple_slices(array_components: &[*mut u8], count: usize) -> Self::TupleSliceType; fn create_tuple_slices_with_ref( - array_components: &Self::ComponentsArray, - is_ref_array_components: &Self::BoolArray, + array_components: &[*mut u8], + is_ref_array_components: &[bool], count: usize, ) -> Self::TupleSliceType; } ///////////////////// -// first three tuple sizes are implemented manually for easier debugging and testing and understanding. // The higher sized tuples are done by a macro towards the bottom of this file. ///////////////////// #[rustfmt::skip] -impl<'a> Iterable<'a> for () -{ - type TupleType = (); - type ComponentsArray = [*mut u8; 0]; - type BoolArray = [bool; 0]; - type TupleSliceType = (); - - fn populate(_filter : &mut impl Filterable){} - - fn register_ids_descriptor(_world: *mut WorldT,_desc: &mut ecs_filter_desc_t){} - - fn create_array_ptrs_of_components(_it: &IterT) -> ComponentsData<'a, Self> { - ComponentsData { - array_components: [], - is_ref_array_components: [], - is_any_array_a_ref: false, - } - } - - fn create_tuple(_array_components: &Self::ComponentsArray, _index: usize) -> Self::TupleType{} - - fn create_tuple_with_ref( - _array_components: &Self::ComponentsArray, - _is_ref_array_components: &Self::BoolArray, - _index: usize, - ) -> Self::TupleType {} - - fn create_tuple_slices( - _array_components: &Self::ComponentsArray, - _count: usize, - ) -> Self::TupleSliceType {} - - fn create_tuple_slices_with_ref( - _array_components: &Self::ComponentsArray, - _is_ref_array_components: &Self::BoolArray, - _count: usize, - ) -> Self::TupleSliceType {} - -} - -#[rustfmt::skip] -impl<'a, A: 'a> Iterable<'a> for (A,) +impl<'a, A: 'a> Iterable<'a> for A where A: IterableTypeOperation, { - type TupleType = (A::ActualType,); - type ComponentsArray = [*mut u8; 1]; - type BoolArray = [bool; 1]; - type TupleSliceType = (A::SliceType,); + type Pointers = ComponentsData<'a, A, 1>; + type TupleType = A::ActualType; + type TupleSliceType = A::SliceType; fn populate(filter: &mut impl Filterable) { - let world = filter.world_ptr_mut(); filter.term_with_id(A::OnlyType::get_id(world)); let term = filter.current_term(); @@ -374,233 +401,62 @@ where } - fn register_ids_descriptor(world: *mut WorldT, desc: &mut ecs_filter_desc_t) { - let term = &mut desc.terms[0]; - term.id = A::OnlyType::get_id(world); - A::populate_term(term); + fn register_ids_descriptor_at( + world: *mut WorldT, + terms: &mut [sys::ecs_term_t], + index: &mut usize, + ) { + terms[*index].id = A::OnlyType::get_id(world); + A::populate_term(&mut terms[*index]); + *index += 1; } - fn create_array_ptrs_of_components(it: &IterT) -> ComponentsData<'a, Self> { - let array_components = unsafe { - [ecs_field::(it, 1) as *mut u8] + fn populate_array_ptrs( + it: &IterT, + components: &mut [*mut u8], + is_ref: &mut [bool], + ) { + components[0] = + unsafe { ecs_field::(it, 1) as *mut u8 }; + is_ref[0] = if !it.sources.is_null() { + unsafe { *it.sources.add(0) != 0 } + } else { + false }; - let is_ref_array_components = if !it.sources.is_null() { unsafe { - [*it.sources.add(0) != 0] - }} else { [false] }; - - let is_any_array_a_ref = is_ref_array_components[0]; - - ComponentsData { - array_components, - is_ref_array_components, - is_any_array_a_ref, - } } - fn create_tuple(array_components: &Self::ComponentsArray, index: usize) -> Self::TupleType { - (A::create_tuple_data(array_components[0], index),) + fn create_tuple(array_components: &[*mut u8], index: usize) -> Self::TupleType { + A::create_tuple_data(array_components[0], index) + } // TODO since it's only one component, we don't need to check if it's a ref array or not, we can just return the first element of the array // I think this is the case for all tuples of size 1 fn create_tuple_with_ref( - array_components: &Self::ComponentsArray, - is_ref_array_components: &Self::BoolArray, - index: usize, - ) -> Self::TupleType { - (A::create_tuple_with_ref_data(array_components[0], is_ref_array_components[0], index),) - } - - fn create_tuple_slices( - array_components: &Self::ComponentsArray, - count: usize, - ) -> Self::TupleSliceType { - (A::create_tuple_slice_data(array_components[0], count),) - } - - fn create_tuple_slices_with_ref( - array_components: &Self::ComponentsArray, - is_ref_array_components: &Self::BoolArray, - count: usize, - ) -> Self::TupleSliceType { - (A::create_tuple_slices_with_ref_data(array_components[0], is_ref_array_components[0], count),) - - } -} - -#[rustfmt::skip] -impl<'a, A: 'a, B: 'a> Iterable<'a> for (A, B) -where - A: IterableTypeOperation, - B: IterableTypeOperation, -{ - type TupleType = (A::ActualType, B::ActualType); - type ComponentsArray = [*mut u8; 2]; - type BoolArray = [bool; 2]; - type TupleSliceType = (A::SliceType, B::SliceType); - - fn populate(filter : &mut impl Filterable) - { - let world = filter.world_ptr_mut(); - filter.term_with_id(A::OnlyType::get_id(world)); - let term = filter.current_term(); - A::populate_term(term); - - filter.term_with_id(B::OnlyType::get_id(world)); - let term = filter.current_term(); - B::populate_term(term); - - } - - fn register_ids_descriptor(world: *mut WorldT,desc: &mut ecs_filter_desc_t) - { - let term = &mut desc.terms[0]; - term.id = A::OnlyType::get_id(world); - A::populate_term(term); - let term = &mut desc.terms[1]; - term.id = B::OnlyType::get_id(world); - B::populate_term(term); - } - - fn create_array_ptrs_of_components(it: &IterT) -> ComponentsData<'a, Self> { - let array_components = unsafe { - [ecs_field::(it, 1) as *mut u8, - ecs_field::(it, 2) as *mut u8] - }; - - let is_ref_array_components = if !it.sources.is_null() { unsafe { - [*it.sources.add(0) != 0, - *it.sources.add(1) != 0] - }} else { [false, false] }; - - let is_any_array_a_ref = is_ref_array_components[0] || is_ref_array_components[1]; - - ComponentsData { - array_components, - is_ref_array_components, - is_any_array_a_ref, - } - } - - fn create_tuple(array_components: &Self::ComponentsArray, index: usize) -> Self::TupleType - { - (A::create_tuple_data(array_components[0], index),B::create_tuple_data(array_components[1], index),) - } - - fn create_tuple_with_ref( - array_components: &Self::ComponentsArray, - is_ref_array_components: &Self::BoolArray, - index: usize, + array_components: &[*mut u8], + is_ref_array_components: &[bool], + index: usize ) -> Self::TupleType { - (A::create_tuple_with_ref_data(array_components[0], is_ref_array_components[0], index),B::create_tuple_with_ref_data(array_components[1], is_ref_array_components[1], index),) + A::create_tuple_with_ref_data(array_components[0], is_ref_array_components[0], index) } fn create_tuple_slices( - array_components: &Self::ComponentsArray, + array_components: &[*mut u8], count: usize, ) -> Self::TupleSliceType { - (A::create_tuple_slice_data(array_components[0], count),B::create_tuple_slice_data(array_components[1], count),) + A::create_tuple_slice_data(array_components[0], count) } fn create_tuple_slices_with_ref( - array_components: &Self::ComponentsArray, - is_ref_array_components: &Self::BoolArray, + array_components: &[*mut u8], + is_ref_array_components: &[bool], count: usize, - ) -> Self::TupleSliceType { - (A::create_tuple_slices_with_ref_data(array_components[0], is_ref_array_components[0], count),B::create_tuple_slices_with_ref_data(array_components[1], is_ref_array_components[1], count),) - } -} - -#[rustfmt::skip] -impl<'a, A: 'a, B: 'a, C: 'a> Iterable<'a> for (A,B,C) -where - A: IterableTypeOperation, - B: IterableTypeOperation, - C: IterableTypeOperation, -{ - type TupleType = (A::ActualType, B::ActualType, C::ActualType); - type ComponentsArray = [*mut u8; 3]; - type BoolArray = [bool; 3]; - type TupleSliceType = (A::SliceType, B::SliceType, C::SliceType); - - fn populate(filter : &mut impl Filterable) - { - let world = filter.world_ptr_mut(); - filter.term_with_id(A::OnlyType::get_id(world)); - let term = filter.current_term(); - A::populate_term(term); - - unsafe { filter.term_with_id(B::OnlyType::get_id_unchecked()) } ; - let term = filter.current_term(); - B::populate_term(term); - - unsafe { filter.term_with_id(C::OnlyType::get_id_unchecked()) } ; - let term = filter.current_term(); - C::populate_term(term); - - } - - fn register_ids_descriptor(world: *mut WorldT,desc: &mut ecs_filter_desc_t) - { - let term = &mut desc.terms[0]; - term.id = A::OnlyType::get_id(world); - A::populate_term(term); - let term = &mut desc.terms[1]; - term.id = B::OnlyType::get_id(world); - B::populate_term(term); - let term = &mut desc.terms[2]; - term.id = C::OnlyType::get_id(world); - C::populate_term(term); - } - - fn create_array_ptrs_of_components(it: &IterT) -> ComponentsData<'a, Self>{ - let array_components = unsafe { - [ecs_field::(it, 1) as *mut u8, - ecs_field::(it, 2) as *mut u8, - ecs_field::(it, 3) as *mut u8] - }; - - let is_ref_array_components = if !it.sources.is_null() { unsafe { - [*it.sources.add(0) != 0, - *it.sources.add(1) != 0, - *it.sources.add(2) != 0] - }} else { [false, false, false] }; - - let is_any_array_a_ref = is_ref_array_components[0] || is_ref_array_components[1] || is_ref_array_components[2]; - - ComponentsData { - array_components, - is_ref_array_components, - is_any_array_a_ref, - } - } - - fn create_tuple(array_components: &Self::ComponentsArray, index: usize) -> Self::TupleType - { - (A::create_tuple_data(array_components[0], index),B::create_tuple_data(array_components[1], index),C::create_tuple_data(array_components[2], index),) - } - - fn create_tuple_with_ref( - array_components: &Self::ComponentsArray, - is_ref_array_components: &Self::BoolArray, - index: usize, - ) -> Self::TupleType { - (A::create_tuple_with_ref_data(array_components[0], is_ref_array_components[0], index),B::create_tuple_with_ref_data(array_components[1], is_ref_array_components[1], index),C::create_tuple_with_ref_data(array_components[2], is_ref_array_components[2], index),) - } - - fn create_tuple_slices( - array_components: &Self::ComponentsArray, - count: usize, - ) -> Self::TupleSliceType { - (A::create_tuple_slice_data(array_components[0], count),B::create_tuple_slice_data(array_components[1], count),C::create_tuple_slice_data(array_components[2], count),) - } - - fn create_tuple_slices_with_ref( - array_components: &Self::ComponentsArray, - is_ref_array_components: &Self::BoolArray, - count: usize, - ) -> Self::TupleSliceType { - (A::create_tuple_slices_with_ref_data(array_components[0], is_ref_array_components[0], count),B::create_tuple_slices_with_ref_data(array_components[1], is_ref_array_components[1], count),C::create_tuple_slices_with_ref_data(array_components[2], is_ref_array_components[2], count),) + ) -> Self::TupleSliceType{ + A::create_tuple_slices_with_ref_data( + array_components[0], + is_ref_array_components[0], + count, + ) } } @@ -738,28 +594,23 @@ macro_rules! tuple_count { ($head:ident, $($tail:ident),*) => { 1 + tuple_count!($($tail),*) }; } -macro_rules! ignore { - ($_:tt) => {}; -} - macro_rules! impl_iterable { - ($($t:ident: $tuple_t:ty),*) => { - impl<'a, $($t: 'a + IterableTypeOperation),*> Iterable<'a> for ($($tuple_t,)*) { + ($($t:ident),*) => { + impl<'a, $($t: 'a + IterableTypeOperation),*> Iterable<'a> for ($($t,)*) { type TupleType = ($( - $t::ActualType - ),*); + $t::ActualType, + )*); type TupleSliceType = ($( - $t::SliceType - ),*); - type ComponentsArray = [*mut u8; tuple_count!($($t),*)]; - type BoolArray = [bool; tuple_count!($($t),*)]; + $t::SliceType, + )*); + type Pointers = ComponentsData<'a, Self, { tuple_count!($($t),*) }>; fn populate(filter: &mut impl Filterable) { - let world = filter.world_ptr_mut(); + let _world = filter.world_ptr_mut(); $( - filter.term_with_id($t::OnlyType::get_id(world)); + filter.term_with_id($t::OnlyType::get_id(_world)); let term = filter.current_term(); $t::populate_term(term); @@ -767,131 +618,73 @@ macro_rules! impl_iterable { } #[allow(unused)] - fn register_ids_descriptor(world: *mut WorldT,desc: &mut ecs_filter_desc_t) { - let mut term_index = 0; - $( - let term = &mut desc.terms[term_index]; - term.id = $t::OnlyType::get_id(world); - $t::populate_term(term); - term_index += 1; - )* + fn register_ids_descriptor_at(world: *mut WorldT, terms: &mut [sys::ecs_term_t], index: &mut usize) { + $( $t::register_ids_descriptor_at(world, terms, index); )* } + #[allow(unused)] - fn create_array_ptrs_of_components(it: &IterT) -> ComponentsData<'a, Self> - { - let mut index = 1; - let mut index_ref = 0; - let mut index_is_any_ref = 0; - - unsafe { - let array_components = [ $( - { - let ptr = ecs_field::<$t::OnlyType>(it, index) as *mut u8; - index += 1; - ptr - }, - )* ]; - - let is_ref_array_components = if !it.sources.is_null() { unsafe { - [ $( - { - ignore!($t); - let is_ref = *it.sources.add(index_ref) != 0; - index_ref += 1; - is_ref - }, - )* ] - }} else { - [false; tuple_count!($($t),*)] + fn populate_array_ptrs( + it: &IterT, + components: &mut [*mut u8], + is_ref: &mut [bool], + ) { + let mut index = 0; + $( + components[index as usize] = + unsafe { ecs_field::<$t::OnlyType>(it, index + 1) as *mut u8 }; + is_ref[index as usize] = if !it.sources.is_null() { + unsafe { *it.sources.add(0) != 0 } + } else { + false }; + index += 1; + )* + } - let is_any_array_a_ref = $( - { - ignore!($t); - let is_ref = is_ref_array_components[index_is_any_ref]; - index_is_any_ref += 1; - is_ref - } || - )* false; - - ComponentsData { - array_components, - is_ref_array_components, - is_any_array_a_ref, - } - } - - } - - - #[allow(unused)] - fn create_tuple(array_components: &Self::ComponentsArray, index: usize) -> Self::TupleType { - let mut array_index = -1; - ( - $( - { - array_index += 1; - $t::create_tuple_data(array_components[array_index as usize] /*as *mut $t*/, index) - }, - )* - ) + #[allow(unused, clippy::unused_unit)] + fn create_tuple(array_components: &[*mut u8], index: usize) -> Self::TupleType { + let mut column: isize = -1; + ($({ + column += 1; + $t::create_tuple_data(array_components[column as usize], index) + },)*) } - #[allow(unused)] - fn create_tuple_with_ref(array_components: &Self::ComponentsArray, is_ref_array_components: &Self::BoolArray, index: usize) -> Self::TupleType { - let mut array_index = -1; - ( - $( - { - array_index += 1; - $t::create_tuple_with_ref_data(array_components[array_index as usize] /*as *mut $t*/, is_ref_array_components[array_index as usize], index) - }, - )* - ) + #[allow(unused, clippy::unused_unit)] + fn create_tuple_with_ref(array_components: &[*mut u8], is_ref_array_components: &[bool], index: usize) -> Self::TupleType { + let mut column: isize = -1; + ($({ + column += 1; + $t::create_tuple_with_ref_data(array_components[column as usize], is_ref_array_components[column as usize], index) + },)*) } - #[allow(unused)] + #[allow(unused, clippy::unused_unit)] fn create_tuple_slices( - array_components: &Self::ComponentsArray, + array_components: &[*mut u8], count: usize, ) -> Self::TupleSliceType { - let mut array_index = -1; - ( - $( - { - array_index += 1; - $t::create_tuple_slice_data(array_components[array_index as usize], count) - }, - )* - ) + let mut column: isize = -1; + ($({ + column += 1; + $t::create_tuple_slice_data(array_components[column as usize], count) + },)*) } - #[allow(unused)] + #[allow(unused, clippy::unused_unit)] fn create_tuple_slices_with_ref( - array_components: &Self::ComponentsArray, - is_ref_array_components: &Self::BoolArray, + array_components: &[*mut u8], + is_ref_array_components: &[bool], count: usize, ) -> Self::TupleSliceType { - let mut array_index = -1; - ( - $( - { - array_index += 1; - $t::create_tuple_slices_with_ref_data(array_components[array_index as usize], is_ref_array_components[array_index as usize], count) - }, - )* - ) + let mut column: isize = -1; + ($({ + column += 1; + $t::create_tuple_slices_with_ref_data(array_components[column as usize], is_ref_array_components[column as usize], count) + },)*) } } } } -impl_iterable!(A: A, B: B, C: C, D: D); //size 4 -impl_iterable!(A: A, B: B, C: C, D: D, E: E); //size 5 -impl_iterable!(A: A, B: B, C: C, D: D, E: E, F: F); //size 6 -impl_iterable!(A: A, B: B, C: C, D: D, E: E, F: F, G: G); //size 7 -impl_iterable!(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H); //size 8 -impl_iterable!(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I); //size 9 -impl_iterable!(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J); //size 10 -impl_iterable!(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J, K: K); //size 11 -impl_iterable!(A: A, B: B, C: C, D: D, E: E, F: F, G: G, H: H, I: I, J: J, K: K, L: L); //size 12 +tuples!(impl_iterable, 0, 12); diff --git a/flecs_ecs/src/core/utility/traits/iter.rs b/flecs_ecs/src/core/utility/traits/iter.rs index fb85d1c4..ac9c7c45 100644 --- a/flecs_ecs/src/core/utility/traits/iter.rs +++ b/flecs_ecs/src/core/utility/traits/iter.rs @@ -3,7 +3,7 @@ use std::ffi::c_char; #[cfg(any(debug_assertions, feature = "flecs_force_enable_ecs_asserts"))] use crate::core::FlecsErrorCode; use crate::{ - core::{Entity, FilterT, Iter, IterIterable, IterT, Iterable, Term}, + core::{ComponentPointers, Entity, FilterT, Iter, IterIterable, IterT, Iterable, Term}, ecs_assert, }; use flecs_ecs_sys::{ecs_filter_str, ecs_iter_fini, ecs_os_api, ecs_table_lock, ecs_table_unlock}; @@ -48,19 +48,13 @@ where let mut iter = self.retrieve_iter(); while self.iter_next(&mut iter) { - let components_data = T::create_array_ptrs_of_components(&iter); + let mut components_data = T::create_ptrs(&iter); let iter_count = iter.count as usize; - let array_components = &components_data.array_components; ecs_table_lock(self.world_ptr_mut(), iter.table); for i in 0..iter_count { - let tuple = if components_data.is_any_array_a_ref { - let is_ref_array_components = &components_data.is_ref_array_components; - T::create_tuple_with_ref(array_components, is_ref_array_components, i) - } else { - T::create_tuple(array_components, i) - }; + let tuple = components_data.get_tuple(i); func(tuple); } @@ -85,8 +79,7 @@ where let mut iter = self.retrieve_iter(); let world = self.world_ptr_mut(); while self.iter_next(&mut iter) { - let components_data = T::create_array_ptrs_of_components(&iter); - let array_components = &components_data.array_components; + let mut components_data = T::create_ptrs(&iter); let iter_count = { if iter.count == 0 { 1_usize @@ -104,13 +97,7 @@ where // update: I believe it's not possible due to not knowing the order of the components in the tuple. I will leave this here for now, maybe I will come back to it in the future. for i in 0..iter_count { let mut entity = Entity::new_from_existing_raw(world, *iter.entities.add(i)); - - let tuple = if components_data.is_any_array_a_ref { - let is_ref_array_components = &components_data.is_ref_array_components; - T::create_tuple_with_ref(array_components, is_ref_array_components, i) - } else { - T::create_tuple(array_components, i) - }; + let tuple = components_data.get_tuple(i); func(&mut entity, tuple); } @@ -126,7 +113,7 @@ where let world = self.world_ptr_mut(); while self.iter_next(&mut iter) { - let components_data = T::create_array_ptrs_of_components(&iter); + let mut components_data = T::create_ptrs(&iter); let iter_count = { if iter.count == 0 { 1_usize @@ -134,19 +121,14 @@ where iter.count as usize } }; - let array_components = &components_data.array_components; ecs_table_lock(world, iter.table); let mut iter_t = Iter::new(&mut iter); for i in 0..iter_count { - let tuple = if components_data.is_any_array_a_ref { - let is_ref_array_components = &components_data.is_ref_array_components; - T::create_tuple_with_ref(array_components, is_ref_array_components, i) - } else { - T::create_tuple(array_components, i) - }; + let tuple = components_data.get_tuple(i); + func(&mut iter_t, i, tuple); } @@ -178,19 +160,13 @@ where let world = self.world_ptr_mut(); while self.iter_next(&mut iter) { - let components_data = T::create_array_ptrs_of_components(&iter); + let mut components_data = T::create_ptrs(&iter); let iter_count = iter.count as usize; - let array_components = &components_data.array_components; ecs_table_lock(world, iter.table); for i in 0..iter_count { - let tuple = if components_data.is_any_array_a_ref { - let is_ref_array_components = &components_data.is_ref_array_components; - T::create_tuple_with_ref(array_components, is_ref_array_components, i) - } else { - T::create_tuple(array_components, i) - }; + let tuple = components_data.get_tuple(i); if func(tuple) { entity = Some(Entity::new_from_existing_raw( iter.world, @@ -232,9 +208,8 @@ where let world = self.world_ptr_mut(); while self.iter_next(&mut iter) { - let components_data = T::create_array_ptrs_of_components(&iter); + let mut components_data = T::create_ptrs(&iter); let iter_count = iter.count as usize; - let array_components = &components_data.array_components; ecs_table_lock(world, iter.table); @@ -242,12 +217,7 @@ where let mut entity = Entity::new_from_existing_raw(iter.world, *iter.entities.add(i)); - let tuple = if components_data.is_any_array_a_ref { - let is_ref_array_components = &components_data.is_ref_array_components; - T::create_tuple_with_ref(array_components, is_ref_array_components, i) - } else { - T::create_tuple(array_components, i) - }; + let tuple = components_data.get_tuple(i); if func(&mut entity, tuple) { entity_result = Some(entity); break; @@ -286,8 +256,7 @@ where let world = self.world_ptr_mut(); while self.iter_next(&mut iter) { - let components_data = T::create_array_ptrs_of_components(&iter); - let array_components = &components_data.array_components; + let mut components_data = T::create_ptrs(&iter); let iter_count = { if iter.count == 0 { 1_usize @@ -300,12 +269,7 @@ where let mut iter_t = Iter::new(&mut iter); for i in 0..iter_count { - let tuple = if components_data.is_any_array_a_ref { - let is_ref_array_components = &components_data.is_ref_array_components; - T::create_tuple_with_ref(array_components, is_ref_array_components, i) - } else { - T::create_tuple(array_components, i) - }; + let tuple = components_data.get_tuple(i); if func(&mut iter_t, i, tuple) { entity_result = Some(Entity::new_from_existing_raw( iter.world, @@ -341,22 +305,12 @@ where let world = self.world_ptr_mut(); while self.iter_next(&mut iter) { - let components_data = T::create_array_ptrs_of_components(&iter); + let mut components_data = T::create_ptrs(&iter); let iter_count = iter.count as usize; - let array_components = &components_data.array_components; ecs_table_lock(world, iter.table); - let tuple = if components_data.is_any_array_a_ref { - let is_ref_array_components = &components_data.is_ref_array_components; - T::create_tuple_slices_with_ref( - array_components, - is_ref_array_components, - iter_count, - ) - } else { - T::create_tuple_slices(array_components, iter_count) - }; + let tuple = components_data.get_slice(iter_count); let mut iter_t = Iter::new(&mut iter); func(&mut iter_t, tuple); ecs_table_unlock(world, iter.table); diff --git a/flecs_ecs/src/core/utility/traits/mod.rs b/flecs_ecs/src/core/utility/traits/mod.rs index 6dc815d1..9b1ca89e 100644 --- a/flecs_ecs/src/core/utility/traits/mod.rs +++ b/flecs_ecs/src/core/utility/traits/mod.rs @@ -22,7 +22,7 @@ pub mod private { use flecs_ecs_sys::{ecs_ctx_free_t, ecs_iter_t, ecs_table_lock, ecs_table_unlock}; - use crate::core::{Entity, Iter, IterT, Iterable, ObserverSystemBindingCtx}; + use crate::core::{ComponentPointers, Entity, Iter, IterT, Iterable, ObserverSystemBindingCtx}; #[allow(non_camel_case_types)] #[doc(hidden)] @@ -55,8 +55,7 @@ pub mod private { let each = (*ctx).each.unwrap(); let each = &mut *(each as *mut Func); - let components_data = T::create_array_ptrs_of_components(&*iter); - let array_components = &components_data.array_components; + let mut components_data = T::create_ptrs(&*iter); let iter_count = { if (*iter).count == 0 { 1_usize @@ -68,12 +67,7 @@ pub mod private { ecs_table_lock((*iter).world, (*iter).table); for i in 0..iter_count { - let tuple = if components_data.is_any_array_a_ref { - let is_ref_array_components = &components_data.is_ref_array_components; - T::create_tuple_with_ref(array_components, is_ref_array_components, i) - } else { - T::create_tuple(array_components, i) - }; + let tuple = components_data.get_tuple(i); each(tuple); } @@ -98,8 +92,7 @@ pub mod private { let each_entity = (*ctx).each_entity.unwrap(); let each_entity = &mut *(each_entity as *mut Func); - let components_data = T::create_array_ptrs_of_components(&*iter); - let array_components = &components_data.array_components; + let mut components_data = T::create_ptrs(&*iter); let iter_count = { if (*iter).count == 0 { 1_usize @@ -113,12 +106,7 @@ pub mod private { for i in 0..iter_count { let mut entity = Entity::new_from_existing_raw((*iter).world, *(*iter).entities.add(i)); - let tuple = if components_data.is_any_array_a_ref { - let is_ref_array_components = &components_data.is_ref_array_components; - T::create_tuple_with_ref(array_components, is_ref_array_components, i) - } else { - T::create_tuple(array_components, i) - }; + let tuple = components_data.get_tuple(i); each_entity(&mut entity, tuple); } @@ -143,8 +131,7 @@ pub mod private { let each_iter = (*ctx).each_iter.unwrap(); let each_iter = &mut *(each_iter as *mut Func); - let components_data = T::create_array_ptrs_of_components(&*iter); - let array_components = &components_data.array_components; + let mut components_data = T::create_ptrs(&*iter); let iter_count = { if (*iter).count == 0 { 1_usize @@ -157,12 +144,7 @@ pub mod private { let mut iter_t = Iter::new(&mut (*iter)); for i in 0..iter_count { - let tuple = if components_data.is_any_array_a_ref { - let is_ref_array_components = &components_data.is_ref_array_components; - T::create_tuple_with_ref(array_components, is_ref_array_components, i) - } else { - T::create_tuple(array_components, i) - }; + let tuple = components_data.get_tuple(i); each_iter(&mut iter_t, i, tuple); } @@ -224,8 +206,7 @@ pub mod private { let iter_func = (*ctx).iter.unwrap(); let iter_func = &mut *(iter_func as *mut Func); - let components_data = T::create_array_ptrs_of_components(&*iter); - let array_components = &components_data.array_components; + let mut components_data = T::create_ptrs(&*iter); let iter_count = { if (*iter).count == 0 { 1_usize @@ -236,16 +217,7 @@ pub mod private { ecs_table_lock((*iter).world, (*iter).table); - let tuple = if components_data.is_any_array_a_ref { - let is_ref_array_components = &components_data.is_ref_array_components; - T::create_tuple_slices_with_ref( - array_components, - is_ref_array_components, - iter_count, - ) - } else { - T::create_tuple_slices(array_components, iter_count) - }; + let tuple = components_data.get_slice(iter_count); let mut iter_t = Iter::new(&mut *iter); iter_func(&mut iter_t, tuple); ecs_table_unlock((*iter).world, (*iter).table); diff --git a/flecs_ecs/tests/entity_test.rs b/flecs_ecs/tests/entity_test.rs index 915d2462..6e918980 100644 --- a/flecs_ecs/tests/entity_test.rs +++ b/flecs_ecs/tests/entity_test.rs @@ -347,7 +347,7 @@ fn entity_get_generic_mut() { let mut invoked = false; world - .observer_builder::<(&Position,)>() + .observer_builder::<&Position>() .add_event::() .on_each(|_| { invoked = true; diff --git a/flecs_ecs_derive/src/lib.rs b/flecs_ecs_derive/src/lib.rs index ad81b036..ee90c2b9 100644 --- a/flecs_ecs_derive/src/lib.rs +++ b/flecs_ecs_derive/src/lib.rs @@ -2,10 +2,12 @@ extern crate proc_macro; use proc_macro::TokenStream as ProcMacroTokenStream; use proc_macro2::TokenStream; -use quote::quote; +use quote::{format_ident, quote}; use syn::{ parse::{Parse, ParseStream}, - parse_macro_input, Data, DeriveInput, Fields, Ident, + parse_macro_input, + token::Comma, + Data, DeriveInput, Fields, Ident, LitInt, Result, }; /// `Component` macro for defining ECS components with optional register attribute when the type is generic over a single T. @@ -494,3 +496,58 @@ fn generate_component_id_impl(name: &Ident, ty: &Ident, is_struct: bool) -> Toke } } } + +struct Tuples { + macro_ident: Ident, + start: usize, + end: usize, + idents: Vec, +} + +impl Parse for Tuples { + fn parse(input: ParseStream) -> Result { + let macro_ident = input.parse::()?; + input.parse::()?; + let start = input.parse::()?.base10_parse()?; + input.parse::()?; + let end = input.parse::()?.base10_parse()?; + let mut idents = vec![]; + while input.parse::().is_ok() { + let ident = input.parse::()?; + idents.push(ident); + } + + Ok(Tuples { + macro_ident, + start, + end, + idents, + }) + } +} + +#[proc_macro] +pub fn tuples(input: ProcMacroTokenStream) -> ProcMacroTokenStream { + let input = parse_macro_input!(input as Tuples); + let len = 1 + input.end - input.start; + let mut tuples = Vec::with_capacity(len); + for i in 0..=len { + tuples.push(format_ident!("P{}", i)); + } + + let macro_ident = &input.macro_ident; + let invocations = (input.start..=input.end).map(|i| { + let tuples = &tuples[..i]; + let idents = &input.idents; + + quote! { + #macro_ident!(#(#idents,)* #(#tuples),*); + } + }); + + ProcMacroTokenStream::from(quote! { + #( + #invocations + )* + }) +}