Skip to content

Commit e6c68a5

Browse files
DJMcNabostwilkens
authored andcommitted
Optional .system (bevyengine#2398)
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.
1 parent 4f434d8 commit e6c68a5

15 files changed

+107
-71
lines changed

crates/bevy_app/src/app_builder.rs

+10-7
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use bevy_ecs::{
77
component::{Component, ComponentDescriptor},
88
event::Events,
99
schedule::{
10-
RunOnce, Schedule, Stage, StageLabel, State, SystemDescriptor, SystemSet, SystemStage,
10+
IntoSystemDescriptor, RunOnce, Schedule, Stage, StageLabel, State, SystemSet, SystemStage,
1111
},
1212
system::{IntoExclusiveSystem, IntoSystem},
1313
world::{FromWorld, World},
@@ -180,18 +180,18 @@ impl AppBuilder {
180180
/// App::build()
181181
/// .add_system(my_system.system());
182182
/// ```
183-
pub fn add_system(&mut self, system: impl Into<SystemDescriptor>) -> &mut Self {
183+
pub fn add_system<Params>(&mut self, system: impl IntoSystemDescriptor<Params>) -> &mut Self {
184184
self.add_system_to_stage(CoreStage::Update, system)
185185
}
186186

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

191-
pub fn add_system_to_stage(
191+
pub fn add_system_to_stage<Params>(
192192
&mut self,
193193
stage_label: impl StageLabel,
194-
system: impl Into<SystemDescriptor>,
194+
system: impl IntoSystemDescriptor<Params>,
195195
) -> &mut Self {
196196
self.app.schedule.add_system_to_stage(stage_label, system);
197197
self
@@ -228,18 +228,21 @@ impl AppBuilder {
228228
/// App::build()
229229
/// .add_startup_system(my_startup_system.system());
230230
/// ```
231-
pub fn add_startup_system(&mut self, system: impl Into<SystemDescriptor>) -> &mut Self {
231+
pub fn add_startup_system<Params>(
232+
&mut self,
233+
system: impl IntoSystemDescriptor<Params>,
234+
) -> &mut Self {
232235
self.add_startup_system_to_stage(StartupStage::Startup, system)
233236
}
234237

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

239-
pub fn add_startup_system_to_stage(
242+
pub fn add_startup_system_to_stage<Params>(
240243
&mut self,
241244
stage_label: impl StageLabel,
242-
system: impl Into<SystemDescriptor>,
245+
system: impl IntoSystemDescriptor<Params>,
243246
) -> &mut Self {
244247
self.app
245248
.schedule

crates/bevy_ecs/src/schedule/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -66,10 +66,10 @@ impl Schedule {
6666
self
6767
}
6868

69-
pub fn with_system_in_stage(
69+
pub fn with_system_in_stage<Params>(
7070
mut self,
7171
stage_label: impl StageLabel,
72-
system: impl Into<SystemDescriptor>,
72+
system: impl IntoSystemDescriptor<Params>,
7373
) -> Self {
7474
self.add_system_to_stage(stage_label, system);
7575
self
@@ -141,10 +141,10 @@ impl Schedule {
141141
self
142142
}
143143

144-
pub fn add_system_to_stage(
144+
pub fn add_system_to_stage<Params>(
145145
&mut self,
146146
stage_label: impl StageLabel,
147-
system: impl Into<SystemDescriptor>,
147+
system: impl IntoSystemDescriptor<Params>,
148148
) -> &mut Self {
149149
// Use a function instead of a closure to ensure that it is codegend inside bevy_ecs instead
150150
// of the game. Closures inherit generic parameters from their enclosing function.

crates/bevy_ecs/src/schedule/stage.rs

+6-4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ use downcast_rs::{impl_downcast, Downcast};
1616
use fixedbitset::FixedBitSet;
1717
use std::fmt::Debug;
1818

19+
use super::IntoSystemDescriptor;
20+
1921
pub trait Stage: Downcast + Send + Sync {
2022
/// Runs the stage; this happens once per update.
2123
/// Implementors must initialize all of their state and systems before running the first time.
@@ -105,7 +107,7 @@ impl SystemStage {
105107
}
106108
}
107109

108-
pub fn single(system: impl Into<SystemDescriptor>) -> Self {
110+
pub fn single<Params>(system: impl IntoSystemDescriptor<Params>) -> Self {
109111
Self::single_threaded().with_system(system)
110112
}
111113

@@ -131,13 +133,13 @@ impl SystemStage {
131133
self.executor = executor;
132134
}
133135

134-
pub fn with_system(mut self, system: impl Into<SystemDescriptor>) -> Self {
136+
pub fn with_system<Params>(mut self, system: impl IntoSystemDescriptor<Params>) -> Self {
135137
self.add_system(system);
136138
self
137139
}
138140

139-
pub fn add_system(&mut self, system: impl Into<SystemDescriptor>) -> &mut Self {
140-
self.add_system_inner(system.into(), None);
141+
pub fn add_system<Params>(&mut self, system: impl IntoSystemDescriptor<Params>) -> &mut Self {
142+
self.add_system_inner(system.into_descriptor(), None);
141143
self
142144
}
143145

crates/bevy_ecs/src/schedule/system_descriptor.rs

+23-19
Original file line numberDiff line numberDiff line change
@@ -39,44 +39,48 @@ pub enum SystemDescriptor {
3939
Exclusive(ExclusiveSystemDescriptor),
4040
}
4141

42+
pub trait IntoSystemDescriptor<Params> {
43+
fn into_descriptor(self) -> SystemDescriptor;
44+
}
45+
4246
pub struct SystemLabelMarker;
4347

44-
impl From<ParallelSystemDescriptor> for SystemDescriptor {
45-
fn from(descriptor: ParallelSystemDescriptor) -> Self {
46-
SystemDescriptor::Parallel(descriptor)
48+
impl IntoSystemDescriptor<()> for ParallelSystemDescriptor {
49+
fn into_descriptor(self) -> SystemDescriptor {
50+
SystemDescriptor::Parallel(self)
4751
}
4852
}
4953

50-
impl<S> From<S> for SystemDescriptor
54+
impl<Params, S> IntoSystemDescriptor<Params> for S
5155
where
52-
S: System<In = (), Out = ()>,
56+
S: crate::system::IntoSystem<(), (), Params>,
5357
{
54-
fn from(system: S) -> Self {
55-
new_parallel_descriptor(Box::new(system)).into()
58+
fn into_descriptor(self) -> SystemDescriptor {
59+
new_parallel_descriptor(Box::new(self.system())).into_descriptor()
5660
}
5761
}
5862

59-
impl From<BoxedSystem<(), ()>> for SystemDescriptor {
60-
fn from(system: BoxedSystem<(), ()>) -> Self {
61-
new_parallel_descriptor(system).into()
63+
impl IntoSystemDescriptor<()> for BoxedSystem<(), ()> {
64+
fn into_descriptor(self) -> SystemDescriptor {
65+
new_parallel_descriptor(self).into_descriptor()
6266
}
6367
}
6468

65-
impl From<ExclusiveSystemDescriptor> for SystemDescriptor {
66-
fn from(descriptor: ExclusiveSystemDescriptor) -> Self {
67-
SystemDescriptor::Exclusive(descriptor)
69+
impl IntoSystemDescriptor<()> for ExclusiveSystemDescriptor {
70+
fn into_descriptor(self) -> SystemDescriptor {
71+
SystemDescriptor::Exclusive(self)
6872
}
6973
}
7074

71-
impl From<ExclusiveSystemFn> for SystemDescriptor {
72-
fn from(system: ExclusiveSystemFn) -> Self {
73-
new_exclusive_descriptor(Box::new(system)).into()
75+
impl IntoSystemDescriptor<()> for ExclusiveSystemFn {
76+
fn into_descriptor(self) -> SystemDescriptor {
77+
new_exclusive_descriptor(Box::new(self)).into_descriptor()
7478
}
7579
}
7680

77-
impl From<ExclusiveSystemCoerced> for SystemDescriptor {
78-
fn from(system: ExclusiveSystemCoerced) -> Self {
79-
new_exclusive_descriptor(Box::new(system)).into()
81+
impl IntoSystemDescriptor<()> for ExclusiveSystemCoerced {
82+
fn into_descriptor(self) -> SystemDescriptor {
83+
new_exclusive_descriptor(Box::new(self)).into_descriptor()
8084
}
8185
}
8286

crates/bevy_ecs/src/schedule/system_set.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ use crate::{
77
};
88
use std::{fmt::Debug, hash::Hash};
99

10+
use super::IntoSystemDescriptor;
11+
1012
/// A builder for describing several systems at the same time.
1113
pub struct SystemSet {
1214
pub(crate) systems: Vec<SystemDescriptor>,
@@ -89,8 +91,8 @@ impl SystemSet {
8991
self
9092
}
9193

92-
pub fn with_system(mut self, system: impl Into<SystemDescriptor>) -> Self {
93-
self.systems.push(system.into());
94+
pub fn with_system<Params>(mut self, system: impl IntoSystemDescriptor<Params>) -> Self {
95+
self.systems.push(system.into_descriptor());
9496
self
9597
}
9698

crates/bevy_ecs/src/system/exclusive_system.rs

+3-4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
use crate::{
2-
system::{check_system_change_tick, BoxedSystem, IntoSystem, System, SystemId},
2+
system::{check_system_change_tick, BoxedSystem, IntoSystem, SystemId},
33
world::World,
44
};
55
use std::borrow::Cow;
@@ -99,10 +99,9 @@ impl ExclusiveSystem for ExclusiveSystemCoerced {
9999
}
100100
}
101101

102-
impl<S, Params, SystemType> IntoExclusiveSystem<(Params, SystemType), ExclusiveSystemCoerced> for S
102+
impl<S, Params> IntoExclusiveSystem<Params, ExclusiveSystemCoerced> for S
103103
where
104-
S: IntoSystem<Params, SystemType>,
105-
SystemType: System<In = (), Out = ()>,
104+
S: IntoSystem<(), (), Params>,
106105
{
107106
fn exclusive_system(self) -> ExclusiveSystemCoerced {
108107
ExclusiveSystemCoerced {

crates/bevy_ecs/src/system/function_system.rs

+39-13
Original file line numberDiff line numberDiff line change
@@ -173,13 +173,20 @@ impl<Param: SystemParam> SystemState<Param> {
173173
///
174174
/// let system = my_system_function.system();
175175
/// ```
176-
pub trait IntoSystem<Params, SystemType: System> {
176+
// This trait has to be generic because we have potentially overlapping impls, in particular
177+
// because Rust thinks a type could impl multiple different `FnMut` combinations
178+
// even though none can currently
179+
pub trait IntoSystem<In, Out, Params> {
180+
type System: System<In = In, Out = Out>;
177181
/// Turns this value into its corresponding [`System`].
178-
fn system(self) -> SystemType;
182+
fn system(self) -> Self::System;
179183
}
180184

185+
pub struct AlreadyWasSystem;
186+
181187
// Systems implicitly implement IntoSystem
182-
impl<Sys: System> IntoSystem<(), Sys> for Sys {
188+
impl<In, Out, Sys: System<In = In, Out = Out>> IntoSystem<In, Out, AlreadyWasSystem> for Sys {
189+
type System = Sys;
183190
fn system(self) -> Sys {
184191
self
185192
}
@@ -256,16 +263,18 @@ impl<In, Out, Param: SystemParam, Marker, F> FunctionSystem<In, Out, Param, Mark
256263
self
257264
}
258265
}
266+
pub struct IsFunctionSystem;
259267

260-
impl<In, Out, Param, Marker, F> IntoSystem<Param, FunctionSystem<In, Out, Param, Marker, F>> for F
268+
impl<In, Out, Param, Marker, F> IntoSystem<In, Out, (IsFunctionSystem, Param, Marker)> for F
261269
where
262270
In: 'static,
263271
Out: 'static,
264272
Param: SystemParam + 'static,
265273
Marker: 'static,
266274
F: SystemParamFunction<In, Out, Param, Marker> + Send + Sync + 'static,
267275
{
268-
fn system(self) -> FunctionSystem<In, Out, Param, Marker, F> {
276+
type System = FunctionSystem<In, Out, Param, Marker, F>;
277+
fn system(self) -> Self::System {
269278
FunctionSystem {
270279
func: self,
271280
param_state: None,
@@ -376,30 +385,47 @@ pub trait SystemParamFunction<In, Out, Param: SystemParam, Marker>: Send + Sync
376385
macro_rules! impl_system_function {
377386
($($param: ident),*) => {
378387
#[allow(non_snake_case)]
379-
impl<Out, Func, $($param: SystemParam),*> SystemParamFunction<(), Out, ($($param,)*), ()> for Func
388+
impl<Out, Func: Send + Sync + 'static, $($param: SystemParam),*> SystemParamFunction<(), Out, ($($param,)*), ()> for Func
380389
where
381-
Func:
390+
for <'a> &'a mut Func:
382391
FnMut($($param),*) -> Out +
383-
FnMut($(<<$param as SystemParam>::Fetch as SystemParamFetch>::Item),*) -> Out + Send + Sync + 'static, Out: 'static
392+
FnMut($(<<$param as SystemParam>::Fetch as SystemParamFetch>::Item),*) -> Out, Out: 'static
384393
{
385394
#[inline]
386395
unsafe fn run(&mut self, _input: (), state: &mut <($($param,)*) as SystemParam>::Fetch, system_meta: &SystemMeta, world: &World, change_tick: u32) -> Out {
396+
// Yes, this is strange, but rustc fails to compile this impl
397+
// without using this function.
398+
#[allow(clippy::too_many_arguments)]
399+
fn call_inner<Out, $($param,)*>(
400+
mut f: impl FnMut($($param,)*)->Out,
401+
$($param: $param,)*
402+
)->Out{
403+
f($($param,)*)
404+
}
387405
let ($($param,)*) = <<($($param,)*) as SystemParam>::Fetch as SystemParamFetch>::get_param(state, system_meta, world, change_tick);
388-
self($($param),*)
406+
call_inner(self, $($param),*)
389407
}
390408
}
391409

392410
#[allow(non_snake_case)]
393-
impl<Input, Out, Func, $($param: SystemParam),*> SystemParamFunction<Input, Out, ($($param,)*), InputMarker> for Func
411+
impl<Input, Out, Func: Send + Sync + 'static, $($param: SystemParam),*> SystemParamFunction<Input, Out, ($($param,)*), InputMarker> for Func
394412
where
395-
Func:
413+
for <'a> &'a mut Func:
396414
FnMut(In<Input>, $($param),*) -> Out +
397-
FnMut(In<Input>, $(<<$param as SystemParam>::Fetch as SystemParamFetch>::Item),*) -> Out + Send + Sync + 'static, Out: 'static
415+
FnMut(In<Input>, $(<<$param as SystemParam>::Fetch as SystemParamFetch>::Item),*) -> Out, Out: 'static
398416
{
399417
#[inline]
400418
unsafe fn run(&mut self, input: Input, state: &mut <($($param,)*) as SystemParam>::Fetch, system_meta: &SystemMeta, world: &World, change_tick: u32) -> Out {
419+
#[allow(clippy::too_many_arguments)]
420+
fn call_inner<Input, Out, $($param,)*>(
421+
mut f: impl FnMut(In<Input>, $($param,)*)->Out,
422+
input: In<Input>,
423+
$($param: $param,)*
424+
)->Out{
425+
f(input, $($param,)*)
426+
}
401427
let ($($param,)*) = <<($($param,)*) as SystemParam>::Fetch as SystemParamFetch>::get_param(state, system_meta, world, change_tick);
402-
self(In(input), $($param),*)
428+
call_inner(self, In(input), $($param),*)
403429
}
404430
}
405431
};

examples/2d/contributors.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ use std::{
99
fn main() {
1010
App::build()
1111
.add_plugins(DefaultPlugins)
12-
.add_startup_system(setup.system())
13-
.add_system(velocity_system.system())
14-
.add_system(move_system.system())
15-
.add_system(collision_system.system())
16-
.add_system(select_system.system())
12+
.add_startup_system(setup)
13+
.add_system(velocity_system)
14+
.add_system(move_system)
15+
.add_system(collision_system)
16+
.add_system(select_system)
1717
.run();
1818
}
1919

examples/2d/many_sprites.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ fn main() {
2323
frustum_culling_enabled: true,
2424
})
2525
.add_plugins(DefaultPlugins)
26-
.add_startup_system(setup.system())
26+
.add_startup_system(setup)
2727
.add_system(tick.system().label("Tick"))
2828
.add_system(move_camera.system().after("Tick"))
2929
.run()

examples/2d/mesh.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use bevy::{
99
fn main() {
1010
App::build()
1111
.add_plugins(DefaultPlugins)
12-
.add_startup_system(star.system())
12+
.add_startup_system(star)
1313
.run();
1414
}
1515

examples/2d/sprite.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use bevy::prelude::*;
33
fn main() {
44
App::build()
55
.add_plugins(DefaultPlugins)
6-
.add_startup_system(setup.system())
6+
.add_startup_system(setup)
77
.run();
88
}
99

examples/2d/sprite_flipping.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use bevy::prelude::*;
33
fn main() {
44
App::build()
55
.add_plugins(DefaultPlugins)
6-
.add_startup_system(setup.system())
6+
.add_startup_system(setup)
77
.run();
88
}
99

examples/2d/sprite_sheet.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ use bevy::prelude::*;
33
fn main() {
44
App::build()
55
.add_plugins(DefaultPlugins)
6-
.add_startup_system(setup.system())
7-
.add_system(animate_sprite_system.system())
6+
.add_startup_system(setup)
7+
.add_system(animate_sprite_system)
88
.run();
99
}
1010

0 commit comments

Comments
 (0)