pub trait IntoSystem<In, Out, Marker>: Sizedwhere
In: SystemInput,{
type System: System<In = In, Out = Out>;
// Required method
fn into_system(this: Self) -> Self::System;
// Provided methods
fn pipe<B, BIn, BOut, MarkerB>(self, system: B) -> IntoPipeSystem<Self, B>
where Out: 'static,
B: IntoSystem<BIn, BOut, MarkerB>,
BIn: for<'a> SystemInput<Inner<'a> = Out> { ... }
fn map<T, F>(self, f: F) -> IntoAdapterSystem<F, Self>
where F: Send + Sync + 'static + FnMut(Out) -> T { ... }
fn with_input<T>(self, value: T) -> WithInputWrapper<Self::System, T>
where In: for<'i> SystemInput<Inner<'i> = &'i mut T>,
T: Send + Sync + 'static { ... }
fn with_input_from<T>(self) -> WithInputFromWrapper<Self::System, T>
where In: for<'i> SystemInput<Inner<'i> = &'i mut T>,
T: FromWorld + Send + Sync + 'static { ... }
fn system_type_id(&self) -> TypeId { ... }
}Expand description
Conversion trait to turn something into a System.
Use this to get a system from a function. Also note that every system implements this trait as well.
§Usage notes
This trait should only be used as a bound for trait implementations or as an
argument to a function. If a system needs to be returned from a function or
stored somewhere, use System instead of this trait.
§Examples
use bevy_ecs::prelude::*;
fn my_system_function(a_usize_local: Local<usize>) {}
let system = IntoSystem::into_system(my_system_function);Required Associated Types§
Required Methods§
Sourcefn into_system(this: Self) -> Self::System
fn into_system(this: Self) -> Self::System
Turns this value into its corresponding System.
Provided Methods§
Sourcefn pipe<B, BIn, BOut, MarkerB>(self, system: B) -> IntoPipeSystem<Self, B>where
Out: 'static,
B: IntoSystem<BIn, BOut, MarkerB>,
BIn: for<'a> SystemInput<Inner<'a> = Out>,
fn pipe<B, BIn, BOut, MarkerB>(self, system: B) -> IntoPipeSystem<Self, B>where
Out: 'static,
B: IntoSystem<BIn, BOut, MarkerB>,
BIn: for<'a> SystemInput<Inner<'a> = Out>,
Pass the output of this system A into a second system B, creating a new compound system.
The second system must have In<T> as its first parameter,
where T is the return type of the first system.
§System Names
By default, the System::name() of the resulting PipeSystem will be
set to a combination of the names of the inner systems.
This can be changed by calling IntoPipeSystem::with_first_name or
IntoPipeSystem::with_second_name to take the name from one of the inner systems,
or IntoPipeSystem::with_name or IntoPipeSystem::with_name_fn
to set a different name.
Examples found in repository?
9fn main() {
10 App::new()
11 .insert_resource(Message("42".to_string()))
12 .insert_resource(OptionalWarning(Err("Got to rusty?".to_string())))
13 .add_plugins(LogPlugin {
14 level: Level::TRACE,
15 filter: "".to_string(),
16 ..default()
17 })
18 .add_systems(
19 Update,
20 (
21 parse_message_system.pipe(handler_system),
22 data_pipe_system.map(|out| info!("{out}")),
23 parse_message_system.map(|out| debug!("{out:?}")),
24 warning_pipe_system.map(|out| {
25 if let Err(err) = out {
26 error!("{err}");
27 }
28 }),
29 parse_error_message_system.map(|out| {
30 if let Err(err) = out {
31 error!("{err}");
32 }
33 }),
34 parse_message_system.map(drop),
35 ),
36 )
37 .run();
38}More examples
73 fn build(&self, app: &mut App) {
74 app.add_systems(
75 StateTransition,
76 // The internals can generate at most one transition event of specific type per frame.
77 // We take the latest one and clear the queue.
78 last_transition::<S>
79 // We insert the optional event into our schedule runner.
80 .pipe(run_reenter::<S>)
81 // State transitions are handled in three ordered steps, exposed as system sets.
82 // We can add our systems to them, which will run the corresponding schedules when they're evaluated.
83 // These are:
84 // - [`ExitSchedules`] - Ran from leaf-states to root-states,
85 // - [`TransitionSchedules`] - Ran in arbitrary order,
86 // - [`EnterSchedules`] - Ran from root-states to leaf-states.
87 .in_set(EnterSchedules::<S>::default()),
88 )
89 .add_systems(
90 StateTransition,
91 last_transition::<S>
92 .pipe(run_reexit::<S>)
93 .in_set(ExitSchedules::<S>::default()),
94 );
95 }12fn main() {
13 let mut app = App::new();
14 // By default, fallible systems that return an error will respond according to the `Severity`` in the error.
15 // These will typically panic, unless `with_severity` is used to change the severity of the error.
16 //
17 // We can change this by configuring the fallback error handler, which applies to the entire app
18 // (you can also set it for specific `World`s).
19 // Here we are using one of the built-in error handlers.
20 // Bevy provides built-in handlers for `panic`, `error`, `warn`, `info`,
21 // `debug`, `trace` and `ignore`.
22 app.set_error_handler(warn);
23
24 app.add_plugins(DefaultPlugins);
25
26 #[cfg(feature = "mesh_picking")]
27 app.add_plugins(MeshPickingPlugin);
28
29 // Fallible systems can be used the same way as regular systems. The only difference is they
30 // return a `Result<(), BevyError>` instead of a `()` (unit) type. Bevy will handle both
31 // types of systems the same way, except for the error handling.
32 app.add_systems(Startup, setup);
33
34 // Commands can also return `Result`s, which are automatically handled by the fallback error handler
35 // if not explicitly handled by the user.
36 app.add_systems(Startup, failing_commands);
37
38 // Individual systems can also be handled by piping the output result:
39 app.add_systems(
40 PostStartup,
41 failing_system.pipe(|result: In<Result>| {
42 let _ = result.0.inspect_err(|err| info!("captured error: {err}"));
43 }),
44 );
45
46 // Fallible observers are also supported.
47 app.add_observer(fallible_observer);
48
49 // If we run the app, we'll see the following output at startup:
50 //
51 // WARN Encountered an error in system `fallible_systems::failing_system`: Resource not initialized
52 // ERROR fallible_systems::failing_system failed: Resource not initialized
53 // INFO captured error: Resource not initialized
54 app.run();
55}78fn stress_test(num_entities: u32, num_components: u32, num_systems: u32) {
79 let mut rng = ChaCha8Rng::seed_from_u64(42);
80 let mut app = App::default();
81 let world = app.world_mut();
82
83 // register a bunch of components
84 let component_ids: Vec<ComponentId> = (1..=num_components)
85 .map(|i| {
86 world.register_component_with_descriptor(
87 // SAFETY:
88 // * We don't implement a drop function
89 // * u8 is Sync and Send
90 unsafe {
91 ComponentDescriptor::new_with_layout(
92 format!("Component{i}").to_string(),
93 StorageType::Table,
94 Layout::new::<u8>(),
95 None,
96 true, // is mutable
97 false, // has no summary tick
98 ComponentCloneBehavior::Default,
99 None,
100 )
101 },
102 )
103 })
104 .collect();
105
106 // fill the schedule with systems
107 let mut schedule = Schedule::new(Update);
108 for _ in 1..=num_systems {
109 let num_access_components = rng.random_range(1..10);
110 let access_components: Vec<ComponentId> = component_ids
111 .sample(&mut rng, num_access_components)
112 .copied()
113 .collect();
114 let system = (QueryParamBuilder::new(|builder| {
115 for &access_component in &access_components {
116 if rand::random::<bool>() {
117 builder.mut_id(access_component);
118 } else {
119 builder.ref_id(access_component);
120 }
121 }
122 }),)
123 .build_state(world)
124 .build_any_system(base_system);
125 schedule.add_systems((move || access_components.clone()).pipe(system));
126 }
127
128 // spawn a bunch of entities
129 for _ in 1..=num_entities {
130 let num_components = rng.random_range(1..10);
131 let components: Vec<ComponentId> = component_ids
132 .sample(&mut rng, num_components)
133 .copied()
134 .collect();
135
136 let mut entity = world.spawn_empty();
137 // We use `ManuallyDrop` here as we need to avoid dropping the u8's when `values` is dropped
138 // since ownership of the values is passed to the world in `insert_by_ids`.
139 // But we do want to deallocate the memory when values is dropped.
140 let mut values: Vec<ManuallyDrop<u8>> = components
141 .iter()
142 .map(|_id| ManuallyDrop::new(rng.random_range(0..255)))
143 .collect();
144 let ptrs: Vec<OwningPtr> = values
145 .iter_mut()
146 .map(|value| {
147 // SAFETY:
148 // * We don't read/write `values` binding after this and values are `ManuallyDrop`,
149 // so we have the right to drop/move the values
150 unsafe { PtrMut::from(value).promote() }
151 })
152 .collect();
153 // SAFETY:
154 // * component_id's are from the same world
155 // * `values` was initialized above, so references are valid
156 unsafe {
157 entity.insert_by_ids(&components, ptrs.into_iter());
158 }
159 }
160
161 // overwrite Update schedule in the app
162 app.add_schedule(schedule);
163 app.add_plugins(MinimalPlugins)
164 .add_plugins(DiagnosticsPlugin)
165 .add_plugins(LogPlugin::default())
166 .add_plugins(FrameTimeDiagnosticsPlugin::default())
167 .add_plugins(LogDiagnosticsPlugin::filtered(HashSet::from_iter([
168 DiagnosticPath::new("fps"),
169 ])));
170 app.run();
171}Sourcefn map<T, F>(self, f: F) -> IntoAdapterSystem<F, Self>
fn map<T, F>(self, f: F) -> IntoAdapterSystem<F, Self>
Pass the output of this system into the passed function f, creating a new system that
outputs the value returned from the function.
// Ignores the output of a system that may fail.
schedule.add_systems(my_system.map(drop));
fn my_system(res: Res<T>) -> Result<(), Err> {
// ...
}Examples found in repository?
9fn main() {
10 App::new()
11 .insert_resource(Message("42".to_string()))
12 .insert_resource(OptionalWarning(Err("Got to rusty?".to_string())))
13 .add_plugins(LogPlugin {
14 level: Level::TRACE,
15 filter: "".to_string(),
16 ..default()
17 })
18 .add_systems(
19 Update,
20 (
21 parse_message_system.pipe(handler_system),
22 data_pipe_system.map(|out| info!("{out}")),
23 parse_message_system.map(|out| debug!("{out:?}")),
24 warning_pipe_system.map(|out| {
25 if let Err(err) = out {
26 error!("{err}");
27 }
28 }),
29 parse_error_message_system.map(|out| {
30 if let Err(err) = out {
31 error!("{err}");
32 }
33 }),
34 parse_message_system.map(drop),
35 ),
36 )
37 .run();
38}Sourcefn with_input<T>(self, value: T) -> WithInputWrapper<Self::System, T>
fn with_input<T>(self, value: T) -> WithInputWrapper<Self::System, T>
Passes a mutable reference to value as input to the system each run,
turning it into a system that takes no input.
Self can have any SystemInput type that takes a mutable reference
to T, such as InMut.
§Example
fn my_system(InMut(value): InMut<usize>) {
*value += 1;
if *value > 10 {
println!("Value is greater than 10!");
}
}
schedule.add_systems(my_system.with_input(0));Sourcefn with_input_from<T>(self) -> WithInputFromWrapper<Self::System, T>
fn with_input_from<T>(self) -> WithInputFromWrapper<Self::System, T>
Passes a mutable reference to a value of type T created via
FromWorld as input to the system each run, turning it into a system
that takes no input.
Self can have any SystemInput type that takes a mutable reference
to T, such as InMut.
§Example
struct MyData {
value: usize,
}
impl FromWorld for MyData {
fn from_world(world: &mut World) -> Self {
// Fetch from the world the data needed to create `MyData`
}
}
fn my_system(InMut(data): InMut<MyData>) {
data.value += 1;
if data.value > 10 {
println!("Value is greater than 10!");
}
}
schedule.add_systems(my_system.with_input_from::<MyData>());Sourcefn system_type_id(&self) -> TypeId
fn system_type_id(&self) -> TypeId
Get the TypeId of the System produced after calling into_system.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".