Skip to content

Commit

Permalink
Update docs and safety invariants
Browse files Browse the repository at this point in the history
  • Loading branch information
BoxyUwU committed Apr 28, 2022
1 parent b3ec59e commit b6b9780
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 47 deletions.
9 changes: 5 additions & 4 deletions crates/bevy_ecs/macros/src/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,8 +267,7 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
#(#ignored_field_idents: #ignored_field_types,)*
}

// SAFETY: `update_component_access` and `update_archetype_component_access` are called for each item in the struct
unsafe impl #user_impl_generics #path::query::FetchState for #state_struct_name #user_ty_generics #user_where_clauses {
impl #user_impl_generics #path::query::FetchState for #state_struct_name #user_ty_generics #user_where_clauses {
fn init(world: &mut #path::world::World) -> Self {
#state_struct_name {
#(#field_idents: <<#field_types as #path::query::WorldQuery>::State as #path::query::FetchState>::init(world),)*
Expand Down Expand Up @@ -304,7 +303,8 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
#(#(#ignored_field_attrs)* #ignored_field_visibilities #ignored_field_idents: #ignored_field_types,)*
}

impl #user_impl_generics #path::query::WorldQuery for #read_only_struct_name #user_ty_generics #user_where_clauses {
// SAFETY: `update_component_access` and `update_archetype_component_access` are called on every field
unsafe impl #user_impl_generics #path::query::WorldQuery for #read_only_struct_name #user_ty_generics #user_where_clauses {
type ReadOnly = Self;
type State = #state_struct_name #user_ty_generics;

