Skip to main content

IntoSystem

Trait IntoSystem 

Source
pub trait IntoSystem<In, Out, Marker>: Sized
where 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§

Source

type System: System<In = In, Out = Out>

The type of System that this instance converts into.

Required Methods§

Source

fn into_system(this: Self) -> Self::System

Turns this value into its corresponding System.

Provided Methods§

Source

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?
examples/ecs/system_piping.rs (line 21)
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
Hide additional examples
examples/state/custom_transitions.rs (line 80)
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        }
examples/ecs/error_handling.rs (lines 41-43)
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}
examples/stress_tests/many_components.rs (line 125)
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}
Source

fn map<T, F>(self, f: F) -> IntoAdapterSystem<F, Self>
where F: Send + Sync + 'static + FnMut(Out) -> T,

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?
examples/ecs/system_piping.rs (line 22)
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}
Source

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,

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));
Source

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,

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>());
Source

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".

Implementors§

Source§

impl<A, B, N, IA, OA, IB, OB, MA, MB> IntoSystem<IA, OB, (IsPipeSystemMarker, OA, IB, MA, MB)> for IntoPipeSystem<A, B, N>
where IA: SystemInput, A: IntoSystem<IA, OA, MA>, B: IntoSystem<IB, OB, MB>, N: PipeSystemName, IB: for<'a> SystemInput<Inner<'a> = OA>,

Source§

type System = PipeSystem<<A as IntoSystem<IA, OA, MA>>::System, <B as IntoSystem<IB, OB, MB>>::System>

Source§

impl<Func, S, I, O, M> IntoSystem<<Func as Adapt<<S as IntoSystem<I, O, M>>::System>>::In, <Func as Adapt<<S as IntoSystem<I, O, M>>::System>>::Out, (IsAdapterSystemMarker, I, O, M)> for IntoAdapterSystem<Func, S>
where Func: Adapt<<S as IntoSystem<I, O, M>>::System>, I: SystemInput, S: IntoSystem<I, O, M>,

Source§

type System = AdapterSystem<Func, <S as IntoSystem<I, O, M>>::System>

Source§

impl<Marker, In, Out, F> IntoSystem<In, Out, (IsFunctionSystem, Marker)> for F
where Marker: 'static, In: SystemInput + 'static, Out: 'static, F: SystemParamFunction<Marker>, <F as SystemParamFunction<Marker>>::In: FromInput<In>, <F as SystemParamFunction<Marker>>::Out: IntoResult<Out>,

Source§

type System = FunctionSystem<Marker, In, Out, F>

Source§

impl<Marker, In, Out, Func, Builder> IntoSystem<In, Out, (IsBuilderSystem, Marker)> for IntoBuilderSystem<Marker, In, Out, Func, Builder>
where Marker: 'static, In: SystemInput + 'static, Out: 'static, Func: SystemParamFunction<Marker>, <Func as SystemParamFunction<Marker>>::In: FromInput<In>, <Func as SystemParamFunction<Marker>>::Out: IntoResult<Out>, Builder: SystemParamBuilder<<Func as SystemParamFunction<Marker>>::Param> + Send + Sync + 'static,

Source§

type System = BuilderSystem<Marker, In, Out, Func, Builder>

Source§

impl<T> IntoSystem<<T as System>::In, <T as System>::Out, ()> for T
where T: System,