System sets and run criteria v2 (#1675)
I'm opening this prematurely; consider this an RFC that predates RFCs and therefore not super-RFC-like. This PR does two "big" things: decouple run criteria from system sets, reimagine system sets as weapons of mass system description. ### What it lets us do: * Reuse run criteria within a stage. * Pipe output of one run criteria as input to another. * Assign labels, dependencies, run criteria, and ambiguity sets to many systems at the same time. ### Things already done: * Decoupled run criteria from system sets. * Mass system description superpowers to `SystemSet`. * Implemented `RunCriteriaDescriptor`. * Removed `VirtualSystemSet`. * Centralized all run criteria of `SystemStage`. * Extended system descriptors with per-system run criteria. * `.before()` and `.after()` for run criteria. * Explicit order between state driver and related run criteria. Fixes #1672. * Opt-in run criteria deduplication; default behavior is to panic. * Labels (not exposed) for state run criteria; state run criteria are deduplicated. ### API issues that need discussion: * [`FixedTimestep::step(1.0).label("my label")`](eaccf857cd/crates/bevy_ecs/src/schedule/run_criteria.rs (L120-L122)) and [`FixedTimestep::step(1.0).with_label("my label")`](eaccf857cd/crates/bevy_core/src/time/fixed_timestep.rs (L86-L89)) are both valid but do very different things. --- I will try to maintain this post up-to-date as things change. Do check the diffs in "edited" thingy from time to time. Co-authored-by: Carter Anderson <mcanders1@gmail.com>
This commit is contained in:
		
							parent
							
								
									10ef750899
								
							
						
					
					
						commit
						d3e020a1e7
					
				@ -13,6 +13,7 @@ use bevy_ecs::{
 | 
				
			|||||||
    world::{FromWorld, World},
 | 
					    world::{FromWorld, World},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use bevy_utils::tracing::debug;
 | 
					use bevy_utils::tracing::debug;
 | 
				
			||||||
 | 
					use std::{fmt::Debug, hash::Hash};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Configure [App]s using the builder pattern
 | 
					/// Configure [App]s using the builder pattern
 | 
				
			||||||
pub struct AppBuilder {
 | 
					pub struct AppBuilder {
 | 
				
			||||||
@ -177,16 +178,18 @@ impl AppBuilder {
 | 
				
			|||||||
        self
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn add_state<T: Component + Clone + Eq>(&mut self, initial: T) -> &mut Self {
 | 
					    pub fn add_state<T>(&mut self, initial: T) -> &mut Self
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        T: Component + Debug + Clone + Eq + Hash,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
        self.insert_resource(State::new(initial))
 | 
					        self.insert_resource(State::new(initial))
 | 
				
			||||||
            .add_system_set(State::<T>::make_driver())
 | 
					            .add_system_set(State::<T>::make_driver())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn add_state_to_stage<T: Component + Clone + Eq>(
 | 
					    pub fn add_state_to_stage<T>(&mut self, stage: impl StageLabel, initial: T) -> &mut Self
 | 
				
			||||||
        &mut self,
 | 
					    where
 | 
				
			||||||
        stage: impl StageLabel,
 | 
					        T: Component + Debug + Clone + Eq + Hash,
 | 
				
			||||||
        initial: T,
 | 
					    {
 | 
				
			||||||
    ) -> &mut Self {
 | 
					 | 
				
			||||||
        self.insert_resource(State::new(initial))
 | 
					        self.insert_resource(State::new(initial))
 | 
				
			||||||
            .add_system_set_to_stage(stage, State::<T>::make_driver())
 | 
					            .add_system_set_to_stage(stage, State::<T>::make_driver())
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -433,6 +433,12 @@ pub fn derive_ambiguity_set_label(input: TokenStream) -> TokenStream {
 | 
				
			|||||||
    derive_label(input, Ident::new("AmbiguitySetLabel", Span::call_site())).into()
 | 
					    derive_label(input, Ident::new("AmbiguitySetLabel", Span::call_site())).into()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[proc_macro_derive(RunCriteriaLabel)]
 | 
				
			||||||
 | 
					pub fn derive_run_criteria_label(input: TokenStream) -> TokenStream {
 | 
				
			||||||
 | 
					    let input = parse_macro_input!(input as DeriveInput);
 | 
				
			||||||
 | 
					    derive_label(input, Ident::new("RunCriteriaLabel", Span::call_site())).into()
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
fn derive_label(input: DeriveInput, label_type: Ident) -> TokenStream2 {
 | 
					fn derive_label(input: DeriveInput, label_type: Ident) -> TokenStream2 {
 | 
				
			||||||
    let ident = input.ident;
 | 
					    let ident = input.ident;
 | 
				
			||||||
    let ecs_path: Path = bevy_ecs_path();
 | 
					    let ecs_path: Path = bevy_ecs_path();
 | 
				
			||||||
 | 
				
			|||||||
@ -19,6 +19,7 @@ pub mod prelude {
 | 
				
			|||||||
        query::{Added, ChangeTrackers, Changed, Or, QueryState, With, WithBundle, Without},
 | 
					        query::{Added, ChangeTrackers, Changed, Or, QueryState, With, WithBundle, Without},
 | 
				
			||||||
        schedule::{
 | 
					        schedule::{
 | 
				
			||||||
            AmbiguitySetLabel, ExclusiveSystemDescriptorCoercion, ParallelSystemDescriptorCoercion,
 | 
					            AmbiguitySetLabel, ExclusiveSystemDescriptorCoercion, ParallelSystemDescriptorCoercion,
 | 
				
			||||||
 | 
					            RunCriteria, RunCriteriaDescriptorCoercion, RunCriteriaLabel, RunCriteriaPiping,
 | 
				
			||||||
            Schedule, Stage, StageLabel, State, SystemLabel, SystemSet, SystemStage,
 | 
					            Schedule, Stage, StageLabel, State, SystemLabel, SystemSet, SystemStage,
 | 
				
			||||||
        },
 | 
					        },
 | 
				
			||||||
        system::{
 | 
					        system::{
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										125
									
								
								crates/bevy_ecs/src/schedule/graph_utils.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										125
									
								
								crates/bevy_ecs/src/schedule/graph_utils.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,125 @@
 | 
				
			|||||||
 | 
					use bevy_utils::{tracing::warn, HashMap, HashSet};
 | 
				
			||||||
 | 
					use fixedbitset::FixedBitSet;
 | 
				
			||||||
 | 
					use std::{borrow::Cow, fmt::Debug, hash::Hash};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub enum DependencyGraphError<Labels> {
 | 
				
			||||||
 | 
					    GraphCycles(Vec<(usize, Labels)>),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait GraphNode<Label> {
 | 
				
			||||||
 | 
					    fn name(&self) -> Cow<'static, str>;
 | 
				
			||||||
 | 
					    fn labels(&self) -> &[Label];
 | 
				
			||||||
 | 
					    fn before(&self) -> &[Label];
 | 
				
			||||||
 | 
					    fn after(&self) -> &[Label];
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Constructs a dependency graph of given nodes.
 | 
				
			||||||
 | 
					pub fn build_dependency_graph<Node, Label>(
 | 
				
			||||||
 | 
					    nodes: &[Node],
 | 
				
			||||||
 | 
					) -> HashMap<usize, HashMap<usize, HashSet<Label>>>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    Node: GraphNode<Label>,
 | 
				
			||||||
 | 
					    Label: Debug + Clone + Eq + Hash,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    let mut labels = HashMap::<Label, FixedBitSet>::default();
 | 
				
			||||||
 | 
					    for (label, index) in nodes.iter().enumerate().flat_map(|(index, container)| {
 | 
				
			||||||
 | 
					        container
 | 
				
			||||||
 | 
					            .labels()
 | 
				
			||||||
 | 
					            .iter()
 | 
				
			||||||
 | 
					            .cloned()
 | 
				
			||||||
 | 
					            .map(move |label| (label, index))
 | 
				
			||||||
 | 
					    }) {
 | 
				
			||||||
 | 
					        labels
 | 
				
			||||||
 | 
					            .entry(label)
 | 
				
			||||||
 | 
					            .or_insert_with(|| FixedBitSet::with_capacity(nodes.len()))
 | 
				
			||||||
 | 
					            .insert(index);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let mut graph = HashMap::with_capacity_and_hasher(nodes.len(), Default::default());
 | 
				
			||||||
 | 
					    for (index, node) in nodes.iter().enumerate() {
 | 
				
			||||||
 | 
					        let dependencies = graph.entry(index).or_insert_with(HashMap::default);
 | 
				
			||||||
 | 
					        for label in node.after() {
 | 
				
			||||||
 | 
					            match labels.get(label) {
 | 
				
			||||||
 | 
					                Some(new_dependencies) => {
 | 
				
			||||||
 | 
					                    for dependency in new_dependencies.ones() {
 | 
				
			||||||
 | 
					                        dependencies
 | 
				
			||||||
 | 
					                            .entry(dependency)
 | 
				
			||||||
 | 
					                            .or_insert_with(HashSet::default)
 | 
				
			||||||
 | 
					                            .insert(label.clone());
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                None => warn!(
 | 
				
			||||||
 | 
					                    // TODO: plumb this as proper output?
 | 
				
			||||||
 | 
					                    "{} wants to be after unknown label: {:?}",
 | 
				
			||||||
 | 
					                    nodes[index].name(),
 | 
				
			||||||
 | 
					                    label
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for label in node.before() {
 | 
				
			||||||
 | 
					            match labels.get(label) {
 | 
				
			||||||
 | 
					                Some(dependants) => {
 | 
				
			||||||
 | 
					                    for dependant in dependants.ones() {
 | 
				
			||||||
 | 
					                        graph
 | 
				
			||||||
 | 
					                            .entry(dependant)
 | 
				
			||||||
 | 
					                            .or_insert_with(HashMap::default)
 | 
				
			||||||
 | 
					                            .entry(index)
 | 
				
			||||||
 | 
					                            .or_insert_with(HashSet::default)
 | 
				
			||||||
 | 
					                            .insert(label.clone());
 | 
				
			||||||
 | 
					                    }
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                None => warn!(
 | 
				
			||||||
 | 
					                    "{} wants to be before unknown label: {:?}",
 | 
				
			||||||
 | 
					                    nodes[index].name(),
 | 
				
			||||||
 | 
					                    label
 | 
				
			||||||
 | 
					                ),
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    graph
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Generates a topological order for the given graph.
 | 
				
			||||||
 | 
					pub fn topological_order<Labels: Clone>(
 | 
				
			||||||
 | 
					    graph: &HashMap<usize, HashMap<usize, Labels>>,
 | 
				
			||||||
 | 
					) -> Result<Vec<usize>, DependencyGraphError<Labels>> {
 | 
				
			||||||
 | 
					    fn check_if_cycles_and_visit<L>(
 | 
				
			||||||
 | 
					        node: &usize,
 | 
				
			||||||
 | 
					        graph: &HashMap<usize, HashMap<usize, L>>,
 | 
				
			||||||
 | 
					        sorted: &mut Vec<usize>,
 | 
				
			||||||
 | 
					        unvisited: &mut HashSet<usize>,
 | 
				
			||||||
 | 
					        current: &mut Vec<usize>,
 | 
				
			||||||
 | 
					    ) -> bool {
 | 
				
			||||||
 | 
					        if current.contains(node) {
 | 
				
			||||||
 | 
					            return true;
 | 
				
			||||||
 | 
					        } else if !unvisited.remove(node) {
 | 
				
			||||||
 | 
					            return false;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        current.push(*node);
 | 
				
			||||||
 | 
					        for dependency in graph.get(node).unwrap().keys() {
 | 
				
			||||||
 | 
					            if check_if_cycles_and_visit(dependency, &graph, sorted, unvisited, current) {
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        sorted.push(*node);
 | 
				
			||||||
 | 
					        current.pop();
 | 
				
			||||||
 | 
					        false
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    let mut sorted = Vec::with_capacity(graph.len());
 | 
				
			||||||
 | 
					    let mut current = Vec::with_capacity(graph.len());
 | 
				
			||||||
 | 
					    let mut unvisited = HashSet::with_capacity_and_hasher(graph.len(), Default::default());
 | 
				
			||||||
 | 
					    unvisited.extend(graph.keys().cloned());
 | 
				
			||||||
 | 
					    while let Some(node) = unvisited.iter().next().cloned() {
 | 
				
			||||||
 | 
					        if check_if_cycles_and_visit(&node, graph, &mut sorted, &mut unvisited, &mut current) {
 | 
				
			||||||
 | 
					            let mut cycle = Vec::new();
 | 
				
			||||||
 | 
					            let last_window = [*current.last().unwrap(), current[0]];
 | 
				
			||||||
 | 
					            let mut windows = current
 | 
				
			||||||
 | 
					                .windows(2)
 | 
				
			||||||
 | 
					                .chain(std::iter::once(&last_window as &[usize]));
 | 
				
			||||||
 | 
					            while let Some(&[dependant, dependency]) = windows.next() {
 | 
				
			||||||
 | 
					                cycle.push((dependant, graph[&dependant][&dependency].clone()));
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            return Err(DependencyGraphError::GraphCycles(cycle));
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Ok(sorted)
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
pub use bevy_ecs_macros::{AmbiguitySetLabel, StageLabel, SystemLabel};
 | 
					pub use bevy_ecs_macros::{AmbiguitySetLabel, RunCriteriaLabel, StageLabel, SystemLabel};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::{
 | 
					use std::{
 | 
				
			||||||
    any::Any,
 | 
					    any::Any,
 | 
				
			||||||
@ -67,6 +67,12 @@ pub trait AmbiguitySetLabel: DynHash + Debug + Send + Sync + 'static {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
pub(crate) type BoxedAmbiguitySetLabel = Box<dyn AmbiguitySetLabel>;
 | 
					pub(crate) type BoxedAmbiguitySetLabel = Box<dyn AmbiguitySetLabel>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait RunCriteriaLabel: DynHash + Debug + Send + Sync + 'static {
 | 
				
			||||||
 | 
					    #[doc(hidden)]
 | 
				
			||||||
 | 
					    fn dyn_clone(&self) -> Box<dyn RunCriteriaLabel>;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					pub(crate) type BoxedRunCriteriaLabel = Box<dyn RunCriteriaLabel>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
macro_rules! impl_label {
 | 
					macro_rules! impl_label {
 | 
				
			||||||
    ($trait_name:ident) => {
 | 
					    ($trait_name:ident) => {
 | 
				
			||||||
        impl PartialEq for dyn $trait_name {
 | 
					        impl PartialEq for dyn $trait_name {
 | 
				
			||||||
@ -106,3 +112,4 @@ macro_rules! impl_label {
 | 
				
			|||||||
impl_label!(StageLabel);
 | 
					impl_label!(StageLabel);
 | 
				
			||||||
impl_label!(SystemLabel);
 | 
					impl_label!(SystemLabel);
 | 
				
			||||||
impl_label!(AmbiguitySetLabel);
 | 
					impl_label!(AmbiguitySetLabel);
 | 
				
			||||||
 | 
					impl_label!(RunCriteriaLabel);
 | 
				
			||||||
 | 
				
			|||||||
@ -1,6 +1,8 @@
 | 
				
			|||||||
mod executor;
 | 
					mod executor;
 | 
				
			||||||
mod executor_parallel;
 | 
					mod executor_parallel;
 | 
				
			||||||
 | 
					pub mod graph_utils;
 | 
				
			||||||
mod label;
 | 
					mod label;
 | 
				
			||||||
 | 
					mod run_criteria;
 | 
				
			||||||
mod stage;
 | 
					mod stage;
 | 
				
			||||||
mod state;
 | 
					mod state;
 | 
				
			||||||
mod system_container;
 | 
					mod system_container;
 | 
				
			||||||
@ -9,7 +11,9 @@ mod system_set;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub use executor::*;
 | 
					pub use executor::*;
 | 
				
			||||||
pub use executor_parallel::*;
 | 
					pub use executor_parallel::*;
 | 
				
			||||||
 | 
					pub use graph_utils::GraphNode;
 | 
				
			||||||
pub use label::*;
 | 
					pub use label::*;
 | 
				
			||||||
 | 
					pub use run_criteria::*;
 | 
				
			||||||
pub use stage::*;
 | 
					pub use stage::*;
 | 
				
			||||||
pub use state::*;
 | 
					pub use state::*;
 | 
				
			||||||
pub use system_container::*;
 | 
					pub use system_container::*;
 | 
				
			||||||
@ -17,20 +21,16 @@ pub use system_descriptor::*;
 | 
				
			|||||||
pub use system_set::*;
 | 
					pub use system_set::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    archetype::{Archetype, ArchetypeComponentId},
 | 
					    system::{IntoSystem, System},
 | 
				
			||||||
    component::ComponentId,
 | 
					 | 
				
			||||||
    query::Access,
 | 
					 | 
				
			||||||
    system::{BoxedSystem, IntoSystem, System, SystemId},
 | 
					 | 
				
			||||||
    world::World,
 | 
					    world::World,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use bevy_utils::HashMap;
 | 
					use bevy_utils::HashMap;
 | 
				
			||||||
use std::borrow::Cow;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Default)]
 | 
					#[derive(Default)]
 | 
				
			||||||
pub struct Schedule {
 | 
					pub struct Schedule {
 | 
				
			||||||
    stages: HashMap<BoxedStageLabel, Box<dyn Stage>>,
 | 
					    stages: HashMap<BoxedStageLabel, Box<dyn Stage>>,
 | 
				
			||||||
    stage_order: Vec<BoxedStageLabel>,
 | 
					    stage_order: Vec<BoxedStageLabel>,
 | 
				
			||||||
    run_criteria: RunCriteria,
 | 
					    run_criteria: BoxedRunCriteria,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Schedule {
 | 
					impl Schedule {
 | 
				
			||||||
@ -229,110 +229,3 @@ impl Stage for Schedule {
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
					 | 
				
			||||||
pub enum ShouldRun {
 | 
					 | 
				
			||||||
    /// Yes, the system should run.
 | 
					 | 
				
			||||||
    Yes,
 | 
					 | 
				
			||||||
    /// No, the system should not run.
 | 
					 | 
				
			||||||
    No,
 | 
					 | 
				
			||||||
    /// Yes, the system should run, and afterwards the criteria should be checked again.
 | 
					 | 
				
			||||||
    YesAndCheckAgain,
 | 
					 | 
				
			||||||
    /// No, the system should not run right now, but the criteria should be checked again later.
 | 
					 | 
				
			||||||
    NoAndCheckAgain,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub(crate) struct RunCriteria {
 | 
					 | 
				
			||||||
    criteria_system: Option<BoxedSystem<(), ShouldRun>>,
 | 
					 | 
				
			||||||
    initialized: bool,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Default for RunCriteria {
 | 
					 | 
				
			||||||
    fn default() -> Self {
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
            criteria_system: None,
 | 
					 | 
				
			||||||
            initialized: false,
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl RunCriteria {
 | 
					 | 
				
			||||||
    pub fn set(&mut self, criteria_system: BoxedSystem<(), ShouldRun>) {
 | 
					 | 
				
			||||||
        self.criteria_system = Some(criteria_system);
 | 
					 | 
				
			||||||
        self.initialized = false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    pub fn should_run(&mut self, world: &mut World) -> ShouldRun {
 | 
					 | 
				
			||||||
        if let Some(ref mut run_criteria) = self.criteria_system {
 | 
					 | 
				
			||||||
            if !self.initialized {
 | 
					 | 
				
			||||||
                run_criteria.initialize(world);
 | 
					 | 
				
			||||||
                self.initialized = true;
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            let should_run = run_criteria.run((), world);
 | 
					 | 
				
			||||||
            run_criteria.apply_buffers(world);
 | 
					 | 
				
			||||||
            should_run
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            ShouldRun::Yes
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
pub struct RunOnce {
 | 
					 | 
				
			||||||
    ran: bool,
 | 
					 | 
				
			||||||
    system_id: SystemId,
 | 
					 | 
				
			||||||
    archetype_component_access: Access<ArchetypeComponentId>,
 | 
					 | 
				
			||||||
    component_access: Access<ComponentId>,
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl Default for RunOnce {
 | 
					 | 
				
			||||||
    fn default() -> Self {
 | 
					 | 
				
			||||||
        Self {
 | 
					 | 
				
			||||||
            ran: false,
 | 
					 | 
				
			||||||
            system_id: SystemId::new(),
 | 
					 | 
				
			||||||
            archetype_component_access: Default::default(),
 | 
					 | 
				
			||||||
            component_access: Default::default(),
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
impl System for RunOnce {
 | 
					 | 
				
			||||||
    type In = ();
 | 
					 | 
				
			||||||
    type Out = ShouldRun;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn name(&self) -> Cow<'static, str> {
 | 
					 | 
				
			||||||
        Cow::Borrowed(std::any::type_name::<RunOnce>())
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn id(&self) -> SystemId {
 | 
					 | 
				
			||||||
        self.system_id
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn new_archetype(&mut self, _archetype: &Archetype) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
 | 
					 | 
				
			||||||
        &self.archetype_component_access
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn component_access(&self) -> &Access<ComponentId> {
 | 
					 | 
				
			||||||
        &self.component_access
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn is_send(&self) -> bool {
 | 
					 | 
				
			||||||
        true
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    unsafe fn run_unsafe(&mut self, _input: Self::In, _world: &World) -> Self::Out {
 | 
					 | 
				
			||||||
        if self.ran {
 | 
					 | 
				
			||||||
            ShouldRun::No
 | 
					 | 
				
			||||||
        } else {
 | 
					 | 
				
			||||||
            self.ran = true;
 | 
					 | 
				
			||||||
            ShouldRun::Yes
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn apply_buffers(&mut self, _world: &mut World) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn initialize(&mut self, _world: &mut World) {}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn check_change_tick(&mut self, _change_tick: u32) {}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										397
									
								
								crates/bevy_ecs/src/schedule/run_criteria.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										397
									
								
								crates/bevy_ecs/src/schedule/run_criteria.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,397 @@
 | 
				
			|||||||
 | 
					use crate::{
 | 
				
			||||||
 | 
					    archetype::{Archetype, ArchetypeComponentId},
 | 
				
			||||||
 | 
					    component::ComponentId,
 | 
				
			||||||
 | 
					    query::Access,
 | 
				
			||||||
 | 
					    schedule::{BoxedRunCriteriaLabel, GraphNode, RunCriteriaLabel},
 | 
				
			||||||
 | 
					    system::{BoxedSystem, System, SystemId},
 | 
				
			||||||
 | 
					    world::World,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					use std::borrow::Cow;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
				
			||||||
 | 
					pub enum ShouldRun {
 | 
				
			||||||
 | 
					    /// Yes, the system should run.
 | 
				
			||||||
 | 
					    Yes,
 | 
				
			||||||
 | 
					    /// No, the system should not run.
 | 
				
			||||||
 | 
					    No,
 | 
				
			||||||
 | 
					    /// Yes, the system should run, and afterwards the criteria should be checked again.
 | 
				
			||||||
 | 
					    YesAndCheckAgain,
 | 
				
			||||||
 | 
					    /// No, the system should not run right now, but the criteria should be checked again later.
 | 
				
			||||||
 | 
					    NoAndCheckAgain,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub(crate) struct BoxedRunCriteria {
 | 
				
			||||||
 | 
					    criteria_system: Option<BoxedSystem<(), ShouldRun>>,
 | 
				
			||||||
 | 
					    initialized: bool,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for BoxedRunCriteria {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            criteria_system: None,
 | 
				
			||||||
 | 
					            initialized: false,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl BoxedRunCriteria {
 | 
				
			||||||
 | 
					    pub fn set(&mut self, criteria_system: BoxedSystem<(), ShouldRun>) {
 | 
				
			||||||
 | 
					        self.criteria_system = Some(criteria_system);
 | 
				
			||||||
 | 
					        self.initialized = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn should_run(&mut self, world: &mut World) -> ShouldRun {
 | 
				
			||||||
 | 
					        if let Some(ref mut run_criteria) = self.criteria_system {
 | 
				
			||||||
 | 
					            if !self.initialized {
 | 
				
			||||||
 | 
					                run_criteria.initialize(world);
 | 
				
			||||||
 | 
					                self.initialized = true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            let should_run = run_criteria.run((), world);
 | 
				
			||||||
 | 
					            run_criteria.apply_buffers(world);
 | 
				
			||||||
 | 
					            should_run
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            ShouldRun::Yes
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub(crate) enum RunCriteriaInner {
 | 
				
			||||||
 | 
					    Single(BoxedSystem<(), ShouldRun>),
 | 
				
			||||||
 | 
					    Piped {
 | 
				
			||||||
 | 
					        input: usize,
 | 
				
			||||||
 | 
					        system: BoxedSystem<ShouldRun, ShouldRun>,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub(crate) struct RunCriteriaContainer {
 | 
				
			||||||
 | 
					    pub should_run: ShouldRun,
 | 
				
			||||||
 | 
					    pub inner: RunCriteriaInner,
 | 
				
			||||||
 | 
					    pub label: Option<BoxedRunCriteriaLabel>,
 | 
				
			||||||
 | 
					    pub before: Vec<BoxedRunCriteriaLabel>,
 | 
				
			||||||
 | 
					    pub after: Vec<BoxedRunCriteriaLabel>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl RunCriteriaContainer {
 | 
				
			||||||
 | 
					    pub fn from_descriptor(descriptor: RunCriteriaDescriptor) -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            should_run: ShouldRun::Yes,
 | 
				
			||||||
 | 
					            inner: match descriptor.system {
 | 
				
			||||||
 | 
					                RunCriteriaSystem::Single(system) => RunCriteriaInner::Single(system),
 | 
				
			||||||
 | 
					                RunCriteriaSystem::Piped(system) => RunCriteriaInner::Piped { input: 0, system },
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
 | 
					            label: descriptor.label,
 | 
				
			||||||
 | 
					            before: descriptor.before,
 | 
				
			||||||
 | 
					            after: descriptor.after,
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn name(&self) -> Cow<'static, str> {
 | 
				
			||||||
 | 
					        match &self.inner {
 | 
				
			||||||
 | 
					            RunCriteriaInner::Single(system) => system.name(),
 | 
				
			||||||
 | 
					            RunCriteriaInner::Piped { system, .. } => system.name(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn initialize(&mut self, world: &mut World) {
 | 
				
			||||||
 | 
					        match &mut self.inner {
 | 
				
			||||||
 | 
					            RunCriteriaInner::Single(system) => system.initialize(world),
 | 
				
			||||||
 | 
					            RunCriteriaInner::Piped { system, .. } => system.initialize(world),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl GraphNode<BoxedRunCriteriaLabel> for RunCriteriaContainer {
 | 
				
			||||||
 | 
					    fn name(&self) -> Cow<'static, str> {
 | 
				
			||||||
 | 
					        match &self.inner {
 | 
				
			||||||
 | 
					            RunCriteriaInner::Single(system) => system.name(),
 | 
				
			||||||
 | 
					            RunCriteriaInner::Piped { system, .. } => system.name(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn labels(&self) -> &[BoxedRunCriteriaLabel] {
 | 
				
			||||||
 | 
					        if let Some(ref label) = self.label {
 | 
				
			||||||
 | 
					            std::slice::from_ref(label)
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            &[]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn before(&self) -> &[BoxedRunCriteriaLabel] {
 | 
				
			||||||
 | 
					        &self.before
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn after(&self) -> &[BoxedRunCriteriaLabel] {
 | 
				
			||||||
 | 
					        &self.after
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub enum RunCriteriaDescriptorOrLabel {
 | 
				
			||||||
 | 
					    Descriptor(RunCriteriaDescriptor),
 | 
				
			||||||
 | 
					    Label(BoxedRunCriteriaLabel),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Clone, Copy)]
 | 
				
			||||||
 | 
					pub(crate) enum DuplicateLabelStrategy {
 | 
				
			||||||
 | 
					    Panic,
 | 
				
			||||||
 | 
					    Discard,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					    pub(crate) system: RunCriteriaSystem,
 | 
				
			||||||
 | 
					    pub(crate) label: Option<BoxedRunCriteriaLabel>,
 | 
				
			||||||
 | 
					    pub(crate) duplicate_label_strategy: DuplicateLabelStrategy,
 | 
				
			||||||
 | 
					    pub(crate) before: Vec<BoxedRunCriteriaLabel>,
 | 
				
			||||||
 | 
					    pub(crate) after: Vec<BoxedRunCriteriaLabel>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub(crate) enum RunCriteriaSystem {
 | 
				
			||||||
 | 
					    Single(BoxedSystem<(), ShouldRun>),
 | 
				
			||||||
 | 
					    Piped(BoxedSystem<ShouldRun, ShouldRun>),
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait IntoRunCriteria<Marker> {
 | 
				
			||||||
 | 
					    fn into(self) -> RunCriteriaDescriptorOrLabel;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl IntoRunCriteria<RunCriteriaDescriptor> for RunCriteriaDescriptorOrLabel {
 | 
				
			||||||
 | 
					    fn into(self) -> RunCriteriaDescriptorOrLabel {
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl IntoRunCriteria<RunCriteriaDescriptorOrLabel> for RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					    fn into(self) -> RunCriteriaDescriptorOrLabel {
 | 
				
			||||||
 | 
					        RunCriteriaDescriptorOrLabel::Descriptor(self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl IntoRunCriteria<BoxedSystem<(), ShouldRun>> for BoxedSystem<(), ShouldRun> {
 | 
				
			||||||
 | 
					    fn into(self) -> RunCriteriaDescriptorOrLabel {
 | 
				
			||||||
 | 
					        RunCriteriaDescriptorOrLabel::Descriptor(new_run_criteria_descriptor(self))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<S> IntoRunCriteria<BoxedSystem<(), ShouldRun>> for S
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    S: System<In = (), Out = ShouldRun>,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn into(self) -> RunCriteriaDescriptorOrLabel {
 | 
				
			||||||
 | 
					        RunCriteriaDescriptorOrLabel::Descriptor(new_run_criteria_descriptor(Box::new(self)))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl IntoRunCriteria<BoxedRunCriteriaLabel> for BoxedRunCriteriaLabel {
 | 
				
			||||||
 | 
					    fn into(self) -> RunCriteriaDescriptorOrLabel {
 | 
				
			||||||
 | 
					        RunCriteriaDescriptorOrLabel::Label(self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<L> IntoRunCriteria<BoxedRunCriteriaLabel> for L
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    L: RunCriteriaLabel,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn into(self) -> RunCriteriaDescriptorOrLabel {
 | 
				
			||||||
 | 
					        RunCriteriaDescriptorOrLabel::Label(Box::new(self))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl IntoRunCriteria<RunCriteria> for RunCriteria {
 | 
				
			||||||
 | 
					    fn into(self) -> RunCriteriaDescriptorOrLabel {
 | 
				
			||||||
 | 
					        RunCriteriaDescriptorOrLabel::Label(self.label)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait RunCriteriaDescriptorCoercion {
 | 
				
			||||||
 | 
					    /// Assigns a label to the criteria. Must be unique.
 | 
				
			||||||
 | 
					    fn label(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Assigns a label to the criteria. If the given label is already in use,
 | 
				
			||||||
 | 
					    /// this criteria will be discarded before initialization.
 | 
				
			||||||
 | 
					    fn label_discard_if_duplicate(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Specifies that this criteria must be evaluated before a criteria with the given label.
 | 
				
			||||||
 | 
					    fn before(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /// Specifies that this criteria must be evaluated after a criteria with the given label.
 | 
				
			||||||
 | 
					    fn after(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl RunCriteriaDescriptorCoercion for RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					    fn label(mut self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        self.label = Some(Box::new(label));
 | 
				
			||||||
 | 
					        self.duplicate_label_strategy = DuplicateLabelStrategy::Panic;
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn label_discard_if_duplicate(mut self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        self.label = Some(Box::new(label));
 | 
				
			||||||
 | 
					        self.duplicate_label_strategy = DuplicateLabelStrategy::Discard;
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn before(mut self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        self.before.push(Box::new(label));
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn after(mut self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        self.after.push(Box::new(label));
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					fn new_run_criteria_descriptor(system: BoxedSystem<(), ShouldRun>) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					    RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        system: RunCriteriaSystem::Single(system),
 | 
				
			||||||
 | 
					        label: None,
 | 
				
			||||||
 | 
					        duplicate_label_strategy: DuplicateLabelStrategy::Panic,
 | 
				
			||||||
 | 
					        before: vec![],
 | 
				
			||||||
 | 
					        after: vec![],
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl RunCriteriaDescriptorCoercion for BoxedSystem<(), ShouldRun> {
 | 
				
			||||||
 | 
					    fn label(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        new_run_criteria_descriptor(self).label(label)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn label_discard_if_duplicate(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        new_run_criteria_descriptor(self).label_discard_if_duplicate(label)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn before(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        new_run_criteria_descriptor(self).before(label)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn after(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        new_run_criteria_descriptor(self).after(label)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<S> RunCriteriaDescriptorCoercion for S
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    S: System<In = (), Out = ShouldRun>,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn label(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        new_run_criteria_descriptor(Box::new(self)).label(label)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn label_discard_if_duplicate(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        new_run_criteria_descriptor(Box::new(self)).label_discard_if_duplicate(label)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn before(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        new_run_criteria_descriptor(Box::new(self)).before(label)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn after(self, label: impl RunCriteriaLabel) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        new_run_criteria_descriptor(Box::new(self)).after(label)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct RunCriteria {
 | 
				
			||||||
 | 
					    label: BoxedRunCriteriaLabel,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl RunCriteria {
 | 
				
			||||||
 | 
					    /// Constructs a new run criteria that will retrieve the result of the criteria `label`
 | 
				
			||||||
 | 
					    /// and pipe it as input to `system`.
 | 
				
			||||||
 | 
					    pub fn pipe(
 | 
				
			||||||
 | 
					        label: impl RunCriteriaLabel,
 | 
				
			||||||
 | 
					        system: impl System<In = ShouldRun, Out = ShouldRun>,
 | 
				
			||||||
 | 
					    ) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        label.pipe(system)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub trait RunCriteriaPiping {
 | 
				
			||||||
 | 
					    /// See [`RunCriteria::pipe()`].
 | 
				
			||||||
 | 
					    fn pipe(self, system: impl System<In = ShouldRun, Out = ShouldRun>) -> RunCriteriaDescriptor;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl RunCriteriaPiping for BoxedRunCriteriaLabel {
 | 
				
			||||||
 | 
					    fn pipe(self, system: impl System<In = ShouldRun, Out = ShouldRun>) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					            system: RunCriteriaSystem::Piped(Box::new(system)),
 | 
				
			||||||
 | 
					            label: None,
 | 
				
			||||||
 | 
					            duplicate_label_strategy: DuplicateLabelStrategy::Panic,
 | 
				
			||||||
 | 
					            before: vec![],
 | 
				
			||||||
 | 
					            after: vec![self],
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<L> RunCriteriaPiping for L
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    L: RunCriteriaLabel,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn pipe(self, system: impl System<In = ShouldRun, Out = ShouldRun>) -> RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					        RunCriteriaDescriptor {
 | 
				
			||||||
 | 
					            system: RunCriteriaSystem::Piped(Box::new(system)),
 | 
				
			||||||
 | 
					            label: None,
 | 
				
			||||||
 | 
					            duplicate_label_strategy: DuplicateLabelStrategy::Panic,
 | 
				
			||||||
 | 
					            before: vec![],
 | 
				
			||||||
 | 
					            after: vec![Box::new(self)],
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					pub struct RunOnce {
 | 
				
			||||||
 | 
					    ran: bool,
 | 
				
			||||||
 | 
					    system_id: SystemId,
 | 
				
			||||||
 | 
					    archetype_component_access: Access<ArchetypeComponentId>,
 | 
				
			||||||
 | 
					    component_access: Access<ComponentId>,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl Default for RunOnce {
 | 
				
			||||||
 | 
					    fn default() -> Self {
 | 
				
			||||||
 | 
					        Self {
 | 
				
			||||||
 | 
					            ran: false,
 | 
				
			||||||
 | 
					            system_id: SystemId::new(),
 | 
				
			||||||
 | 
					            archetype_component_access: Default::default(),
 | 
				
			||||||
 | 
					            component_access: Default::default(),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl System for RunOnce {
 | 
				
			||||||
 | 
					    type In = ();
 | 
				
			||||||
 | 
					    type Out = ShouldRun;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn name(&self) -> Cow<'static, str> {
 | 
				
			||||||
 | 
					        Cow::Borrowed(std::any::type_name::<RunOnce>())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn id(&self) -> SystemId {
 | 
				
			||||||
 | 
					        self.system_id
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn new_archetype(&mut self, _archetype: &Archetype) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn component_access(&self) -> &Access<ComponentId> {
 | 
				
			||||||
 | 
					        &self.component_access
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn archetype_component_access(&self) -> &Access<ArchetypeComponentId> {
 | 
				
			||||||
 | 
					        &self.archetype_component_access
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn is_send(&self) -> bool {
 | 
				
			||||||
 | 
					        true
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    unsafe fn run_unsafe(&mut self, _input: Self::In, _world: &World) -> Self::Out {
 | 
				
			||||||
 | 
					        if self.ran {
 | 
				
			||||||
 | 
					            ShouldRun::No
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            self.ran = true;
 | 
				
			||||||
 | 
					            ShouldRun::Yes
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn apply_buffers(&mut self, _world: &mut World) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn initialize(&mut self, _world: &mut World) {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn check_change_tick(&mut self, _change_tick: u32) {}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							@ -1,8 +1,12 @@
 | 
				
			|||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    component::Component,
 | 
					    component::Component,
 | 
				
			||||||
    schedule::{ShouldRun, SystemSet},
 | 
					    schedule::{
 | 
				
			||||||
    system::{In, IntoChainSystem, IntoSystem, Local, Res, ResMut, System},
 | 
					        RunCriteriaDescriptor, RunCriteriaDescriptorCoercion, RunCriteriaLabel, ShouldRun,
 | 
				
			||||||
 | 
					        SystemSet,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    system::{In, IntoChainSystem, IntoSystem, Local, Res, ResMut},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					use std::{any::TypeId, fmt::Debug, hash::Hash};
 | 
				
			||||||
use thiserror::Error;
 | 
					use thiserror::Error;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// ### Stack based state machine
 | 
					/// ### Stack based state machine
 | 
				
			||||||
@ -12,7 +16,7 @@ use thiserror::Error;
 | 
				
			|||||||
/// * Pop removes the current state, and unpauses the last paused state.
 | 
					/// * Pop removes the current state, and unpauses the last paused state.
 | 
				
			||||||
/// * Next unwinds the state stack, and replaces the entire stack with a single new state
 | 
					/// * Next unwinds the state stack, and replaces the entire stack with a single new state
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
pub struct State<T: Component + Clone + Eq> {
 | 
					pub struct State<T> {
 | 
				
			||||||
    transition: Option<StateTransition<T>>,
 | 
					    transition: Option<StateTransition<T>>,
 | 
				
			||||||
    stack: Vec<T>,
 | 
					    stack: Vec<T>,
 | 
				
			||||||
    scheduled: Option<ScheduledOperation<T>>,
 | 
					    scheduled: Option<ScheduledOperation<T>>,
 | 
				
			||||||
@ -20,7 +24,7 @@ pub struct State<T: Component + Clone + Eq> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
enum StateTransition<T: Component + Clone + Eq> {
 | 
					enum StateTransition<T> {
 | 
				
			||||||
    PreStartup,
 | 
					    PreStartup,
 | 
				
			||||||
    Startup,
 | 
					    Startup,
 | 
				
			||||||
    // The parameter order is always (leaving, entering)
 | 
					    // The parameter order is always (leaving, entering)
 | 
				
			||||||
@ -32,23 +36,73 @@ enum StateTransition<T: Component + Clone + Eq> {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug)]
 | 
				
			||||||
enum ScheduledOperation<T: Component + Clone + Eq> {
 | 
					enum ScheduledOperation<T> {
 | 
				
			||||||
    Next(T),
 | 
					    Next(T),
 | 
				
			||||||
    Pop,
 | 
					    Pop,
 | 
				
			||||||
    Push(T),
 | 
					    Push(T),
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl<T: Component + Clone + Eq> State<T> {
 | 
					#[derive(Debug, PartialEq, Eq, Clone, Hash)]
 | 
				
			||||||
    pub fn on_update(s: T) -> impl System<In = (), Out = ShouldRun> {
 | 
					enum StateCallback {
 | 
				
			||||||
 | 
					    Update,
 | 
				
			||||||
 | 
					    InactiveUpdate,
 | 
				
			||||||
 | 
					    InStackUpdate,
 | 
				
			||||||
 | 
					    Enter,
 | 
				
			||||||
 | 
					    Exit,
 | 
				
			||||||
 | 
					    Pause,
 | 
				
			||||||
 | 
					    Resume,
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl StateCallback {
 | 
				
			||||||
 | 
					    fn into_label<T>(self, state: T) -> StateRunCriteriaLabel<T>
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        T: Component + Debug + Clone + Eq + Hash,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        StateRunCriteriaLabel(state, self)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, PartialEq, Eq, Clone, Hash)]
 | 
				
			||||||
 | 
					struct StateRunCriteriaLabel<T>(T, StateCallback);
 | 
				
			||||||
 | 
					impl<T> RunCriteriaLabel for StateRunCriteriaLabel<T>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    T: Component + Debug + Clone + Eq + Hash,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    fn dyn_clone(&self) -> Box<dyn RunCriteriaLabel> {
 | 
				
			||||||
 | 
					        Box::new(self.clone())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#[derive(Debug, PartialEq, Eq, Clone, Hash)]
 | 
				
			||||||
 | 
					struct DriverLabel(TypeId);
 | 
				
			||||||
 | 
					impl RunCriteriaLabel for DriverLabel {
 | 
				
			||||||
 | 
					    fn dyn_clone(&self) -> Box<dyn RunCriteriaLabel> {
 | 
				
			||||||
 | 
					        Box::new(self.clone())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl DriverLabel {
 | 
				
			||||||
 | 
					    fn of<T: 'static>() -> Self {
 | 
				
			||||||
 | 
					        Self(TypeId::of::<T>())
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl<T> State<T>
 | 
				
			||||||
 | 
					where
 | 
				
			||||||
 | 
					    T: Component + Debug + Clone + Eq + Hash,
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    pub fn on_update(s: T) -> RunCriteriaDescriptor {
 | 
				
			||||||
        (|state: Res<State<T>>, pred: Local<Option<T>>| {
 | 
					        (|state: Res<State<T>>, pred: Local<Option<T>>| {
 | 
				
			||||||
            state.stack.last().unwrap() == pred.as_ref().unwrap() && state.transition.is_none()
 | 
					            state.stack.last().unwrap() == pred.as_ref().unwrap() && state.transition.is_none()
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .system()
 | 
					        .system()
 | 
				
			||||||
        .config(|(_, pred)| *pred = Some(Some(s)))
 | 
					        .config(|(_, pred)| *pred = Some(Some(s.clone())))
 | 
				
			||||||
        .chain(should_run_adapter::<T>.system())
 | 
					        .chain(should_run_adapter::<T>.system())
 | 
				
			||||||
 | 
					        .after(DriverLabel::of::<T>())
 | 
				
			||||||
 | 
					        .label_discard_if_duplicate(StateCallback::Update.into_label(s))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn on_inactive_update(s: T) -> impl System<In = (), Out = ShouldRun> {
 | 
					    pub fn on_inactive_update(s: T) -> RunCriteriaDescriptor {
 | 
				
			||||||
        (|state: Res<State<T>>, mut is_inactive: Local<bool>, pred: Local<Option<T>>| match &state
 | 
					        (|state: Res<State<T>>, mut is_inactive: Local<bool>, pred: Local<Option<T>>| match &state
 | 
				
			||||||
            .transition
 | 
					            .transition
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@ -63,11 +117,13 @@ impl<T: Component + Clone + Eq> State<T> {
 | 
				
			|||||||
            None => *is_inactive,
 | 
					            None => *is_inactive,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .system()
 | 
					        .system()
 | 
				
			||||||
        .config(|(_, _, pred)| *pred = Some(Some(s)))
 | 
					        .config(|(_, _, pred)| *pred = Some(Some(s.clone())))
 | 
				
			||||||
        .chain(should_run_adapter::<T>.system())
 | 
					        .chain(should_run_adapter::<T>.system())
 | 
				
			||||||
 | 
					        .after(DriverLabel::of::<T>())
 | 
				
			||||||
 | 
					        .label_discard_if_duplicate(StateCallback::InactiveUpdate.into_label(s))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn on_in_stack_update(s: T) -> impl System<In = (), Out = ShouldRun> {
 | 
					    pub fn on_in_stack_update(s: T) -> RunCriteriaDescriptor {
 | 
				
			||||||
        (|state: Res<State<T>>, mut is_in_stack: Local<bool>, pred: Local<Option<T>>| match &state
 | 
					        (|state: Res<State<T>>, mut is_in_stack: Local<bool>, pred: Local<Option<T>>| match &state
 | 
				
			||||||
            .transition
 | 
					            .transition
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@ -94,11 +150,13 @@ impl<T: Component + Clone + Eq> State<T> {
 | 
				
			|||||||
            None => *is_in_stack,
 | 
					            None => *is_in_stack,
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .system()
 | 
					        .system()
 | 
				
			||||||
        .config(|(_, _, pred)| *pred = Some(Some(s)))
 | 
					        .config(|(_, _, pred)| *pred = Some(Some(s.clone())))
 | 
				
			||||||
        .chain(should_run_adapter::<T>.system())
 | 
					        .chain(should_run_adapter::<T>.system())
 | 
				
			||||||
 | 
					        .after(DriverLabel::of::<T>())
 | 
				
			||||||
 | 
					        .label_discard_if_duplicate(StateCallback::InStackUpdate.into_label(s))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn on_enter(s: T) -> impl System<In = (), Out = ShouldRun> {
 | 
					    pub fn on_enter(s: T) -> RunCriteriaDescriptor {
 | 
				
			||||||
        (|state: Res<State<T>>, pred: Local<Option<T>>| {
 | 
					        (|state: Res<State<T>>, pred: Local<Option<T>>| {
 | 
				
			||||||
            state
 | 
					            state
 | 
				
			||||||
                .transition
 | 
					                .transition
 | 
				
			||||||
@ -112,11 +170,13 @@ impl<T: Component + Clone + Eq> State<T> {
 | 
				
			|||||||
                })
 | 
					                })
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .system()
 | 
					        .system()
 | 
				
			||||||
        .config(|(_, pred)| *pred = Some(Some(s)))
 | 
					        .config(|(_, pred)| *pred = Some(Some(s.clone())))
 | 
				
			||||||
        .chain(should_run_adapter::<T>.system())
 | 
					        .chain(should_run_adapter::<T>.system())
 | 
				
			||||||
 | 
					        .after(DriverLabel::of::<T>())
 | 
				
			||||||
 | 
					        .label_discard_if_duplicate(StateCallback::Enter.into_label(s))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn on_exit(s: T) -> impl System<In = (), Out = ShouldRun> {
 | 
					    pub fn on_exit(s: T) -> RunCriteriaDescriptor {
 | 
				
			||||||
        (|state: Res<State<T>>, pred: Local<Option<T>>| {
 | 
					        (|state: Res<State<T>>, pred: Local<Option<T>>| {
 | 
				
			||||||
            state
 | 
					            state
 | 
				
			||||||
                .transition
 | 
					                .transition
 | 
				
			||||||
@ -128,11 +188,13 @@ impl<T: Component + Clone + Eq> State<T> {
 | 
				
			|||||||
                })
 | 
					                })
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .system()
 | 
					        .system()
 | 
				
			||||||
        .config(|(_, pred)| *pred = Some(Some(s)))
 | 
					        .config(|(_, pred)| *pred = Some(Some(s.clone())))
 | 
				
			||||||
        .chain(should_run_adapter::<T>.system())
 | 
					        .chain(should_run_adapter::<T>.system())
 | 
				
			||||||
 | 
					        .after(DriverLabel::of::<T>())
 | 
				
			||||||
 | 
					        .label_discard_if_duplicate(StateCallback::Exit.into_label(s))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn on_pause(s: T) -> impl System<In = (), Out = ShouldRun> {
 | 
					    pub fn on_pause(s: T) -> RunCriteriaDescriptor {
 | 
				
			||||||
        (|state: Res<State<T>>, pred: Local<Option<T>>| {
 | 
					        (|state: Res<State<T>>, pred: Local<Option<T>>| {
 | 
				
			||||||
            state
 | 
					            state
 | 
				
			||||||
                .transition
 | 
					                .transition
 | 
				
			||||||
@ -143,11 +205,13 @@ impl<T: Component + Clone + Eq> State<T> {
 | 
				
			|||||||
                })
 | 
					                })
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .system()
 | 
					        .system()
 | 
				
			||||||
        .config(|(_, pred)| *pred = Some(Some(s)))
 | 
					        .config(|(_, pred)| *pred = Some(Some(s.clone())))
 | 
				
			||||||
        .chain(should_run_adapter::<T>.system())
 | 
					        .chain(should_run_adapter::<T>.system())
 | 
				
			||||||
 | 
					        .after(DriverLabel::of::<T>())
 | 
				
			||||||
 | 
					        .label_discard_if_duplicate(StateCallback::Pause.into_label(s))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn on_resume(s: T) -> impl System<In = (), Out = ShouldRun> {
 | 
					    pub fn on_resume(s: T) -> RunCriteriaDescriptor {
 | 
				
			||||||
        (|state: Res<State<T>>, pred: Local<Option<T>>| {
 | 
					        (|state: Res<State<T>>, pred: Local<Option<T>>| {
 | 
				
			||||||
            state
 | 
					            state
 | 
				
			||||||
                .transition
 | 
					                .transition
 | 
				
			||||||
@ -158,8 +222,10 @@ impl<T: Component + Clone + Eq> State<T> {
 | 
				
			|||||||
                })
 | 
					                })
 | 
				
			||||||
        })
 | 
					        })
 | 
				
			||||||
        .system()
 | 
					        .system()
 | 
				
			||||||
        .config(|(_, pred)| *pred = Some(Some(s)))
 | 
					        .config(|(_, pred)| *pred = Some(Some(s.clone())))
 | 
				
			||||||
        .chain(should_run_adapter::<T>.system())
 | 
					        .chain(should_run_adapter::<T>.system())
 | 
				
			||||||
 | 
					        .after(DriverLabel::of::<T>())
 | 
				
			||||||
 | 
					        .label_discard_if_duplicate(StateCallback::Resume.into_label(s))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn on_update_set(s: T) -> SystemSet {
 | 
					    pub fn on_update_set(s: T) -> SystemSet {
 | 
				
			||||||
@ -191,7 +257,8 @@ impl<T: Component + Clone + Eq> State<T> {
 | 
				
			|||||||
    /// Important note: this set must be inserted **before** all other state-dependant sets to work
 | 
					    /// Important note: this set must be inserted **before** all other state-dependant sets to work
 | 
				
			||||||
    /// properly!
 | 
					    /// properly!
 | 
				
			||||||
    pub fn make_driver() -> SystemSet {
 | 
					    pub fn make_driver() -> SystemSet {
 | 
				
			||||||
        SystemSet::default().with_run_criteria(state_cleaner::<T>.system())
 | 
					        SystemSet::default()
 | 
				
			||||||
 | 
					            .with_run_criteria(state_cleaner::<T>.system().label(DriverLabel::of::<T>()))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn new(initial: T) -> Self {
 | 
					    pub fn new(initial: T) -> Self {
 | 
				
			||||||
@ -390,7 +457,7 @@ mod test {
 | 
				
			|||||||
    use super::*;
 | 
					    use super::*;
 | 
				
			||||||
    use crate::prelude::*;
 | 
					    use crate::prelude::*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    #[derive(Copy, Clone, Eq, PartialEq, Debug)]
 | 
					    #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
 | 
				
			||||||
    enum MyState {
 | 
					    enum MyState {
 | 
				
			||||||
        S1,
 | 
					        S1,
 | 
				
			||||||
        S2,
 | 
					        S2,
 | 
				
			||||||
 | 
				
			|||||||
@ -2,32 +2,33 @@ use crate::{
 | 
				
			|||||||
    component::ComponentId,
 | 
					    component::ComponentId,
 | 
				
			||||||
    query::Access,
 | 
					    query::Access,
 | 
				
			||||||
    schedule::{
 | 
					    schedule::{
 | 
				
			||||||
        BoxedAmbiguitySetLabel, BoxedSystemLabel, ExclusiveSystemDescriptor,
 | 
					        BoxedAmbiguitySetLabel, BoxedRunCriteriaLabel, BoxedSystemLabel, ExclusiveSystemDescriptor,
 | 
				
			||||||
        ParallelSystemDescriptor,
 | 
					        GraphNode, ParallelSystemDescriptor,
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    system::{ExclusiveSystem, System},
 | 
					    system::{ExclusiveSystem, System},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
use std::{borrow::Cow, ptr::NonNull};
 | 
					use std::{borrow::Cow, ptr::NonNull};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// System metadata like its name, labels, order requirements and component access.
 | 
					/// System metadata like its name, labels, order requirements and component access.
 | 
				
			||||||
pub trait SystemContainer {
 | 
					pub trait SystemContainer: GraphNode<BoxedSystemLabel> {
 | 
				
			||||||
    fn name(&self) -> Cow<'static, str>;
 | 
					 | 
				
			||||||
    #[doc(hidden)]
 | 
					    #[doc(hidden)]
 | 
				
			||||||
    fn dependencies(&self) -> &[usize];
 | 
					    fn dependencies(&self) -> &[usize];
 | 
				
			||||||
    #[doc(hidden)]
 | 
					    #[doc(hidden)]
 | 
				
			||||||
    fn set_dependencies(&mut self, dependencies: impl IntoIterator<Item = usize>);
 | 
					    fn set_dependencies(&mut self, dependencies: impl IntoIterator<Item = usize>);
 | 
				
			||||||
    fn system_set(&self) -> usize;
 | 
					    #[doc(hidden)]
 | 
				
			||||||
    fn labels(&self) -> &[BoxedSystemLabel];
 | 
					    fn run_criteria(&self) -> Option<usize>;
 | 
				
			||||||
    fn before(&self) -> &[BoxedSystemLabel];
 | 
					    #[doc(hidden)]
 | 
				
			||||||
    fn after(&self) -> &[BoxedSystemLabel];
 | 
					    fn set_run_criteria(&mut self, index: usize);
 | 
				
			||||||
 | 
					    fn run_criteria_label(&self) -> Option<&BoxedRunCriteriaLabel>;
 | 
				
			||||||
    fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel];
 | 
					    fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel];
 | 
				
			||||||
    fn component_access(&self) -> Option<&Access<ComponentId>>;
 | 
					    fn component_access(&self) -> Option<&Access<ComponentId>>;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub(super) struct ExclusiveSystemContainer {
 | 
					pub(super) struct ExclusiveSystemContainer {
 | 
				
			||||||
    system: Box<dyn ExclusiveSystem>,
 | 
					    system: Box<dyn ExclusiveSystem>,
 | 
				
			||||||
 | 
					    pub(super) run_criteria_index: Option<usize>,
 | 
				
			||||||
 | 
					    pub(super) run_criteria_label: Option<BoxedRunCriteriaLabel>,
 | 
				
			||||||
    dependencies: Vec<usize>,
 | 
					    dependencies: Vec<usize>,
 | 
				
			||||||
    set: usize,
 | 
					 | 
				
			||||||
    labels: Vec<BoxedSystemLabel>,
 | 
					    labels: Vec<BoxedSystemLabel>,
 | 
				
			||||||
    before: Vec<BoxedSystemLabel>,
 | 
					    before: Vec<BoxedSystemLabel>,
 | 
				
			||||||
    after: Vec<BoxedSystemLabel>,
 | 
					    after: Vec<BoxedSystemLabel>,
 | 
				
			||||||
@ -35,11 +36,12 @@ pub(super) struct ExclusiveSystemContainer {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ExclusiveSystemContainer {
 | 
					impl ExclusiveSystemContainer {
 | 
				
			||||||
    pub fn from_descriptor(descriptor: ExclusiveSystemDescriptor, set: usize) -> Self {
 | 
					    pub fn from_descriptor(descriptor: ExclusiveSystemDescriptor) -> Self {
 | 
				
			||||||
        ExclusiveSystemContainer {
 | 
					        ExclusiveSystemContainer {
 | 
				
			||||||
            system: descriptor.system,
 | 
					            system: descriptor.system,
 | 
				
			||||||
 | 
					            run_criteria_index: None,
 | 
				
			||||||
 | 
					            run_criteria_label: None,
 | 
				
			||||||
            dependencies: Vec::new(),
 | 
					            dependencies: Vec::new(),
 | 
				
			||||||
            set,
 | 
					 | 
				
			||||||
            labels: descriptor.labels,
 | 
					            labels: descriptor.labels,
 | 
				
			||||||
            before: descriptor.before,
 | 
					            before: descriptor.before,
 | 
				
			||||||
            after: descriptor.after,
 | 
					            after: descriptor.after,
 | 
				
			||||||
@ -52,24 +54,11 @@ impl ExclusiveSystemContainer {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl SystemContainer for ExclusiveSystemContainer {
 | 
					impl GraphNode<BoxedSystemLabel> for ExclusiveSystemContainer {
 | 
				
			||||||
    fn name(&self) -> Cow<'static, str> {
 | 
					    fn name(&self) -> Cow<'static, str> {
 | 
				
			||||||
        self.system.name()
 | 
					        self.system.name()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn dependencies(&self) -> &[usize] {
 | 
					 | 
				
			||||||
        &self.dependencies
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn set_dependencies(&mut self, dependencies: impl IntoIterator<Item = usize>) {
 | 
					 | 
				
			||||||
        self.dependencies.clear();
 | 
					 | 
				
			||||||
        self.dependencies.extend(dependencies);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn system_set(&self) -> usize {
 | 
					 | 
				
			||||||
        self.set
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn labels(&self) -> &[BoxedSystemLabel] {
 | 
					    fn labels(&self) -> &[BoxedSystemLabel] {
 | 
				
			||||||
        &self.labels
 | 
					        &self.labels
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -81,6 +70,29 @@ impl SystemContainer for ExclusiveSystemContainer {
 | 
				
			|||||||
    fn after(&self) -> &[BoxedSystemLabel] {
 | 
					    fn after(&self) -> &[BoxedSystemLabel] {
 | 
				
			||||||
        &self.after
 | 
					        &self.after
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl SystemContainer for ExclusiveSystemContainer {
 | 
				
			||||||
 | 
					    fn dependencies(&self) -> &[usize] {
 | 
				
			||||||
 | 
					        &self.dependencies
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn set_dependencies(&mut self, dependencies: impl IntoIterator<Item = usize>) {
 | 
				
			||||||
 | 
					        self.dependencies.clear();
 | 
				
			||||||
 | 
					        self.dependencies.extend(dependencies);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn run_criteria(&self) -> Option<usize> {
 | 
				
			||||||
 | 
					        self.run_criteria_index
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn set_run_criteria(&mut self, index: usize) {
 | 
				
			||||||
 | 
					        self.run_criteria_index = Some(index);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn run_criteria_label(&self) -> Option<&BoxedRunCriteriaLabel> {
 | 
				
			||||||
 | 
					        self.run_criteria_label.as_ref()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel] {
 | 
					    fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel] {
 | 
				
			||||||
        &self.ambiguity_sets
 | 
					        &self.ambiguity_sets
 | 
				
			||||||
@ -93,9 +105,10 @@ impl SystemContainer for ExclusiveSystemContainer {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
pub struct ParallelSystemContainer {
 | 
					pub struct ParallelSystemContainer {
 | 
				
			||||||
    system: NonNull<dyn System<In = (), Out = ()>>,
 | 
					    system: NonNull<dyn System<In = (), Out = ()>>,
 | 
				
			||||||
 | 
					    pub(crate) run_criteria_index: Option<usize>,
 | 
				
			||||||
 | 
					    pub(crate) run_criteria_label: Option<BoxedRunCriteriaLabel>,
 | 
				
			||||||
    pub(crate) should_run: bool,
 | 
					    pub(crate) should_run: bool,
 | 
				
			||||||
    dependencies: Vec<usize>,
 | 
					    dependencies: Vec<usize>,
 | 
				
			||||||
    set: usize,
 | 
					 | 
				
			||||||
    labels: Vec<BoxedSystemLabel>,
 | 
					    labels: Vec<BoxedSystemLabel>,
 | 
				
			||||||
    before: Vec<BoxedSystemLabel>,
 | 
					    before: Vec<BoxedSystemLabel>,
 | 
				
			||||||
    after: Vec<BoxedSystemLabel>,
 | 
					    after: Vec<BoxedSystemLabel>,
 | 
				
			||||||
@ -106,11 +119,12 @@ unsafe impl Send for ParallelSystemContainer {}
 | 
				
			|||||||
unsafe impl Sync for ParallelSystemContainer {}
 | 
					unsafe impl Sync for ParallelSystemContainer {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ParallelSystemContainer {
 | 
					impl ParallelSystemContainer {
 | 
				
			||||||
    pub(crate) fn from_descriptor(descriptor: ParallelSystemDescriptor, set: usize) -> Self {
 | 
					    pub(crate) fn from_descriptor(descriptor: ParallelSystemDescriptor) -> Self {
 | 
				
			||||||
        ParallelSystemContainer {
 | 
					        ParallelSystemContainer {
 | 
				
			||||||
            system: unsafe { NonNull::new_unchecked(Box::into_raw(descriptor.system)) },
 | 
					            system: unsafe { NonNull::new_unchecked(Box::into_raw(descriptor.system)) },
 | 
				
			||||||
            should_run: false,
 | 
					            should_run: false,
 | 
				
			||||||
            set,
 | 
					            run_criteria_index: None,
 | 
				
			||||||
 | 
					            run_criteria_label: None,
 | 
				
			||||||
            dependencies: Vec::new(),
 | 
					            dependencies: Vec::new(),
 | 
				
			||||||
            labels: descriptor.labels,
 | 
					            labels: descriptor.labels,
 | 
				
			||||||
            before: descriptor.before,
 | 
					            before: descriptor.before,
 | 
				
			||||||
@ -120,7 +134,7 @@ impl ParallelSystemContainer {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn name(&self) -> Cow<'static, str> {
 | 
					    pub fn name(&self) -> Cow<'static, str> {
 | 
				
			||||||
        SystemContainer::name(self)
 | 
					        GraphNode::name(self)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn system(&self) -> &dyn System<In = (), Out = ()> {
 | 
					    pub fn system(&self) -> &dyn System<In = (), Out = ()> {
 | 
				
			||||||
@ -149,24 +163,11 @@ impl ParallelSystemContainer {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl SystemContainer for ParallelSystemContainer {
 | 
					impl GraphNode<BoxedSystemLabel> for ParallelSystemContainer {
 | 
				
			||||||
    fn name(&self) -> Cow<'static, str> {
 | 
					    fn name(&self) -> Cow<'static, str> {
 | 
				
			||||||
        self.system().name()
 | 
					        self.system().name()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn dependencies(&self) -> &[usize] {
 | 
					 | 
				
			||||||
        &self.dependencies
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn set_dependencies(&mut self, dependencies: impl IntoIterator<Item = usize>) {
 | 
					 | 
				
			||||||
        self.dependencies.clear();
 | 
					 | 
				
			||||||
        self.dependencies.extend(dependencies);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn system_set(&self) -> usize {
 | 
					 | 
				
			||||||
        self.set
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    fn labels(&self) -> &[BoxedSystemLabel] {
 | 
					    fn labels(&self) -> &[BoxedSystemLabel] {
 | 
				
			||||||
        &self.labels
 | 
					        &self.labels
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -178,6 +179,29 @@ impl SystemContainer for ParallelSystemContainer {
 | 
				
			|||||||
    fn after(&self) -> &[BoxedSystemLabel] {
 | 
					    fn after(&self) -> &[BoxedSystemLabel] {
 | 
				
			||||||
        &self.after
 | 
					        &self.after
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl SystemContainer for ParallelSystemContainer {
 | 
				
			||||||
 | 
					    fn dependencies(&self) -> &[usize] {
 | 
				
			||||||
 | 
					        &self.dependencies
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn set_dependencies(&mut self, dependencies: impl IntoIterator<Item = usize>) {
 | 
				
			||||||
 | 
					        self.dependencies.clear();
 | 
				
			||||||
 | 
					        self.dependencies.extend(dependencies);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn run_criteria(&self) -> Option<usize> {
 | 
				
			||||||
 | 
					        self.run_criteria_index
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn set_run_criteria(&mut self, index: usize) {
 | 
				
			||||||
 | 
					        self.run_criteria_index = Some(index);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    fn run_criteria_label(&self) -> Option<&BoxedRunCriteriaLabel> {
 | 
				
			||||||
 | 
					        self.run_criteria_label.as_ref()
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel] {
 | 
					    fn ambiguity_sets(&self) -> &[BoxedAmbiguitySetLabel] {
 | 
				
			||||||
        &self.ambiguity_sets
 | 
					        &self.ambiguity_sets
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,8 @@
 | 
				
			|||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    schedule::{AmbiguitySetLabel, BoxedAmbiguitySetLabel, BoxedSystemLabel, SystemLabel},
 | 
					    schedule::{
 | 
				
			||||||
 | 
					        AmbiguitySetLabel, BoxedAmbiguitySetLabel, BoxedSystemLabel, IntoRunCriteria,
 | 
				
			||||||
 | 
					        RunCriteriaDescriptorOrLabel, SystemLabel,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    system::{BoxedSystem, ExclusiveSystem, ExclusiveSystemCoerced, ExclusiveSystemFn, System},
 | 
					    system::{BoxedSystem, ExclusiveSystem, ExclusiveSystemCoerced, ExclusiveSystemFn, System},
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -77,9 +80,10 @@ impl From<ExclusiveSystemCoerced> for SystemDescriptor {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Encapsulates a parallel system and information on when it run in a `SystemStage`.
 | 
					/// Encapsulates a parallel system and information on when it runs in a `SystemStage`.
 | 
				
			||||||
pub struct ParallelSystemDescriptor {
 | 
					pub struct ParallelSystemDescriptor {
 | 
				
			||||||
    pub(crate) system: BoxedSystem<(), ()>,
 | 
					    pub(crate) system: BoxedSystem<(), ()>,
 | 
				
			||||||
 | 
					    pub(crate) run_criteria: Option<RunCriteriaDescriptorOrLabel>,
 | 
				
			||||||
    pub(crate) labels: Vec<BoxedSystemLabel>,
 | 
					    pub(crate) labels: Vec<BoxedSystemLabel>,
 | 
				
			||||||
    pub(crate) before: Vec<BoxedSystemLabel>,
 | 
					    pub(crate) before: Vec<BoxedSystemLabel>,
 | 
				
			||||||
    pub(crate) after: Vec<BoxedSystemLabel>,
 | 
					    pub(crate) after: Vec<BoxedSystemLabel>,
 | 
				
			||||||
@ -89,6 +93,7 @@ pub struct ParallelSystemDescriptor {
 | 
				
			|||||||
fn new_parallel_descriptor(system: BoxedSystem<(), ()>) -> ParallelSystemDescriptor {
 | 
					fn new_parallel_descriptor(system: BoxedSystem<(), ()>) -> ParallelSystemDescriptor {
 | 
				
			||||||
    ParallelSystemDescriptor {
 | 
					    ParallelSystemDescriptor {
 | 
				
			||||||
        system,
 | 
					        system,
 | 
				
			||||||
 | 
					        run_criteria: None,
 | 
				
			||||||
        labels: Vec::new(),
 | 
					        labels: Vec::new(),
 | 
				
			||||||
        before: Vec::new(),
 | 
					        before: Vec::new(),
 | 
				
			||||||
        after: Vec::new(),
 | 
					        after: Vec::new(),
 | 
				
			||||||
@ -97,10 +102,17 @@ fn new_parallel_descriptor(system: BoxedSystem<(), ()>) -> ParallelSystemDescrip
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait ParallelSystemDescriptorCoercion {
 | 
					pub trait ParallelSystemDescriptorCoercion {
 | 
				
			||||||
 | 
					    /// Assigns a run criteria to the system. Can be a new descriptor or a label of a
 | 
				
			||||||
 | 
					    /// run criteria defined elsewhere.
 | 
				
			||||||
 | 
					    fn with_run_criteria<Marker>(
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        run_criteria: impl IntoRunCriteria<Marker>,
 | 
				
			||||||
 | 
					    ) -> ParallelSystemDescriptor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Assigns a label to the system; there can be more than one, and it doesn't have to be unique.
 | 
					    /// Assigns a label to the system; there can be more than one, and it doesn't have to be unique.
 | 
				
			||||||
    fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor;
 | 
					    fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Specifies that the system should run before systems with the  given label.
 | 
					    /// Specifies that the system should run before systems with the given label.
 | 
				
			||||||
    fn before(self, label: impl SystemLabel) -> ParallelSystemDescriptor;
 | 
					    fn before(self, label: impl SystemLabel) -> ParallelSystemDescriptor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Specifies that the system should run after systems with the given label.
 | 
					    /// Specifies that the system should run after systems with the given label.
 | 
				
			||||||
@ -112,6 +124,14 @@ pub trait ParallelSystemDescriptorCoercion {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ParallelSystemDescriptorCoercion for ParallelSystemDescriptor {
 | 
					impl ParallelSystemDescriptorCoercion for ParallelSystemDescriptor {
 | 
				
			||||||
 | 
					    fn with_run_criteria<Marker>(
 | 
				
			||||||
 | 
					        mut self,
 | 
				
			||||||
 | 
					        run_criteria: impl IntoRunCriteria<Marker>,
 | 
				
			||||||
 | 
					    ) -> ParallelSystemDescriptor {
 | 
				
			||||||
 | 
					        self.run_criteria = Some(run_criteria.into());
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn label(mut self, label: impl SystemLabel) -> ParallelSystemDescriptor {
 | 
					    fn label(mut self, label: impl SystemLabel) -> ParallelSystemDescriptor {
 | 
				
			||||||
        self.labels.push(Box::new(label));
 | 
					        self.labels.push(Box::new(label));
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
@ -137,6 +157,13 @@ impl<S> ParallelSystemDescriptorCoercion for S
 | 
				
			|||||||
where
 | 
					where
 | 
				
			||||||
    S: System<In = (), Out = ()>,
 | 
					    S: System<In = (), Out = ()>,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    fn with_run_criteria<Marker>(
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        run_criteria: impl IntoRunCriteria<Marker>,
 | 
				
			||||||
 | 
					    ) -> ParallelSystemDescriptor {
 | 
				
			||||||
 | 
					        new_parallel_descriptor(Box::new(self)).with_run_criteria(run_criteria)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
 | 
					    fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
 | 
				
			||||||
        new_parallel_descriptor(Box::new(self)).label(label)
 | 
					        new_parallel_descriptor(Box::new(self)).label(label)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -155,6 +182,13 @@ where
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ParallelSystemDescriptorCoercion for BoxedSystem<(), ()> {
 | 
					impl ParallelSystemDescriptorCoercion for BoxedSystem<(), ()> {
 | 
				
			||||||
 | 
					    fn with_run_criteria<Marker>(
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        run_criteria: impl IntoRunCriteria<Marker>,
 | 
				
			||||||
 | 
					    ) -> ParallelSystemDescriptor {
 | 
				
			||||||
 | 
					        new_parallel_descriptor(self).with_run_criteria(run_criteria)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
 | 
					    fn label(self, label: impl SystemLabel) -> ParallelSystemDescriptor {
 | 
				
			||||||
        new_parallel_descriptor(self).label(label)
 | 
					        new_parallel_descriptor(self).label(label)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -179,9 +213,10 @@ pub(crate) enum InsertionPoint {
 | 
				
			|||||||
    AtEnd,
 | 
					    AtEnd,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Encapsulates an exclusive system and information on when it run in a `SystemStage`.
 | 
					/// Encapsulates an exclusive system and information on when it runs in a `SystemStage`.
 | 
				
			||||||
pub struct ExclusiveSystemDescriptor {
 | 
					pub struct ExclusiveSystemDescriptor {
 | 
				
			||||||
    pub(crate) system: Box<dyn ExclusiveSystem>,
 | 
					    pub(crate) system: Box<dyn ExclusiveSystem>,
 | 
				
			||||||
 | 
					    pub(crate) run_criteria: Option<RunCriteriaDescriptorOrLabel>,
 | 
				
			||||||
    pub(crate) labels: Vec<BoxedSystemLabel>,
 | 
					    pub(crate) labels: Vec<BoxedSystemLabel>,
 | 
				
			||||||
    pub(crate) before: Vec<BoxedSystemLabel>,
 | 
					    pub(crate) before: Vec<BoxedSystemLabel>,
 | 
				
			||||||
    pub(crate) after: Vec<BoxedSystemLabel>,
 | 
					    pub(crate) after: Vec<BoxedSystemLabel>,
 | 
				
			||||||
@ -192,6 +227,7 @@ pub struct ExclusiveSystemDescriptor {
 | 
				
			|||||||
fn new_exclusive_descriptor(system: Box<dyn ExclusiveSystem>) -> ExclusiveSystemDescriptor {
 | 
					fn new_exclusive_descriptor(system: Box<dyn ExclusiveSystem>) -> ExclusiveSystemDescriptor {
 | 
				
			||||||
    ExclusiveSystemDescriptor {
 | 
					    ExclusiveSystemDescriptor {
 | 
				
			||||||
        system,
 | 
					        system,
 | 
				
			||||||
 | 
					        run_criteria: None,
 | 
				
			||||||
        labels: Vec::new(),
 | 
					        labels: Vec::new(),
 | 
				
			||||||
        before: Vec::new(),
 | 
					        before: Vec::new(),
 | 
				
			||||||
        after: Vec::new(),
 | 
					        after: Vec::new(),
 | 
				
			||||||
@ -201,6 +237,13 @@ fn new_exclusive_descriptor(system: Box<dyn ExclusiveSystem>) -> ExclusiveSystem
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub trait ExclusiveSystemDescriptorCoercion {
 | 
					pub trait ExclusiveSystemDescriptorCoercion {
 | 
				
			||||||
 | 
					    /// Assigns a run criteria to the system. Can be a new descriptor or a label of a
 | 
				
			||||||
 | 
					    /// run criteria defined elsewhere.
 | 
				
			||||||
 | 
					    fn with_run_criteria<Marker>(
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        run_criteria: impl IntoRunCriteria<Marker>,
 | 
				
			||||||
 | 
					    ) -> ExclusiveSystemDescriptor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Assigns a label to the system; there can be more than one, and it doesn't have to be unique.
 | 
					    /// Assigns a label to the system; there can be more than one, and it doesn't have to be unique.
 | 
				
			||||||
    fn label(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor;
 | 
					    fn label(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -226,6 +269,14 @@ pub trait ExclusiveSystemDescriptorCoercion {
 | 
				
			|||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl ExclusiveSystemDescriptorCoercion for ExclusiveSystemDescriptor {
 | 
					impl ExclusiveSystemDescriptorCoercion for ExclusiveSystemDescriptor {
 | 
				
			||||||
 | 
					    fn with_run_criteria<Marker>(
 | 
				
			||||||
 | 
					        mut self,
 | 
				
			||||||
 | 
					        run_criteria: impl IntoRunCriteria<Marker>,
 | 
				
			||||||
 | 
					    ) -> ExclusiveSystemDescriptor {
 | 
				
			||||||
 | 
					        self.run_criteria = Some(run_criteria.into());
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn label(mut self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
 | 
					    fn label(mut self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
 | 
				
			||||||
        self.labels.push(Box::new(label));
 | 
					        self.labels.push(Box::new(label));
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
@ -266,6 +317,13 @@ impl<T> ExclusiveSystemDescriptorCoercion for T
 | 
				
			|||||||
where
 | 
					where
 | 
				
			||||||
    T: ExclusiveSystem + 'static,
 | 
					    T: ExclusiveSystem + 'static,
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    fn with_run_criteria<Marker>(
 | 
				
			||||||
 | 
					        self,
 | 
				
			||||||
 | 
					        run_criteria: impl IntoRunCriteria<Marker>,
 | 
				
			||||||
 | 
					    ) -> ExclusiveSystemDescriptor {
 | 
				
			||||||
 | 
					        new_exclusive_descriptor(Box::new(self)).with_run_criteria(run_criteria)
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    fn label(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
 | 
					    fn label(self, label: impl SystemLabel) -> ExclusiveSystemDescriptor {
 | 
				
			||||||
        new_exclusive_descriptor(Box::new(self)).label(label)
 | 
					        new_exclusive_descriptor(Box::new(self)).label(label)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,20 +1,31 @@
 | 
				
			|||||||
use crate::{
 | 
					use crate::{
 | 
				
			||||||
    component::Component,
 | 
					    component::Component,
 | 
				
			||||||
    schedule::{RunCriteria, ShouldRun, State, SystemDescriptor},
 | 
					    schedule::{
 | 
				
			||||||
    system::System,
 | 
					        AmbiguitySetLabel, BoxedAmbiguitySetLabel, BoxedSystemLabel, IntoRunCriteria,
 | 
				
			||||||
 | 
					        RunCriteriaDescriptorOrLabel, State, SystemDescriptor, SystemLabel,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					use std::{fmt::Debug, hash::Hash};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Describes a group of systems sharing one run criterion.
 | 
					/// A builder for describing several systems at the same time.
 | 
				
			||||||
pub struct SystemSet {
 | 
					pub struct SystemSet {
 | 
				
			||||||
    pub(crate) run_criteria: RunCriteria,
 | 
					    pub(crate) systems: Vec<SystemDescriptor>,
 | 
				
			||||||
    pub(crate) descriptors: Vec<SystemDescriptor>,
 | 
					    pub(crate) run_criteria: Option<RunCriteriaDescriptorOrLabel>,
 | 
				
			||||||
 | 
					    pub(crate) labels: Vec<BoxedSystemLabel>,
 | 
				
			||||||
 | 
					    pub(crate) before: Vec<BoxedSystemLabel>,
 | 
				
			||||||
 | 
					    pub(crate) after: Vec<BoxedSystemLabel>,
 | 
				
			||||||
 | 
					    pub(crate) ambiguity_sets: Vec<BoxedAmbiguitySetLabel>,
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Default for SystemSet {
 | 
					impl Default for SystemSet {
 | 
				
			||||||
    fn default() -> SystemSet {
 | 
					    fn default() -> SystemSet {
 | 
				
			||||||
        SystemSet {
 | 
					        SystemSet {
 | 
				
			||||||
            run_criteria: Default::default(),
 | 
					            systems: Vec::new(),
 | 
				
			||||||
            descriptors: vec![],
 | 
					            run_criteria: None,
 | 
				
			||||||
 | 
					            labels: Vec::new(),
 | 
				
			||||||
 | 
					            before: Vec::new(),
 | 
				
			||||||
 | 
					            after: Vec::new(),
 | 
				
			||||||
 | 
					            ambiguity_sets: Vec::new(),
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -24,50 +35,107 @@ impl SystemSet {
 | 
				
			|||||||
        Default::default()
 | 
					        Default::default()
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn with_run_criteria<S: System<In = (), Out = ShouldRun>>(mut self, system: S) -> Self {
 | 
					    pub fn on_update<T>(s: T) -> SystemSet
 | 
				
			||||||
        self.add_run_criteria(system);
 | 
					    where
 | 
				
			||||||
        self
 | 
					        T: Component + Debug + Clone + Eq + Hash,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Self::new().with_run_criteria(State::<T>::on_update(s))
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn add_run_criteria<S: System<In = (), Out = ShouldRun>>(
 | 
					    pub fn on_inactive_update<T>(s: T) -> SystemSet
 | 
				
			||||||
        &mut self,
 | 
					    where
 | 
				
			||||||
        system: S,
 | 
					        T: Component + Debug + Clone + Eq + Hash,
 | 
				
			||||||
    ) -> &mut Self {
 | 
					    {
 | 
				
			||||||
        self.run_criteria.set(Box::new(system));
 | 
					        Self::new().with_run_criteria(State::<T>::on_inactive_update(s))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn on_enter<T>(s: T) -> SystemSet
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        T: Component + Debug + Clone + Eq + Hash,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Self::new().with_run_criteria(State::<T>::on_enter(s))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn on_exit<T>(s: T) -> SystemSet
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        T: Component + Debug + Clone + Eq + Hash,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Self::new().with_run_criteria(State::<T>::on_exit(s))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn on_pause<T>(s: T) -> SystemSet
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        T: Component + Debug + Clone + Eq + Hash,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Self::new().with_run_criteria(State::<T>::on_pause(s))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn on_resume<T>(s: T) -> SystemSet
 | 
				
			||||||
 | 
					    where
 | 
				
			||||||
 | 
					        T: Component + Debug + Clone + Eq + Hash,
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					        Self::new().with_run_criteria(State::<T>::on_resume(s))
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    pub fn in_ambiguity_set(mut self, set: impl AmbiguitySetLabel) -> Self {
 | 
				
			||||||
 | 
					        self.ambiguity_sets.push(Box::new(set));
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn with_system(mut self, system: impl Into<SystemDescriptor>) -> Self {
 | 
					    pub fn with_system(mut self, system: impl Into<SystemDescriptor>) -> Self {
 | 
				
			||||||
        self.add_system(system);
 | 
					        self.systems.push(system.into());
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn add_system(&mut self, system: impl Into<SystemDescriptor>) -> &mut Self {
 | 
					    pub fn with_run_criteria<Marker>(mut self, run_criteria: impl IntoRunCriteria<Marker>) -> Self {
 | 
				
			||||||
        self.descriptors.push(system.into());
 | 
					        self.run_criteria = Some(run_criteria.into());
 | 
				
			||||||
        self
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn on_update<T: Component + Clone + Eq>(s: T) -> SystemSet {
 | 
					    pub fn label(mut self, label: impl SystemLabel) -> Self {
 | 
				
			||||||
        Self::new().with_run_criteria(State::<T>::on_update(s))
 | 
					        self.labels.push(Box::new(label));
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn on_inactive_update<T: Component + Clone + Eq>(s: T) -> SystemSet {
 | 
					    pub fn before(mut self, label: impl SystemLabel) -> Self {
 | 
				
			||||||
        Self::new().with_run_criteria(State::<T>::on_inactive_update(s))
 | 
					        self.before.push(Box::new(label));
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn on_enter<T: Component + Clone + Eq>(s: T) -> SystemSet {
 | 
					    pub fn after(mut self, label: impl SystemLabel) -> Self {
 | 
				
			||||||
        Self::new().with_run_criteria(State::<T>::on_enter(s))
 | 
					        self.after.push(Box::new(label));
 | 
				
			||||||
 | 
					        self
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    pub fn on_exit<T: Component + Clone + Eq>(s: T) -> SystemSet {
 | 
					    pub(crate) fn bake(self) -> (Option<RunCriteriaDescriptorOrLabel>, Vec<SystemDescriptor>) {
 | 
				
			||||||
        Self::new().with_run_criteria(State::<T>::on_exit(s))
 | 
					        let SystemSet {
 | 
				
			||||||
    }
 | 
					            mut systems,
 | 
				
			||||||
 | 
					            run_criteria,
 | 
				
			||||||
    pub fn on_pause<T: Component + Clone + Eq>(s: T) -> SystemSet {
 | 
					            labels,
 | 
				
			||||||
        Self::new().with_run_criteria(State::<T>::on_pause(s))
 | 
					            before,
 | 
				
			||||||
    }
 | 
					            after,
 | 
				
			||||||
 | 
					            ambiguity_sets,
 | 
				
			||||||
    pub fn on_resume<T: Component + Clone + Eq>(s: T) -> SystemSet {
 | 
					        } = self;
 | 
				
			||||||
        Self::new().with_run_criteria(State::<T>::on_resume(s))
 | 
					        for descriptor in &mut systems {
 | 
				
			||||||
 | 
					            match descriptor {
 | 
				
			||||||
 | 
					                SystemDescriptor::Parallel(descriptor) => {
 | 
				
			||||||
 | 
					                    descriptor.labels.extend(labels.iter().cloned());
 | 
				
			||||||
 | 
					                    descriptor.before.extend(before.iter().cloned());
 | 
				
			||||||
 | 
					                    descriptor.after.extend(after.iter().cloned());
 | 
				
			||||||
 | 
					                    descriptor
 | 
				
			||||||
 | 
					                        .ambiguity_sets
 | 
				
			||||||
 | 
					                        .extend(ambiguity_sets.iter().cloned());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					                SystemDescriptor::Exclusive(descriptor) => {
 | 
				
			||||||
 | 
					                    descriptor.labels.extend(labels.iter().cloned());
 | 
				
			||||||
 | 
					                    descriptor.before.extend(before.iter().cloned());
 | 
				
			||||||
 | 
					                    descriptor.after.extend(after.iter().cloned());
 | 
				
			||||||
 | 
					                    descriptor
 | 
				
			||||||
 | 
					                        .ambiguity_sets
 | 
				
			||||||
 | 
					                        .extend(ambiguity_sets.iter().cloned());
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        (run_criteria, systems)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
				
			|||||||
@ -13,7 +13,7 @@ fn main() {
 | 
				
			|||||||
        .run();
 | 
					        .run();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, PartialEq, Eq)]
 | 
					#[derive(Debug, Clone, PartialEq, Eq, Hash)]
 | 
				
			||||||
enum AppState {
 | 
					enum AppState {
 | 
				
			||||||
    Setup,
 | 
					    Setup,
 | 
				
			||||||
    Finished,
 | 
					    Finished,
 | 
				
			||||||
 | 
				
			|||||||
@ -19,7 +19,7 @@ fn main() {
 | 
				
			|||||||
        .run();
 | 
					        .run();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Eq, PartialEq)]
 | 
					#[derive(Debug, Clone, Eq, PartialEq, Hash)]
 | 
				
			||||||
enum AppState {
 | 
					enum AppState {
 | 
				
			||||||
    Menu,
 | 
					    Menu,
 | 
				
			||||||
    InGame,
 | 
					    InGame,
 | 
				
			||||||
 | 
				
			|||||||
@ -6,7 +6,7 @@ use bevy::{
 | 
				
			|||||||
};
 | 
					};
 | 
				
			||||||
use rand::Rng;
 | 
					use rand::Rng;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Clone, Eq, PartialEq, Debug)]
 | 
					#[derive(Clone, Eq, PartialEq, Debug, Hash)]
 | 
				
			||||||
enum GameState {
 | 
					enum GameState {
 | 
				
			||||||
    Playing,
 | 
					    Playing,
 | 
				
			||||||
    GameOver,
 | 
					    GameOver,
 | 
				
			||||||
 | 
				
			|||||||
@ -27,7 +27,7 @@ fn main() {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
// NOTE: this "state based" approach to multiple windows is a short term workaround.
 | 
					// NOTE: this "state based" approach to multiple windows is a short term workaround.
 | 
				
			||||||
// Future Bevy releases shouldn't require such a strict order of operations.
 | 
					// Future Bevy releases shouldn't require such a strict order of operations.
 | 
				
			||||||
#[derive(Clone, Eq, PartialEq)]
 | 
					#[derive(Debug, Clone, Eq, PartialEq, Hash)]
 | 
				
			||||||
enum AppState {
 | 
					enum AppState {
 | 
				
			||||||
    CreateWindow,
 | 
					    CreateWindow,
 | 
				
			||||||
    Setup,
 | 
					    Setup,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user