Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add default system sets based on World accesses #5388

Closed
wants to merge 30 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
2677f4d
allow `SystemParam`s to apply labels to systems which contain them
JoJoJet Jul 20, 2022
8b5a374
add auto-labels to `EventReader` and `EventWriter`
JoJoJet Jul 20, 2022
7b954f8
improve ergonomics of the read/write label types
JoJoJet Jul 20, 2022
e5b9cf1
retain auto-labels in `SystemParam`
JoJoJet Jul 20, 2022
a91041c
add doctests to `Reads`/`Writes`
JoJoJet Jul 20, 2022
5d24069
add a method to remove labels from systems
JoJoJet Jul 20, 2022
862ad96
add unit tests
JoJoJet Jul 21, 2022
5906a96
generalize `Reads`/`Writes` to resources
JoJoJet Jul 21, 2022
49dee8c
Merge remote-tracking branch 'upstream/main' into event-labels-patch
JoJoJet Mar 1, 2023
9b3801c
revert derive macro
JoJoJet Mar 1, 2023
106402a
fix a merge error
JoJoJet Mar 1, 2023
2df782e
simplify `default_system_sets` initialization
JoJoJet Mar 1, 2023
a55be95
allow system params to add default sets
JoJoJet Mar 1, 2023
abcb2cc
allow `WorldQuery`s to add default sets
JoJoJet Mar 1, 2023
157c0fb
Merge remote-tracking branch 'upstream/main' into event-labels
JoJoJet Mar 1, 2023
4a4fdf0
add a missing closing brace
JoJoJet Mar 1, 2023
e8bcf00
simplify boxed system sets
JoJoJet Mar 1, 2023
f5b3a8e
make component attributes more flexible
JoJoJet Mar 1, 2023
5d75bf0
propagate default sets for world queries
JoJoJet Mar 1, 2023
e79d255
propagate default sets for system params
JoJoJet Mar 1, 2023
ddb7406
specify access sets for components
JoJoJet Mar 1, 2023
ac493fd
fix parsing for read and write sets
JoJoJet Mar 1, 2023
4ef31a0
add a test case for write sets
JoJoJet Mar 1, 2023
29f9978
fix ci
JoJoJet Mar 1, 2023
36d4f66
simplify string parsing
JoJoJet Mar 1, 2023
3c49b8a
don't require sets to be in quotes
JoJoJet Mar 1, 2023
8320b04
cargo fmt
JoJoJet Mar 1, 2023
f3c0713
return a custom type from parse_attrs
JoJoJet Mar 1, 2023
241ccf3
fix ci
JoJoJet Mar 1, 2023
3d711d4
use a match statement for attribute arguments
JoJoJet Mar 1, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 27 additions & 25 deletions crates/bevy_ecs/macros/src/component.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use bevy_macro_utils::{get_lit_str, Symbol};
use bevy_macro_utils::{get_lit_str, NamedArg, Symbol};
use proc_macro::TokenStream;
use proc_macro2::{Span, TokenStream as TokenStream2};
use quote::{quote, ToTokens};
use quote::quote;
use syn::{parse_macro_input, parse_quote, DeriveInput, Error, Ident, Path, Result};

