Skip to content

Commit 18db650

Browse files
authored
Try #2305:
2 parents 71bf07f + 596268e commit 18db650

5 files changed

Lines changed: 430 additions & 237 deletions

File tree

crates/bevy_ecs/src/query/fetch.rs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use std::{
4343
pub trait WorldQuery {
4444
type Fetch: for<'a> Fetch<'a, State = Self::State>;
4545
type State: FetchState;
46+
type ReadOnlyFetch: for<'a> Fetch<'a, State = Self::State> + ReadOnlyFetch;
4647
}
4748

4849
pub trait Fetch<'w>: Sized {
@@ -134,6 +135,7 @@ pub unsafe trait ReadOnlyFetch {}
134135
impl WorldQuery for Entity {
135136
type Fetch = EntityFetch;
136137
type State = EntityState;
138+
type ReadOnlyFetch = EntityFetch;
137139
}
138140

139141
/// The [`Fetch`] of [`Entity`].
@@ -222,6 +224,7 @@ impl<'w> Fetch<'w> for EntityFetch {
222224
impl<T: Component> WorldQuery for &T {
223225
type Fetch = ReadFetch<T>;
224226
type State = ReadState<T>;
227+
type ReadOnlyFetch = ReadFetch<T>;
225228
}
226229

227230
/// The [`FetchState`] of `&T`.
@@ -382,6 +385,7 @@ impl<'w, T: Component> Fetch<'w> for ReadFetch<T> {
382385
impl<T: Component> WorldQuery for &mut T {
383386
type Fetch = WriteFetch<T>;
384387
type State = WriteState<T>;
388+
type ReadOnlyFetch = ReadOnlyWriteFetch<T>;
385389
}
386390

387391
/// The [`Fetch`] of `&mut T`.
@@ -411,6 +415,36 @@ impl<T> Clone for WriteFetch<T> {
411415
}
412416
}
413417

418+
/// The [`ReadOnlyFetch`] of `&mut T`.
419+
pub struct ReadOnlyWriteFetch<T> {
420+
storage_type: StorageType,
421+
table_components: NonNull<T>,
422+
table_ticks: *const UnsafeCell<ComponentTicks>,
423+
entities: *const Entity,
424+
entity_table_rows: *const usize,
425+
sparse_set: *const ComponentSparseSet,
426+
last_change_tick: u32,
427+
change_tick: u32,
428+
}
429+
430+
/// SAFETY: access is read only
431+
unsafe impl<T> ReadOnlyFetch for ReadOnlyWriteFetch<T> {}
432+
433+
impl<T> Clone for ReadOnlyWriteFetch<T> {
434+
fn clone(&self) -> Self {
435+
Self {
436+
storage_type: self.storage_type,
437+
table_components: self.table_components,
438+
table_ticks: self.table_ticks,
439+
entities: self.entities,
440+
entity_table_rows: self.entity_table_rows,
441+
sparse_set: self.sparse_set,
442+
last_change_tick: self.last_change_tick,
443+
change_tick: self.change_tick,
444+
}
445+
}
446+
}
447+
414448
/// The [`FetchState`] of `&mut T`.
415449
pub struct WriteState<T> {
416450
component_id: ComponentId,
@@ -567,9 +601,95 @@ impl<'w, T: Component> Fetch<'w> for WriteFetch<T> {
567601
}
568602
}
569603

604+
impl<'w, T: Component> Fetch<'w> for ReadOnlyWriteFetch<T> {
605+
type Item = &'w T;
606+
type State = WriteState<T>;
607+
608+
#[inline]
609+
fn is_dense(&self) -> bool {
610+
match self.storage_type {
611+
StorageType::Table => true,
612+
StorageType::SparseSet => false,
613+
}
614+
}
615+
616+
unsafe fn init(
617+
world: &World,
618+
state: &Self::State,
619+
last_change_tick: u32,
620+
change_tick: u32,
621+
) -> Self {
622+
let mut value = Self {
623+
storage_type: state.storage_type,
624+
table_components: NonNull::dangling(),
625+
entities: ptr::null::<Entity>(),
626+
entity_table_rows: ptr::null::<usize>(),
627+
sparse_set: ptr::null::<ComponentSparseSet>(),
628+
table_ticks: ptr::null::<UnsafeCell<ComponentTicks>>(),
629+
last_change_tick,
630+
change_tick,
631+
};
632+
if state.storage_type == StorageType::SparseSet {
633+
value.sparse_set = world
634+
.storages()
635+
.sparse_sets
636+
.get(state.component_id)
637+
.unwrap();
638+
}
639+
value
640+
}
641+
642+
#[inline]
643+
unsafe fn set_archetype(
644+
&mut self,
645+
state: &Self::State,
646+
archetype: &Archetype,
647+
tables: &Tables,
648+
) {
649+
match state.storage_type {
650+
StorageType::Table => {
651+
self.entity_table_rows = archetype.entity_table_rows().as_ptr();
652+
let column = tables[archetype.table_id()]
653+
.get_column(state.component_id)
654+
.unwrap();
655+
self.table_components = column.get_data_ptr().cast::<T>();
656+
self.table_ticks = column.get_ticks_ptr();
657+
}
658+
StorageType::SparseSet => self.entities = archetype.entities().as_ptr(),
659+
}
660+
}
661+
662+
#[inline]
663+
unsafe fn set_table(&mut self, state: &Self::State, table: &Table) {
664+
let column = table.get_column(state.component_id).unwrap();
665+
self.table_components = column.get_data_ptr().cast::<T>();
666+
self.table_ticks = column.get_ticks_ptr();
667+
}
668+
669+
#[inline]
670+
unsafe fn archetype_fetch(&mut self, archetype_index: usize) -> Self::Item {
671+
match self.storage_type {
672+
StorageType::Table => {
673+
let table_row = *self.entity_table_rows.add(archetype_index);
674+
&*self.table_components.as_ptr().add(table_row)
675+
}
676+
StorageType::SparseSet => {
677+
let entity = *self.entities.add(archetype_index);
678+
&*(*self.sparse_set).get(entity).unwrap().cast::<T>()
679+
}
680+
}
681+
}
682+
683+
#[inline]
684+
unsafe fn table_fetch(&mut self, table_row: usize) -> Self::Item {
685+
&*self.table_components.as_ptr().add(table_row)
686+
}
687+
}
688+
570689
impl<T: WorldQuery> WorldQuery for Option<T> {
571690
type Fetch = OptionFetch<T::Fetch>;
572691
type State = OptionState<T::State>;
692+
type ReadOnlyFetch = OptionFetch<T::ReadOnlyFetch>;
573693
}
574694

575695
/// The [`Fetch`] of `Option<T>`.
@@ -745,6 +865,7 @@ impl<T: Component> ChangeTrackers<T> {
745865
impl<T: Component> WorldQuery for ChangeTrackers<T> {
746866
type Fetch = ChangeTrackersFetch<T>;
747867
type State = ChangeTrackersState<T>;
868+
type ReadOnlyFetch = ChangeTrackersFetch<T>;
748869
}
749870

750871
/// The [`FetchState`] of [`ChangeTrackers`].
@@ -987,6 +1108,7 @@ macro_rules! impl_tuple_fetch {
9871108
impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
9881109
type Fetch = ($($name::Fetch,)*);
9891110
type State = ($($name::State,)*);
1111+
type ReadOnlyFetch = ($($name::ReadOnlyFetch,)*);
9901112
}
9911113

9921114
/// SAFETY: each item in the tuple is read only
@@ -996,3 +1118,48 @@ macro_rules! impl_tuple_fetch {
9961118
}
9971119

9981120
all_tuples!(impl_tuple_fetch, 0, 15, F, S);
1121+
1122+
/// [`Fetch`] that does not actually fetch anything
1123+
///
1124+
/// Mostly useful when something is generic over the Fetch and you don't want to fetch as you will discard the result
1125+
pub struct NopFetch<State> {
1126+
state: PhantomData<State>,
1127+
}
1128+
1129+
impl<'w, State: FetchState> Fetch<'w> for NopFetch<State> {
1130+
type Item = ();
1131+
type State = State;
1132+
1133+
#[inline(always)]
1134+
unsafe fn init(
1135+
_world: &World,
1136+
_state: &Self::State,
1137+
_last_change_tick: u32,
1138+
_change_tick: u32,
1139+
) -> Self {
1140+
Self { state: PhantomData }
1141+
}
1142+
1143+
#[inline(always)]
1144+
fn is_dense(&self) -> bool {
1145+
true
1146+
}
1147+
1148+
#[inline(always)]
1149+
unsafe fn set_archetype(
1150+
&mut self,
1151+
_state: &Self::State,
1152+
_archetype: &Archetype,
1153+
_tables: &Tables,
1154+
) {
1155+
}
1156+
1157+
#[inline(always)]
1158+
unsafe fn set_table(&mut self, _state: &Self::State, _table: &Table) {}
1159+
1160+
#[inline(always)]
1161+
unsafe fn archetype_fetch(&mut self, _archetype_index: usize) -> Self::Item {}
1162+
1163+
#[inline(always)]
1164+
unsafe fn table_fetch(&mut self, _table_row: usize) -> Self::Item {}
1165+
}

crates/bevy_ecs/src/query/filter.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use crate::{
33
bundle::Bundle,
44
component::{Component, ComponentId, ComponentTicks, StorageType},
55
entity::Entity,
6-
query::{Access, Fetch, FetchState, FilteredAccess, WorldQuery},
6+
query::{Access, Fetch, FetchState, FilteredAccess, ReadOnlyFetch, WorldQuery},
77
storage::{ComponentSparseSet, Table, Tables},
88
world::World,
99
};
@@ -71,6 +71,7 @@ pub struct With<T>(PhantomData<T>);
7171
impl<T: Component> WorldQuery for With<T> {
7272
type Fetch = WithFetch<T>;
7373
type State = WithState<T>;
74+
type ReadOnlyFetch = WithFetch<T>;
7475
}
7576

7677
/// The [`Fetch`] of [`With`].
@@ -163,6 +164,9 @@ impl<'a, T: Component> Fetch<'a> for WithFetch<T> {
163164
}
164165
}
165166

167+
// SAFETY: no component access or archetype component access
168+
unsafe impl<T> ReadOnlyFetch for WithFetch<T> {}
169+
166170
/// Filter that selects entities without a component `T`.
167171
///
168172
/// This is the negation of [`With`].
@@ -190,6 +194,7 @@ pub struct Without<T>(PhantomData<T>);
190194
impl<T: Component> WorldQuery for Without<T> {
191195
type Fetch = WithoutFetch<T>;
192196
type State = WithoutState<T>;
197+
type ReadOnlyFetch = WithoutFetch<T>;
193198
}
194199

195200
/// The [`Fetch`] of [`Without`].
@@ -282,11 +287,15 @@ impl<'a, T: Component> Fetch<'a> for WithoutFetch<T> {
282287
}
283288
}
284289

290+
// SAFETY: no component access or archetype component access
291+
unsafe impl<T: Component> ReadOnlyFetch for WithoutFetch<T> {}
292+
285293
pub struct WithBundle<T: Bundle>(PhantomData<T>);
286294

287295
impl<T: Bundle> WorldQuery for WithBundle<T> {
288296
type Fetch = WithBundleFetch<T>;
289297
type State = WithBundleState<T>;
298+
type ReadOnlyFetch = WithBundleFetch<T>;
290299
}
291300

292301
pub struct WithBundleFetch<T: Bundle> {
@@ -382,6 +391,9 @@ impl<'a, T: Bundle> Fetch<'a> for WithBundleFetch<T> {
382391
}
383392
}
384393

394+
// SAFETY: no component access or archetype component access
395+
unsafe impl<T: Bundle> ReadOnlyFetch for WithBundleFetch<T> {}
396+
385397
/// A filter that tests if any of the given filters apply.
386398
///
387399
/// This is useful for example if a system with multiple components in a query only wants to run
@@ -441,8 +453,11 @@ macro_rules! impl_query_filter_tuple {
441453
{
442454
type Fetch = Or<($(OrFetch<$filter::Fetch>,)*)>;
443455
type State = Or<($($filter::State,)*)>;
456+
type ReadOnlyFetch = Or<($(OrFetch<$filter::Fetch>,)*)>;
444457
}
445458

459+
/// SAFETY: this only works using the filter which doesn't write
460+
unsafe impl<$($filter: FilterFetch),*> ReadOnlyFetch for Or<($(OrFetch<$filter>,)*)> {}
446461

447462
#[allow(unused_variables)]
448463
#[allow(non_snake_case)]
@@ -569,9 +584,9 @@ macro_rules! impl_tick_filter {
569584
impl<T: Component> WorldQuery for $name<T> {
570585
type Fetch = $fetch_name<T>;
571586
type State = $state_name<T>;
587+
type ReadOnlyFetch = $fetch_name<T>;
572588
}
573589

574-
575590
// SAFETY: this reads the T component. archetype component access and component access are updated to reflect that
576591
unsafe impl<T: Component> FetchState for $state_name<T> {
577592
fn init(world: &mut World) -> Self {
@@ -678,6 +693,9 @@ macro_rules! impl_tick_filter {
678693
}
679694
}
680695
}
696+
697+
/// SAFETY: read-only access
698+
unsafe impl<T: Component> ReadOnlyFetch for $fetch_name<T> {}
681699
};
682700
}
683701

0 commit comments

Comments
 (0)