Skip to content

Commit

Permalink
Optional .system (#2398)
Browse files Browse the repository at this point in the history
This can be your 6 months post-christmas present.

# Objective

- Make `.system` optional
- yeet
- It's ugly
- Alternative title: `.system` is dead; long live `.system`
- **yeet**

## Solution

- Use a higher ranked lifetime, and some trait magic.

N.B. This PR does not actually remove any `.system`s, except in a couple of examples. Once this is merged we can do that piecemeal across crates, and decide on syntax for labels.
  • Loading branch information
DJMcNab committed Jun 27, 2021
1 parent 1bc34b4 commit c893b99
Show file tree
Hide file tree
Showing 15 changed files with 107 additions and 71 deletions.
17 changes: 10 additions & 7 deletions crates/bevy_app/src/app_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use bevy_ecs::{
component::{Component, ComponentDescriptor},
event::Events,
schedule::{
RunOnce, Schedule, Stage, StageLabel, State, SystemDescriptor, SystemSet, SystemStage,
IntoSystemDescriptor, RunOnce, Schedule, Stage, StageLabel, State, SystemSet, SystemStage,
},
system::{IntoExclusiveSystem, IntoSystem},
world::{FromWorld, World},
Expand Down Expand Up @@ -180,18 +180,18 @@ impl AppBuilder {
/// App::build()
/// .add_system(my_system.system());
/// ```
pub fn add_system(&mut self, system: impl Into<SystemDescriptor>) -> &mut Self {
pub fn add_system<Params>(&mut self, system: impl IntoSystemDescriptor<Params>) -> &mut Self {
self.add_system_to_stage(CoreStage::Update, system)
}

pub fn add_system_set(&mut self, system_set: SystemSet) -> &mut Self {
self.add_system_set_to_stage(CoreStage::Update, system_set)
}

pub fn add_system_to_stage(
pub fn add_system_to_stage<Params>(
&mut self,
stage_label: impl StageLabel,
system: impl Into<SystemDescriptor>,
system: impl IntoSystemDescriptor<Params>,
) -> &mut Self {
self.app.schedule.add_system_to_stage(stage_label, system);
self
Expand Down Expand Up @@ -228,18 +228,21 @@ impl AppBuilder {
/// App::build()
/// .add_startup_system(my_startup_system.system());
/// ```
pub fn add_startup_system(&mut self, system: impl Into<SystemDescriptor>) -> &mut Self {
pub fn add_startup_system<Params>(
&mut self,
system: impl IntoSystemDescriptor<Params>,
) -> &mut Self {
self.add_startup_system_to_stage(StartupStage::Startup, system)
}

pub fn add_startup_system_set(&mut self, system_set: SystemSet) -> &mut Self {
self.add_startup_system_set_to_stage(StartupStage::Startup, system_set)
}

pub fn add_startup_system_to_stage(
pub fn add_startup_system_to_stage<Params>(
&mut self,
stage_label: impl StageLabel,
system: impl Into<SystemDescriptor>,
system: impl IntoSystemDescriptor<Params>,
) -> &mut Self {
self.app
.schedule
Expand Down
8 changes: 4 additions & 4 deletions crates/bevy_ecs/src/schedule/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ impl Schedule {
self
}

pub fn with_system_in_stage(
pub fn with_system_in_stage<Params>(
mut self,
stage_label: impl StageLabel,
system: impl Into<SystemDescriptor>,
system: impl IntoSystemDescriptor<Params>,
) -> Self {
self.add_system_to_stage(stage_label, system);
self
Expand Down Expand Up @@ -141,10 +141,10 @@ impl Schedule {
self
}

pub fn add_system_to_stage(
pub fn add_system_to_stage<Params>(
&mut self,
stage_label: impl StageLabel,
system: impl Into<SystemDescriptor>,
system: impl IntoSystemDescriptor<Params>,
) -> &mut Self {
// Use a function instead of a closure to ensure that it is codegend inside bevy_ecs instead
// of the game. Closures inherit generic parameters from their enclosing function.
Expand Down
10 changes: 6 additions & 4 deletions crates/bevy_ecs/src/schedule/stage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ use downcast_rs::{impl_downcast, Downcast};
use fixedbitset::FixedBitSet;
use std::fmt::Debug;

use super::IntoSystemDescriptor;

pub trait Stage: Downcast + Send + Sync {
/// Runs the stage; this happens once per update.
/// Implementors must initialize all of their state and systems before running the first time.
Expand Down Expand Up @@ -105,7 +107,7 @@ impl SystemStage {
}
}

pub fn single(system: impl Into<SystemDescriptor>) -> Self {
pub fn single<Params>(system: impl IntoSystemDescriptor<Params>) -> Self {
Self::single_threaded().with_system(system)
}

Expand All @@ -131,13 +133,13 @@ impl SystemStage {
self.executor = executor;
}

pub fn with_system(mut self, system: impl Into<SystemDescriptor>) -> Self {
pub fn with_system<Params>(mut self, system: impl IntoSystemDescriptor<Params>) -> Self {
self.add_system(system);
self
}

pub fn add_system(&mut self, system: impl Into<SystemDescriptor>) -> &mut Self {
self.add_system_inner(system.into(), None);
pub fn add_system<Params>(&mut self, system: impl IntoSystemDescriptor<Params>) -> &mut Self {
self.add_system_inner(system.into_descriptor(), None);
self
}

Expand Down
42 changes: 23 additions & 19 deletions crates/bevy_ecs/src/schedule/system_descriptor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,44 +39,48 @@ pub enum SystemDescriptor {
Exclusive(ExclusiveSystemDescriptor),
}

pub trait IntoSystemDescriptor<Params> {
fn into_descriptor(self) -> SystemDescriptor;
}

pub struct SystemLabelMarker;

impl From<ParallelSystemDescriptor> for SystemDescriptor {
fn from(descriptor: ParallelSystemDescriptor) -> Self {
SystemDescriptor::Parallel(descriptor)
impl IntoSystemDescriptor<()> for ParallelSystemDescriptor {
fn into_descriptor(self) -> SystemDescriptor {
SystemDescriptor::Parallel(self)
}
}

impl<S> From<S> for SystemDescriptor
impl<Params, S> IntoSystemDescriptor<Params> for S
where
S: System<In = (), Out = ()>,
S: crate::system::IntoSystem<(), (), Params>,
{
fn from(system: S) -> Self {
new_parallel_descriptor(Box::new(system)).into()
fn into_descriptor(self) -> SystemDescriptor {
new_parallel_descriptor(Box::new(self.system())).into_descriptor()
}
}

impl From<BoxedSystem<(), ()>> for SystemDescriptor {
fn from(system: BoxedSystem<(), ()>) -> Self {
new_parallel_descriptor(system).into()
impl IntoSystemDescriptor<()> for BoxedSystem<(), ()> {
fn into_descriptor(self) -> SystemDescriptor {
new_parallel_descriptor(self).into_descriptor()
}
}

impl From<ExclusiveSystemDescriptor> for SystemDescriptor {
fn from(descriptor: ExclusiveSystemDescriptor) -> Self {
SystemDescriptor::Exclusive(descriptor)
impl IntoSystemDescriptor<()> for ExclusiveSystemDescriptor {
fn into_descriptor(self) -> SystemDescriptor {
SystemDescriptor::Exclusive(self)
}
}

impl From<ExclusiveSystemFn> for SystemDescriptor {
fn from(system: ExclusiveSystemFn) -> Self {
new_exclusive_descriptor(Box::new(system)).into()
impl IntoSystemDescriptor<()> for ExclusiveSystemFn {
fn into_descriptor(self) -> SystemDescriptor {
new_exclusive_descriptor(Box::new(self)).into_descriptor()
}
}

impl From<ExclusiveSystemCoerced> for SystemDescriptor {
fn from(system: ExclusiveSystemCoerced) -> Self {
new_exclusive_descriptor(Box::new(system)).into()
impl IntoSystemDescriptor<()> for ExclusiveSystemCoerced {
fn into_descriptor(self) -> SystemDescriptor {
new_exclusive_descriptor(Box::new(self)).into_descriptor()
}
}

Expand Down
6 changes: 4 additions & 2 deletions crates/bevy_ecs/src/schedule/system_set.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ use crate::{
};
use std::{fmt::Debug, hash::Hash};

use super::IntoSystemDescriptor;

/// A builder for describing several systems at the same time.
pub struct SystemSet {
pub(crate) systems: Vec<SystemDescriptor>,
Expand Down Expand Up @@ -89,8 +91,8 @@ impl SystemSet {
self
}

pub fn with_system(mut self, system: impl Into<SystemDescriptor>) -> Self {
self.systems.push(system.into());
pub fn with_system<Params>(mut self, system: impl IntoSystemDescriptor<Params>) -> Self {
self.systems.push(system.into_descriptor());
self
}

Expand Down
7 changes: 3 additions & 4 deletions crates/bevy_ecs/src/system/exclusive_system.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::{
system::{check_system_change_tick, BoxedSystem, IntoSystem, System, SystemId},
system::{check_system_change_tick, BoxedSystem, IntoSystem, SystemId},
world::World,
};
use std::borrow::Cow;
Expand Down Expand Up @@ -99,10 +99,9 @@ impl ExclusiveSystem for ExclusiveSystemCoerced {
}
}

impl<S, Params, SystemType> IntoExclusiveSystem<(Params, SystemType), ExclusiveSystemCoerced> for S
impl<S, Params> IntoExclusiveSystem<Params, ExclusiveSystemCoerced> for S
where
S: IntoSystem<Params, SystemType>,
SystemType: System<In = (), Out = ()>,
S: IntoSystem<(), (), Params>,
{
fn exclusive_system(self) -> ExclusiveSystemCoerced {
ExclusiveSystemCoerced {
Expand Down
52 changes: 39 additions & 13 deletions crates/bevy_ecs/src/system/function_system.rs
Original file line number Diff line number Diff line change
Expand Up @@ -173,13 +173,20 @@ impl<Param: SystemParam> SystemState<Param> {
///
/// let system = my_system_function.system();
/// ```
pub trait IntoSystem<Params, SystemType: System> {
// This trait has to be generic because we have potentially overlapping impls, in particular
// because Rust thinks a type could impl multiple different `FnMut` combinations
// even though none can currently
pub trait IntoSystem<In, Out, Params> {
type System: System<In = In, Out = Out>;
/// Turns this value into its corresponding [`System`].
fn system(self) -> SystemType;
fn system(self) -> Self::System;
}

pub struct AlreadyWasSystem;

// Systems implicitly implement IntoSystem
impl<Sys: System> IntoSystem<(), Sys> for Sys {
impl<In, Out, Sys: System<In = In, Out = Out>> IntoSystem<In, Out, AlreadyWasSystem> for Sys {
type System = Sys;
fn system(self) -> Sys {
self
}
Expand Down Expand Up @@ -256,16 +263,18 @@ impl<In, Out, Param: SystemParam, Marker, F> FunctionSystem<In, Out, Param, Mark
self
}
}
pub struct IsFunctionSystem;

impl<In, Out, Param, Marker, F> IntoSystem<Param, FunctionSystem<In, Out, Param, Marker, F>> for F
impl<In, Out, Param, Marker, F> IntoSystem<In, Out, (IsFunctionSystem, Param, Marker)> for F
where
In: 'static,
Out: 'static,
Param: SystemParam + 'static,
Marker: 'static,
F: SystemParamFunction<In, Out, Param, Marker> + Send + Sync + 'static,
{
fn system(self) -> FunctionSystem<In, Out, Param, Marker, F> {
type System = FunctionSystem<In, Out, Param, Marker, F>;
fn system(self) -> Self::System {
FunctionSystem {
func: self,
param_state: None,
Expand Down Expand Up @@ -376,30 +385,47 @@ pub trait SystemParamFunction<In, Out, Param: SystemParam, Marker>: Send + Sync
macro_rules! impl_system_function {
($($param: ident),*) => {
#[allow(non_snake_case)]
impl<Out, Func, $($param: SystemParam),*> SystemParamFunction<(), Out, ($($param,)*), ()> for Func
impl<Out, Func: Send + Sync + 'static, $($param: SystemParam),*> SystemParamFunction<(), Out, ($($param,)*), ()> for Func
where
Func:
for <'a> &'a mut Func:
FnMut($($param),*) -> Out +
FnMut($(<<$param as SystemParam>::Fetch as SystemParamFetch>::Item),*) -> Out + Send + Sync + 'static, Out: 'static
FnMut($(<<$param as SystemParam>::Fetch as SystemParamFetch>::Item),*) -> Out, Out: 'static
{
#[inline]
unsafe fn run(&mut self, _input: (), state: &mut <($($param,)*) as SystemParam>::Fetch, system_meta: &SystemMeta, world: &World, change_tick: u32) -> Out {
// Yes, this is strange, but rustc fails to compile this impl
// without using this function.
#[allow(clippy::too_many_arguments)]
fn call_inner<Out, $($param,)*>(
mut f: impl FnMut($($param,)*)->Out,
$($param: $param,)*
)->Out{
f($($param,)*)
}
let ($($param,)*) = <<($($param,)*) as SystemParam>::Fetch as SystemParamFetch>::get_param(state, system_meta, world, change_tick);
self($($param),*)
call_inner(self, $($param),*)
}
}

#[allow(non_snake_case)]
impl<Input, Out, Func, $($param: SystemParam),*> SystemParamFunction<Input, Out, ($($param,)*), InputMarker> for Func
impl<Input, Out, Func: Send + Sync + 'static, $($param: SystemParam),*> SystemParamFunction<Input, Out, ($($param,)*), InputMarker> for Func
where
Func:
for <'a> &'a mut Func:
FnMut(In<Input>, $($param),*) -> Out +
FnMut(In<Input>, $(<<$param as SystemParam>::Fetch as SystemParamFetch>::Item),*) -> Out + Send + Sync + 'static, Out: 'static
FnMut(In<Input>, $(<<$param as SystemParam>::Fetch as SystemParamFetch>::Item),*) -> Out, Out: 'static
{
#[inline]
unsafe fn run(&mut self, input: Input, state: &mut <($($param,)*) as SystemParam>::Fetch, system_meta: &SystemMeta, world: &World, change_tick: u32) -> Out {
#[allow(clippy::too_many_arguments)]
fn call_inner<Input, Out, $($param,)*>(
mut f: impl FnMut(In<Input>, $($param,)*)->Out,
input: In<Input>,
$($param: $param,)*
)->Out{
f(input, $($param,)*)
}
let ($($param,)*) = <<($($param,)*) as SystemParam>::Fetch as SystemParamFetch>::get_param(state, system_meta, world, change_tick);
self(In(input), $($param),*)
call_inner(self, In(input), $($param),*)
}
}
};
Expand Down
10 changes: 5 additions & 5 deletions examples/2d/contributors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ use std::{
fn main() {
App::build()
.add_plugins(DefaultPlugins)
.add_startup_system(setup.system())
.add_system(velocity_system.system())
.add_system(move_system.system())
.add_system(collision_system.system())
.add_system(select_system.system())
.add_startup_system(setup)
.add_system(velocity_system)
.add_system(move_system)
.add_system(collision_system)
.add_system(select_system)
.run();
}

Expand Down
2 changes: 1 addition & 1 deletion examples/2d/many_sprites.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ fn main() {
frustum_culling_enabled: true,
})
.add_plugins(DefaultPlugins)
.add_startup_system(setup.system())
.add_startup_system(setup)
.add_system(tick.system().label("Tick"))
.add_system(move_camera.system().after("Tick"))
.run()
Expand Down
2 changes: 1 addition & 1 deletion examples/2d/mesh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use bevy::{
fn main() {
App::build()
.add_plugins(DefaultPlugins)
.add_startup_system(star.system())
.add_startup_system(star)
.run();
}

Expand Down
2 changes: 1 addition & 1 deletion examples/2d/sprite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use bevy::prelude::*;
fn main() {
App::build()
.add_plugins(DefaultPlugins)
.add_startup_system(setup.system())
.add_startup_system(setup)
.run();
}

Expand Down
2 changes: 1 addition & 1 deletion examples/2d/sprite_flipping.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use bevy::prelude::*;
fn main() {
App::build()
.add_plugins(DefaultPlugins)
.add_startup_system(setup.system())
.add_startup_system(setup)
.run();
}

Expand Down
4 changes: 2 additions & 2 deletions examples/2d/sprite_sheet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ use bevy::prelude::*;
fn main() {
App::build()
.add_plugins(DefaultPlugins)
.add_startup_system(setup.system())
.add_system(animate_sprite_system.system())
.add_startup_system(setup)
.add_system(animate_sprite_system)
.run();
}

Expand Down
Loading

0 comments on commit c893b99

Please sign in to comment.