pub fn derive_resource(input: TokenStream) -> TokenStream {
Expand Down Expand Up @@ -33,6 +33,9 @@ pub fn derive_component(input: TokenStream) -> TokenStream {

let storage = storage_path(&bevy_ecs_path, attrs.storage);

let read_sets = attrs.read_sets;
let write_sets = attrs.write_sets;

ast.generics
.make_where_clause()
.predicates
Expand All @@ -44,6 +47,14 @@ pub fn derive_component(input: TokenStream) -> TokenStream {
TokenStream::from(quote! {
impl #impl_generics #bevy_ecs_path::component::Component for #struct_name #type_generics #where_clause {
type Storage = #storage;

fn add_read_sets(_sets: &mut Vec<#bevy_ecs_path::schedule::BoxedSystemSet>) {
#(_sets.push(#read_sets.dyn_clone());)*
}

fn add_write_sets(_sets: &mut Vec<#bevy_ecs_path::schedule::BoxedSystemSet>) {
#(_sets.push(Box::new(#write_sets));)*
}
}
})
}
Expand All @@ -53,6 +64,8 @@ pub const STORAGE: Symbol = Symbol("storage");

struct Attrs {
storage: StorageTy,
read_sets: Vec<syn::Expr>,
write_sets: Vec<syn::Expr>,
}

#[derive(Clone, Copy)]
Expand All @@ -66,47 +79,36 @@ const TABLE: &str = "Table";
const SPARSE_SET: &str = "SparseSet";

fn parse_component_attr(ast: &DeriveInput) -> Result<Attrs> {
let meta_items = bevy_macro_utils::parse_attrs(ast, COMPONENT)?;

let mut attrs = Attrs {
storage: StorageTy::Table,
read_sets: vec![],
write_sets: vec![],
};

for meta in meta_items {
use syn::{
Meta::NameValue,
NestedMeta::{Lit, Meta},
};
match meta {
Meta(NameValue(m)) if m.path == STORAGE => {
attrs.storage = match get_lit_str(STORAGE, &m.lit)?.value().as_str() {
for NamedArg { path, expr } in bevy_macro_utils::parse_attrs(ast, COMPONENT)? {
match path.get_ident().unwrap().to_string().as_str() {
"storage" => {
attrs.storage = match get_lit_str(STORAGE, &expr)?.value().as_str() {
TABLE => StorageTy::Table,
SPARSE_SET => StorageTy::SparseSet,
s => {
return Err(Error::new_spanned(
m.lit,
expr,
format!(
"Invalid storage type `{s}`, expected '{TABLE}' or '{SPARSE_SET}'.",
),
))
}
};
}
Meta(meta_item) => {
"read_set" => attrs.read_sets.push(expr),
"write_set" => attrs.write_sets.push(expr),
_ => {
return Err(Error::new_spanned(
meta_item.path(),
format!(
"unknown component attribute `{}`",
meta_item.path().into_token_stream()
),
path,
"Invalid component attribute format: expected `storages`, `read_set`, or `write_set`",
));
}
Lit(lit) => {
return Err(Error::new_spanned(
lit,
"unexpected literal in component attribute",
))
}
}
}

Expand Down
4 changes: 4 additions & 0 deletions crates/bevy_ecs/macros/src/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,10 @@ pub fn derive_world_query_impl(ast: DeriveInput) -> TokenStream {
fn matches_component_set(state: &Self::State, _set_contains_id: &impl Fn(#path::component::ComponentId) -> bool) -> bool {
true #(&& <#field_types>::matches_component_set(&state.#field_idents, _set_contains_id))*
}

fn add_default_sets(_sets: &mut Vec<#path::schedule::BoxedSystemSet>) {
#( <#field_types>::add_default_sets(_sets); )*
}
}
}
};
Expand Down
10 changes: 10 additions & 0 deletions crates/bevy_ecs/macros/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,11 @@ pub fn impl_param_set(_input: TokenStream) -> TokenStream {
change_tick,
}
}

#[inline]
fn add_default_sets(_sets: &mut Vec<BoxedSystemSet>) {
#( #param::add_default_sets(_sets); )*
}
}

impl<'w, 's, #(#param: SystemParam,)*> ParamSet<'w, 's, (#(#param,)*)>
Expand Down Expand Up @@ -441,6 +446,11 @@ pub fn derive_system_param(input: TokenStream) -> TokenStream {
#(#ignored_fields: std::default::Default::default(),)*
}
}

#[inline]
fn add_default_sets(_sets: &mut Vec<#path::schedule::BoxedSystemSet>) {
<(#(#tuple_types,)*) as #path::system::SystemParam>::add_default_sets(_sets);
}
}

// Safety: Each field is `ReadOnlySystemParam`, so this can only read from the `World`
Expand Down
7 changes: 7 additions & 0 deletions crates/bevy_ecs/src/component.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

use crate::{
change_detection::MAX_CHANGE_AGE,
schedule::BoxedSystemSet,
storage::{SparseSetIndex, Storages},
system::{Local, Resource},
world::{FromWorld, World},
Expand Down Expand Up @@ -147,6 +148,12 @@ use std::{
/// [`Exclusive`]: https://doc.rust-lang.org/nightly/std/sync/struct.Exclusive.html
pub trait Component: Send + Sync + 'static {
type Storage: ComponentStorage;

#[allow(unused_variables)]
fn add_read_sets(sets: &mut Vec<BoxedSystemSet>) {}

#[allow(unused_variables)]
fn add_write_sets(sets: &mut Vec<BoxedSystemSet>) {}
}

pub struct TableStorage;
Expand Down
30 changes: 30 additions & 0 deletions crates/bevy_ecs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ type TypeIdMap<V> = rustc_hash::FxHashMap<TypeId, V>;
mod tests {
use crate as bevy_ecs;
use crate::prelude::Or;
use crate::schedule::{IntoSystemConfig, Schedule, ScheduleBuildSettings};
use crate::system::Query;
use crate::{
bundle::Bundle,
change_detection::Ref,
Expand All @@ -74,6 +76,7 @@ mod tests {
system::Resource,
world::{Mut, World},
};
use bevy_ecs_macros::SystemSet;
use bevy_tasks::{ComputeTaskPool, TaskPool};
use std::{
any::TypeId,
Expand Down Expand Up @@ -1738,4 +1741,31 @@ mod tests {
"new entity was spawned and received C component"
);
}

#[test]
fn component_with_access_set() {
#[derive(SystemSet, Debug, Clone, Copy, PartialEq, Eq, Hash)]
struct WriteSet;

#[derive(Component)]
#[component(write_set = WriteSet)]
struct WithWriteSet;

fn does_write(_q: Query<&mut WithWriteSet>) {}
fn after_write(_q: Query<&WithWriteSet>) {}

let mut world = World::new();
let mut schedule = Schedule::new();

schedule.add_system(does_write);
schedule.add_system(after_write.after(WriteSet));

// Panic if there are ambiguities.
schedule.set_build_settings(ScheduleBuildSettings {
ambiguity_detection: bevy_ecs::schedule::LogLevel::Error,
..Default::default()
});

schedule.run(&mut world);
}
}
24 changes: 24 additions & 0 deletions crates/bevy_ecs/src/query/fetch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
component::{Component, ComponentId, ComponentStorage, ComponentTicks, StorageType, Tick},
entity::Entity,
query::{Access, DebugCheckedUnwrap, FilteredAccess},
schedule::BoxedSystemSet,
storage::{ComponentSparseSet, Table, TableRow},
world::{Mut, Ref, World},
};
Expand Down Expand Up @@ -428,6 +429,9 @@ pub unsafe trait WorldQuery {
state: &Self::State,
set_contains_id: &impl Fn(ComponentId) -> bool,
) -> bool;

#[allow(unused_variables)]
fn add_default_sets(sets: &mut Vec<BoxedSystemSet>) {}
}

/// A world query that is read only.
Expand Down Expand Up @@ -648,6 +652,10 @@ unsafe impl<T: Component> WorldQuery for &T {
) -> bool {
set_contains_id(state)
}

fn add_default_sets(sets: &mut Vec<BoxedSystemSet>) {
T::add_read_sets(sets);
}
}

/// SAFETY: access is read only
Expand Down Expand Up @@ -809,6 +817,10 @@ unsafe impl<'__w, T: Component> WorldQuery for Ref<'__w, T> {
) -> bool {
set_contains_id(state)
}

fn add_default_sets(sets: &mut Vec<BoxedSystemSet>) {
T::add_read_sets(sets);
}
}

/// SAFETY: access is read only
Expand Down Expand Up @@ -974,6 +986,10 @@ unsafe impl<'__w, T: Component> WorldQuery for &'__w mut T {
) -> bool {
set_contains_id(state)
}

fn add_default_sets(sets: &mut Vec<BoxedSystemSet>) {
T::add_write_sets(sets);
}
}

