Skip to content

Commit a10ecce

Browse files
committed
Making archetype iter/iter_mut return View/ViewMut rather than tuples
1 parent 409c870 commit a10ecce

8 files changed

Lines changed: 80 additions & 75 deletions

File tree

CHANGELOG

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
## [Unreleased]
22
- Split `View` into `View` and `ViewMut`. Note that creating a `View` still requires mutable access to the
3-
archetype/world, but can be useful for passing around read-only access to a given entity.
3+
archetype/world, but can be useful for passing around read-only access to a given entity.
4+
- The `iter`/`iter_mut` functions on archetypes now return a `View`/`ViewMut` with named component fields rather than
5+
anonymous tuples, making element access less sensitive to component order changes. This also makes iteration more
6+
compatible with the `ArchetypeHas` trait, as that can be used to generically access components from views.

macros/src/generate/world.rs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -821,9 +821,6 @@ fn section_archetype(archetype_data: &DataArchetype) -> TokenStream {
821821

822822
type Components = #ArchetypeComponents;
823823

824-
type IterItem<'a> = (&'a Entity<#Archetype>, #(&'a #Component,)*);
825-
type IterItemMut<'a> = (&'a Entity<#Archetype>, #(&'a mut #Component,)*);
826-
827824
type Slices<'a> = #ArchetypeSlices<'a>;
828825
type View<'a> = #ArchetypeView<'a>;
829826
type ViewMut<'a> = #ArchetypeViewMut<'a>;
@@ -884,12 +881,12 @@ fn section_archetype(archetype_data: &DataArchetype) -> TokenStream {
884881
}
885882

886883
#[inline(always)]
887-
fn iter(&mut self) -> impl Iterator<Item = Self::IterItem<'_>> {
884+
fn iter(&mut self) -> impl Iterator<Item = #ArchetypeView<'_>> {
888885
self.data.iter()
889886
}
890887

891888
#[inline(always)]
892-
fn iter_mut(&mut self) -> impl Iterator<Item = Self::IterItemMut<'_>> {
889+
fn iter_mut(&mut self) -> impl Iterator<Item = #ArchetypeViewMut<'_>> {
893890
self.data.iter_mut()
894891
}
895892

src/archetype/iter.rs

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,67 +2,80 @@ use seq_macro::seq;
22

33
use crate::entity::Entity;
44
use crate::traits::Archetype;
5+
use crate::archetype::view::*;
56