Expand Down Expand Up @@ -372,7 +372,8 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {

#read_only_world_query_impl

impl #user_impl_generics #path::query::WorldQuery for #struct_name #user_ty_generics #user_where_clauses {
// SAFETY: `update_component_access` and `update_archetype_component_access` are called on every field
unsafe impl #user_impl_generics #path::query::WorldQuery for #struct_name #user_ty_generics #user_where_clauses {
type ReadOnly = #read_only_struct_name #user_ty_generics;
type State = #state_struct_name #user_ty_generics;
fn shrink<'__wlong: '__wshort, '__wshort>(item: #path::query::#item_type_alias<'__wlong, Self>)
Expand Down
63 changes: 32 additions & 31 deletions crates/bevy_ecs/src/query/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,13 @@ use std::{cell::UnsafeCell, marker::PhantomData};
///
/// # bevy_ecs::system::assert_is_system(my_system);
/// ```
pub trait WorldQuery: for<'w> WorldQueryGats<'w, _State = Self::State> {
/// # Safety
///
/// Implementor must ensure that [`WorldQuery::update_component_access`] and
/// [`WorldQuery::update_archetype_component_access`] exactly reflects the results of
/// [`FetchState::matches_archetype`], [`FetchState::matches_table`], [`Fetch::archetype_fetch`], and
/// [`Fetch::table_fetch`].
pub unsafe trait WorldQuery: for<'w> WorldQueryGats<'w, _State = Self::State> {
type ReadOnly: ReadOnlyWorldQuery<State = Self::State>;
type State: FetchState;

Expand Down Expand Up @@ -429,20 +435,14 @@ pub trait Fetch<'world>: Sized {
/// State used to construct a Fetch. This will be cached inside [`QueryState`](crate::query::QueryState),
/// so it is best to move as much data / computation here as possible to reduce the cost of
/// constructing Fetch.
///
/// # Safety
///
/// Implementor must ensure that [`FetchState::update_component_access`] and
/// [`FetchState::update_archetype_component_access`] exactly reflects the results of
/// [`FetchState::matches_archetype`], [`FetchState::matches_table`], [`Fetch::archetype_fetch`], and
/// [`Fetch::table_fetch`].
pub unsafe trait FetchState: Send + Sync + Sized {
pub trait FetchState: Send + Sync + Sized {
fn init(world: &mut World) -> Self;
fn matches_archetype(&self, archetype: &Archetype) -> bool;
fn matches_table(&self, table: &Table) -> bool;
}

impl WorldQuery for Entity {
/// SAFETY: no component or archetype access
unsafe impl WorldQuery for Entity {
type ReadOnly = Self;
type State = EntityState;

Expand Down Expand Up @@ -474,8 +474,7 @@ unsafe impl ReadOnlyWorldQuery for Entity {}
#[doc(hidden)]
pub struct EntityState;

// SAFETY: no component or archetype access
unsafe impl FetchState for EntityState {
impl FetchState for EntityState {
fn init(_world: &mut World) -> Self {
Self
}
Expand Down Expand Up @@ -541,7 +540,9 @@ impl<'w> Fetch<'w> for EntityFetch<'w> {
}
}

impl<T: Component> WorldQuery for &T {
// SAFETY: component access and archetype component access are properly updated to reflect that T is
// read
unsafe impl<T: Component> WorldQuery for &T {
type ReadOnly = Self;
type State = ReadState<T>;

Expand Down Expand Up @@ -578,9 +579,7 @@ pub struct ReadState<T> {
marker: PhantomData<T>,
}

// SAFETY: component access and archetype component access are properly updated to reflect that T is
// read
unsafe impl<T: Component> FetchState for ReadState<T> {
impl<T: Component> FetchState for ReadState<T> {
fn init(world: &mut World) -> Self {
let component_id = world.init_component::<T>();
ReadState {
Expand Down Expand Up @@ -725,7 +724,9 @@ impl<'w, T: Component> Fetch<'w> for ReadFetch<'w, T> {
}
}

impl<'w, T: Component> WorldQuery for &'w mut T {
/// SAFETY: // SAFETYcomponent access and archetype component access are properly updated to reflect that T is
/// read and write
unsafe impl<'w, T: Component> WorldQuery for &'w mut T {
type ReadOnly = &'w T;
type State = ReadState<T>;

Expand Down Expand Up @@ -908,7 +909,9 @@ impl<'w, 's, T: Component> Fetch<'w> for WriteFetch<'w, T> {
}
}

impl<T: WorldQuery> WorldQuery for Option<T> {
// SAFETY: component access and archetype component access are properly updated according to the
// internal Fetch
unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
type ReadOnly = Option<T::ReadOnly>;
type State = OptionState<T::State>;

Expand Down Expand Up @@ -948,9 +951,7 @@ pub struct OptionState<T: FetchState> {
state: T,
}

// SAFETY: component access and archetype component access are properly updated according to the
// internal Fetch
unsafe impl<T: FetchState> FetchState for OptionState<T> {
impl<T: FetchState> FetchState for OptionState<T> {
fn init(world: &mut World) -> Self {
Self {
state: T::init(world),
Expand Down Expand Up @@ -1095,7 +1096,9 @@ impl<T: Component> ChangeTrackers<T> {
}
}

impl<T: Component> WorldQuery for ChangeTrackers<T> {
// SAFETY: component access and archetype component access are properly updated to reflect that T is
// read
unsafe impl<T: Component> WorldQuery for ChangeTrackers<T> {
type ReadOnly = Self;
type State = ChangeTrackersState<T>;

Expand Down Expand Up @@ -1132,9 +1135,7 @@ pub struct ChangeTrackersState<T> {
marker: PhantomData<T>,
}

// SAFETY: component access and archetype component access are properly updated to reflect that T is
// read
unsafe impl<T: Component> FetchState for ChangeTrackersState<T> {
impl<T: Component> FetchState for ChangeTrackersState<T> {
fn init(world: &mut World) -> Self {
let component_id = world.init_component::<T>();
Self {
Expand Down Expand Up @@ -1377,10 +1378,9 @@ macro_rules! impl_tuple_fetch {
}
}

// SAFETY: update_component_access and update_archetype_component_access are called for each item in the tuple
#[allow(non_snake_case)]
#[allow(clippy::unused_unit)]
unsafe impl<$($name: FetchState),*> FetchState for ($($name,)*) {
impl<$($name: FetchState),*> FetchState for ($($name,)*) {
fn init(_world: &mut World) -> Self {
($($name::init(_world),)*)
}
Expand All @@ -1398,7 +1398,8 @@ macro_rules! impl_tuple_fetch {

#[allow(non_snake_case)]
#[allow(clippy::unused_unit)]
impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
// SAFETY: update_component_access and update_archetype_component_access are called for each item in the tuple
unsafe impl<$($name: WorldQuery),*> WorldQuery for ($($name,)*) {
type ReadOnly = ($($name::ReadOnly,)*);
type State = ($($name::State,)*);

Expand Down Expand Up @@ -1500,10 +1501,9 @@ macro_rules! impl_anytuple_fetch {
}
}

// SAFETY: update_component_access and update_archetype_component_access are called for each item in the tuple
#[allow(non_snake_case)]
#[allow(clippy::unused_unit)]
unsafe impl<$($name: FetchState),*> FetchState for AnyOf<($($name,)*)> {
impl<$($name: FetchState),*> FetchState for AnyOf<($($name,)*)> {
fn init(_world: &mut World) -> Self {
AnyOf(($($name::init(_world),)*))
}
Expand All @@ -1521,7 +1521,8 @@ macro_rules! impl_anytuple_fetch {

#[allow(non_snake_case)]
#[allow(clippy::unused_unit)]
impl<$($name: WorldQuery),*> WorldQuery for AnyOf<($($name,)*)> {
// SAFETY: update_component_access and update_archetype_component_access are called for each item in the tuple
unsafe impl<$($name: WorldQuery),*> WorldQuery for AnyOf<($($name,)*)> {
type ReadOnly = AnyOf<($($name::ReadOnly,)*)>;
type State = AnyOf<($($name::State,)*)>;

Expand Down
24 changes: 12 additions & 12 deletions crates/bevy_ecs/src/query/filter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ use super::ReadOnlyWorldQuery;
/// ```
pub struct With<T>(PhantomData<T>);

impl<T: Component> WorldQuery for With<T> {
// SAFETY: no component access or archetype component access
unsafe impl<T: Component> WorldQuery for With<T> {
type ReadOnly = Self;
type State = WithState<T>;

Expand Down Expand Up @@ -81,8 +82,7 @@ pub struct WithState<T> {
marker: PhantomData<T>,
}

// SAFETY: no component access or archetype component access
unsafe impl<T: Component> FetchState for WithState<T> {
impl<T: Component> FetchState for WithState<T> {
fn init(world: &mut World) -> Self {
let component_id = world.init_component::<T>();
Self {
Expand Down Expand Up @@ -187,7 +187,8 @@ impl<T> Copy for WithFetch<T> {}
/// ```
pub struct Without<T>(PhantomData<T>);

impl<T: Component> WorldQuery for Without<T> {
// SAFETY: no component access or archetype component access
unsafe impl<T: Component> WorldQuery for Without<T> {
type ReadOnly = Self;
type State = WithoutState<T>;

Expand Down Expand Up @@ -224,8 +225,7 @@ pub struct WithoutState<T> {
marker: PhantomData<T>,
}

// SAFETY: no component access or archetype component access
unsafe impl<T: Component> FetchState for WithoutState<T> {
impl<T: Component> FetchState for WithoutState<T> {
fn init(world: &mut World) -> Self {
let component_id = world.init_component::<T>();
Self {
Expand Down Expand Up @@ -350,7 +350,8 @@ macro_rules! impl_query_filter_tuple {
($(($filter: ident, $state: ident)),*) => {
#[allow(unused_variables)]
#[allow(non_snake_case)]
impl<$($filter: WorldQuery),*> WorldQuery for Or<($($filter,)*)> {
// SAFETY: update_component_access and update_archetype_component_access are called for each item in the tuple
unsafe impl<$($filter: WorldQuery),*> WorldQuery for Or<($($filter,)*)> {
type ReadOnly = Or<($($filter::ReadOnly,)*)>;
type State = Or<($($filter::State,)*)>;

Expand Down Expand Up @@ -442,10 +443,9 @@ macro_rules! impl_query_filter_tuple {
}
}

// SAFETY: update_component_access and update_archetype_component_access are called for each item in the tuple
#[allow(unused_variables)]
#[allow(non_snake_case)]
unsafe impl<$($filter: FetchState),*> FetchState for Or<($($filter,)*)> {
impl<$($filter: FetchState),*> FetchState for Or<($($filter,)*)> {
fn init(world: &mut World) -> Self {
Or(($($filter::init(world),)*))
}
Expand Down Expand Up @@ -500,7 +500,8 @@ macro_rules! impl_tick_filter {
marker: PhantomData<T>,
}

impl<T: Component> WorldQuery for $name<T> {
// SAFETY: this reads the T component. archetype component access and component access are updated to reflect that
unsafe impl<T: Component> WorldQuery for $name<T> {
type ReadOnly = Self;
type State = $state_name<T>;

Expand Down Expand Up @@ -529,8 +530,7 @@ macro_rules! impl_tick_filter {
}
}

// SAFETY: this reads the T component. archetype component access and component access are updated to reflect that
unsafe impl<T: Component> FetchState for $state_name<T> {
impl<T: Component> FetchState for $state_name<T> {
fn init(world: &mut World) -> Self {
Self {
component_id: world.init_component::<T>(),
Expand Down

0 comments on commit b6b9780

Please sign in to comment.