#[doc(hidden)]
Expand Down Expand Up @@ -1078,6 +1094,10 @@ unsafe impl<T: WorldQuery> WorldQuery for Option<T> {
) -> bool {
true
}

fn add_default_sets(sets: &mut Vec<BoxedSystemSet>) {
T::add_default_sets(sets);
}
}

/// SAFETY: [`OptionFetch`] is read only because `T` is read only
Expand Down Expand Up @@ -1559,6 +1579,10 @@ macro_rules! impl_anytuple_fetch {
let ($($name,)*) = _state;
false $(|| $name::matches_component_set($name, _set_contains_id))*
}

fn add_default_sets(_sets: &mut Vec<BoxedSystemSet>) {
$( $name::add_default_sets(_sets); )*
}
}

/// SAFETY: each item in the tuple is read only
Expand Down
5 changes: 2 additions & 3 deletions crates/bevy_ecs/src/schedule/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,9 @@ pub struct SystemConfig {

impl SystemConfig {
fn new(system: BoxedSystem) -> Self {
// include system in its default sets
let sets = system.default_system_sets().into_iter().collect();
let mut graph_info = GraphInfo::system();
graph_info.sets = sets;
// Include the system in its default sets.
graph_info.sets = system.default_system_sets();
Self {
system,
graph_info,
Expand Down
7 changes: 5 additions & 2 deletions crates/bevy_ecs/src/system/function_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use crate::{
component::ComponentId,
prelude::FromWorld,
query::{Access, FilteredAccessSet},
schedule::BoxedSystemSet,
system::{check_system_change_tick, ReadOnlySystemParam, System, SystemParam, SystemParamItem},
world::{World, WorldId},
};
Expand Down Expand Up @@ -515,9 +516,11 @@ where
);
}

fn default_system_sets(&self) -> Vec<Box<dyn crate::schedule::SystemSet>> {
fn default_system_sets(&self) -> Vec<BoxedSystemSet> {
let set = crate::schedule::SystemTypeSet::<F>::new();
vec![Box::new(set)]
let mut sets = vec![Box::new(set) as BoxedSystemSet];
F::Param::add_default_sets(&mut sets);
sets
}
}

Expand Down
19 changes: 19 additions & 0 deletions crates/bevy_ecs/src/system/system_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ use crate::{
query::{
Access, FilteredAccess, FilteredAccessSet, QueryState, ReadOnlyWorldQuery, WorldQuery,
},
schedule::BoxedSystemSet,
system::{Query, SystemMeta},
world::{FromWorld, World},
};
Expand Down Expand Up @@ -171,6 +172,9 @@ pub unsafe trait SystemParam: Sized {
world: &'world World,
change_tick: u32,
) -> Self::Item<'world, 'state>;

#[allow(unused_variables)]
fn add_default_sets(sets: &mut Vec<BoxedSystemSet>) {}
}

/// A [`SystemParam`] that only reads a given [`World`].
Expand Down Expand Up @@ -237,6 +241,11 @@ unsafe impl<Q: WorldQuery + 'static, F: ReadOnlyWorldQuery + 'static> SystemPara
false,
)
}