67
macro_rules! declare_iter_n {
7-
($iter:ident, $iter_mut:ident, $n:literal) => {
8+
($iter:ident, $iter_mut:ident, $view:ident, $view_mut:ident, $n:literal) => {
89
seq!(I in 0..$n {
9-
pub struct $iter<'a, A: Archetype, #(T~I,)*> {
10+
pub struct $iter<'a, A: Archetype, V: $view<'a, A, #(T~I,)*>, #(T~I,)*> {
1011
pub(crate) remaining: usize,
1112
pub(crate) ptr_entity: *const Entity<A>,
1213
#(pub(crate) ptr_d~I: *const T~I,)*
13-
pub(crate) phantom: std::marker::PhantomData<&'a mut A>,
14+
pub(crate) phantom: std::marker::PhantomData<fn() -> (&'a A, &'a V)>,
1415
}
1516

16-
pub struct $iter_mut<'a, A: Archetype, #(T~I,)*> {
17+
pub struct $iter_mut<'a, A: Archetype, V: $view_mut<'a, A, #(T~I,)*>, #(T~I,)*> {
1718
pub(crate) remaining: usize,
1819
pub(crate) ptr_entity: *const Entity<A>,
1920
#(pub(crate) ptr_d~I: *mut T~I,)*
20-
pub(crate) phantom: std::marker::PhantomData<&'a mut A>,
21+
pub(crate) phantom: std::marker::PhantomData<fn() -> (&'a A, &'a V)>,
2122
}
2223

23-
impl<'a, A: Archetype + 'a, #(T~I: 'a,)*> Iterator for $iter<'a, A, #(T~I,)*> {
24-
type Item = (&'a Entity<A>, #(&'a T~I,)*);
24+
impl<
25+
'a,
26+
A: Archetype + 'a,
27+
V: $view<'a, A, #(T~I,)*> + 'a,
28+
#(T~I: 'a,)*
29+
> Iterator for $iter<'a, A, V, #(T~I,)*> {
30+
type Item = V;
2531

2632
fn next(&mut self) -> Option<Self::Item> {
2733
if self.remaining == 0 {
2834
return None;
2935
}
3036

3137
unsafe {
32-
let result = (&*self.ptr_entity, #(&*self.ptr_d~I,)*);
38+
let entity = &*self.ptr_entity;
39+
#(let arg~I = &*self.ptr_d~I;)*
3340

3441
self.ptr_entity = self.ptr_entity.offset(1);
3542
#(self.ptr_d~I = self.ptr_d~I.offset(1);)*
3643

3744
self.remaining -= 1;
38-
Some(result)
45+
Some(V::new(entity, #(arg~I,)*))
3946
}
4047
}
4148
}
4249

43-
impl<'a, A: Archetype + 'a, #(T~I: 'a,)*> Iterator for $iter_mut<'a, A, #(T~I,)*> {
44-
type Item = (&'a Entity<A>, #(&'a mut T~I,)*);
50+
impl<
51+
'a,
52+
A: Archetype + 'a,
53+
V: $view_mut<'a, A, #(T~I,)*> + 'a,
54+
#(T~I: 'a,)*
55+
> Iterator for $iter_mut<'a, A, V, #(T~I,)*> {
56+
type Item = V;
4557

4658
fn next(&mut self) -> Option<Self::Item> {
4759
if self.remaining == 0 {
4860
return None;
4961
}
5062

5163
unsafe {
52-
let result = (&*self.ptr_entity, #(&mut *self.ptr_d~I,)*);
64+
let entity = &*self.ptr_entity;
65+
#(let arg~I = &mut *self.ptr_d~I;)*
5366

5467
self.ptr_entity = self.ptr_entity.offset(1);
5568
#(self.ptr_d~I = self.ptr_d~I.offset(1);)*
5669

5770
self.remaining -= 1;
58-
Some(result)
71+
Some(V::new(entity, #(arg~I,)*))
5972
}
6073
}
6174
}
6275
});
6376
};
6477
}
6578

66-
seq!(N in 1..=16 { declare_iter_n!(Iter~N, IterMut~N, N); });
79+
seq!(N in 1..=16 { declare_iter_n!(Iter~N, IterMut~N, View~N, ViewMut~N, N); });
6780
#[cfg(feature = "32_components")]
68-
seq!(N in 17..=32 { declare_iter_n!(Iter~N, IterMut~N, N); });
81+
seq!(N in 17..=32 { declare_iter_n!(Iter~N, IterMut~N, View~N, ViewMut~N, N); });

src/archetype/storage.rs

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use crate::archetype::view::*;
1515
use crate::entity::{Entity, EntityDirect};
1616
use crate::index::{TrimmedIndex, MAX_DATA_CAPACITY};
1717
use crate::traits::{Archetype, EntityKey, StorageCanResolve};
18-
use crate::util::{debug_checked_assume, num_assert_leq};
18+
use crate::util::debug_checked_assume;
1919
use crate::version::ArchetypeVersion;
2020

2121
macro_rules! declare_storage_n {
@@ -58,8 +58,13 @@ macro_rules! declare_storage_n {
5858

5959
#[inline(always)]
6060
pub fn with_capacity(capacity: usize) -> Self {
61-
// We assume in a lot of places that u32 can trivially convert to usize
62-
num_assert_leq!(std::mem::size_of::<u32>(), std::mem::size_of::<usize>());
61+
const {
62+
assert!(
63+
mem::size_of::<u32>() <= mem::size_of::<usize>(),
64+
"unsupported architecture (usize too small)",
65+
);
66+
}
67+
6368
// Our data indices must be able to fit inside of entity handles
6469
if capacity > MAX_DATA_CAPACITY as usize {
6570
panic!("capacity may not exceed {}", MAX_DATA_CAPACITY);
@@ -246,7 +251,9 @@ macro_rules! declare_storage_n {
246251

247252
/// Returns an iterator over all of the entities and their data.
248253
#[inline]
249-
pub fn iter(&mut self) -> impl Iterator<Item = (&Entity<A>, #(&T~I,)*)> {
254+
pub fn iter<'a, V: $view<'a, A, #(T~I,)*> + 'a>(
255+
&'a mut self,
256+
) -> impl Iterator<Item = V> + use<'a, V, A, #(T~I,)*> {
250257
unsafe {
251258
// SAFETY: We've initialized all data by this point and won't exceed self.len.
252259
$iter {
@@ -260,7 +267,9 @@ macro_rules! declare_storage_n {
260267

261268
/// Returns a mutable iterator over all of the entities and their data.
262269
#[inline]
263-
pub fn iter_mut(&mut self) -> impl Iterator<Item = (&Entity<A>, #(&mut T~I,)*)> {
270+
pub fn iter_mut<'a, V: $view_mut<'a, A, #(T~I,)*> + 'a>(
271+
&'a mut self,
272+
) -> impl Iterator<Item = V> + use<'a, V, A, #(T~I,)*> {
264273
unsafe {
265274
// SAFETY: We've initialized all data by this point and won't exceed self.len.
266275
$iter_mut {

src/traits.rs

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -348,16 +348,6 @@ where
348348
/// A struct with named storage to each component in this archetype.
349349
type Components: Components<Archetype = Self>;
350350

351-
/// A struct yielded by iterators on this archetype, including the entity itself.
352-
type IterItem<'a>
353-
where
354-
Self: 'a;
355-
356-
/// A struct yielded by mut iterators on this archetype, including the entity itself.
357-
type IterItemMut<'a>
358-
where
359-
Self: 'a;
360-
361351
/// The slices type when accessing all of this archetype's slices simultaneously.
362352
type Slices<'a>
363353
where
@@ -429,10 +419,10 @@ where
429419
) -> Result<Entity<Self>, Self::Components>;
430420

431421
/// Returns an iterator over all of the entities and their data.
432-
fn iter(&mut self) -> impl Iterator<Item = Self::IterItem<'_>>;
422+
fn iter(&mut self) -> impl Iterator<Item = Self::View<'_>>;
433423

434424
/// Returns a mutable iterator over all of the entities and their data.
435-
fn iter_mut(&mut self) -> impl Iterator<Item = Self::IterItemMut<'_>>;
425+
fn iter_mut(&mut self) -> impl Iterator<Item = Self::ViewMut<'_>>;
436426

437427
/// Returns mutable slices to all data for all entities in the archetype. To get the
438428
/// data index for a specific entity using this function, use the `resolve` function.

src/util.rs

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -2,37 +2,6 @@
22
#![allow(unused_macros)]
33
#![allow(unused_imports)]
44

5-
pub(crate) struct NumAssert<const L: usize, const R: usize>;
6-
7-
#[allow(clippy::erasing_op)]
8-
impl<const L: usize, const R: usize> NumAssert<L, R> {
9-
pub const LEQ: usize = R - L;
10-
pub const LT: usize = R - L - 1;
11-
}
12-
13-
macro_rules! num_assert_leq {
14-
($a:expr, $b:expr) => {
15-
#[allow(path_statements)]
16-
#[allow(clippy::no_effect)]
17-
{
18-
$crate::util::NumAssert::<{ $a }, { $b }>::LEQ;
19-
}
20-
};
21-
}
22-
23-
macro_rules! num_assert_lt {
24-
($a:expr, $b:expr) => {
25-
#[allow(path_statements)]
26-
#[allow(clippy::no_effect)]
27-
{
28-
$crate::util::NumAssert::<{ $a }, { $b }>::LT;
29-
}
30-
};
31-
}
32-
33-
pub(crate) use num_assert_leq;
34-
pub(crate) use num_assert_lt;
35-
365
/// Hints the compiler that the given predicate will always be true.
376
///
387
/// # Safety

tests/test_generic.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,16 @@ pub fn test_generic_borrow_get() {
6161
assert_eq!(borrow.component::<CompB>().0, 2);
6262
}
6363

64+
#[test]
65+
pub fn test_generic_iter() {
66+
let mut world = EcsWorld::new();
67+
68+
world.create::<ArchFoo>((CompA(1), CompB(2)));
69+
world.create::<ArchFoo>((CompA(3), CompB(4)));
70+
71+
assert_eq!(sum_generic(world.archetype_mut::<ArchFoo>()), 1 + 2 + 3 + 4);
72+
}
73+
6474
fn view_increment<'a, V: ViewMut<'a>>(view: &mut V)
6575
where
6676
V::Archetype: ArchetypeHas<CompA> + ArchetypeHas<CompB>,
@@ -96,3 +106,17 @@ where
96106
borrow.component_mut::<CompA>().0 += 1;
97107
borrow.component_mut::<CompB>().0 += 1;
98108
}
109+
110+
fn sum_generic<A>(archetype: &mut A) -> u32
111+
where
112+
A: ArchetypeHas<CompA> + ArchetypeHas<CompB>,
113+
{
114+
let mut sum = 0;
115+
116+
for view in archetype.iter() {
117+
sum += view.component::<CompA>().0;
118+
sum += view.component::<CompB>().0;
119+
}
120+
121+
sum
122+
}

tests/test_iter.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,20 +24,20 @@ pub fn test_single_iter() {
2424

2525
let mut vec = Vec::new();
2626

27-
for (_, a, _) in world.arch_foo.iter() {
28-
vec.push(a.0);
27+
for view in world.arch_foo.iter() {
28+
vec.push(view.comp_a.0);
2929
}
3030

3131
assert_eq!(vec, vec![0, 1, 2, 3, 4]);
3232

3333
vec.clear();
3434

35-
for (_, a, _) in world.arch_foo.iter_mut() {
36-
a.0 += 1;
35+
for view in world.arch_foo.iter_mut() {
36+
view.comp_a.0 += 1;
3737
}
3838

39-
for (_, a, _) in world.arch_foo.iter() {
40-
vec.push(a.0);
39+
for view in world.arch_foo.iter() {
40+
vec.push(view.comp_a.0);
4141
}
4242

4343
assert_eq!(vec, vec![1, 2, 3, 4, 5]);

0 commit comments

Comments
 (0)