fn add_default_sets(sets: &mut Vec<BoxedSystemSet>) {
Q::add_default_sets(sets);
F::add_default_sets(sets);
}
}

fn assert_component_access_compatibility(
Expand Down Expand Up @@ -1416,6 +1425,11 @@ macro_rules! impl_system_param_tuple {
let ($($param,)*) = state;
($($param::get_param($param, _system_meta, _world, _change_tick),)*)
}

#[inline]
fn add_default_sets(_sets: &mut Vec<BoxedSystemSet>) {
$( $param::add_default_sets(_sets); )*
}
}
};
}
Expand Down Expand Up @@ -1539,6 +1553,11 @@ unsafe impl<P: SystemParam + 'static> SystemParam for StaticSystemParam<'_, '_,
// SAFETY: Defer to the safety of P::SystemParam
StaticSystemParam(P::get_param(state, system_meta, world, change_tick))
}

#[inline]
fn add_default_sets(sets: &mut Vec<BoxedSystemSet>) {
P::add_default_sets(sets);
}
}

#[cfg(test)]
Expand Down
1 change: 1 addition & 0 deletions crates/bevy_macro_utils/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ license = "MIT OR Apache-2.0"
keywords = ["bevy"]

[dependencies]
proc-macro2 = "1"
toml_edit = "0.19"
syn = "1.0"
quote = "1.0"
Loading