Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Merged by Bors] - Rename system chaining to system piping #6230

Closed
wants to merge 11 commits into from
10 changes: 5 additions & 5 deletions Cargo.toml
Expand Up @@ -872,12 +872,12 @@ category = "ECS (Entity Component System)"
wasm = false

[[example]]
name = "system_chaining"
path = "examples/ecs/system_chaining.rs"
name = "system_piping"
path = "examples/ecs/system_piping.rs"

[package.metadata.example.system_chaining]
name = "System Chaining"
description = "Chain two systems together, specifying a return type in a system (such as `Result`)"
[package.metadata.example.system_piping]
name = "System Piping"
description = "Pipe the output of one system into a second, allowing you to handle any errors gracefully"
category = "ECS (Entity Component System)"
wasm = false

Expand Down
2 changes: 1 addition & 1 deletion crates/bevy_ecs/src/lib.rs
Expand Up @@ -38,7 +38,7 @@ pub mod prelude {
Schedule, Stage, StageLabel, State, SystemLabel, SystemSet, SystemStage,
},
system::{
adapter as system_adapter, Commands, In, IntoChainSystem, IntoSystem, Local, NonSend,
adapter as system_adapter, Commands, In, IntoPipeSystem, IntoSystem, Local, NonSend,
NonSendMut, ParallelCommands, ParamSet, Query, RemovedComponents, Res, ResMut,
Resource, System, SystemParamFunction,
},
Expand Down
16 changes: 8 additions & 8 deletions crates/bevy_ecs/src/schedule/state.rs
Expand Up @@ -3,7 +3,7 @@ use crate::{
RunCriteriaDescriptor, RunCriteriaDescriptorCoercion, RunCriteriaLabel, ShouldRun,
SystemSet,
},
system::{In, IntoChainSystem, Local, Res, ResMut, Resource},
system::{In, IntoPipeSystem, Local, Res, ResMut, Resource},
};
use std::{
any::TypeId,
Expand Down Expand Up @@ -79,7 +79,7 @@ where
(move |state: Res<State<T>>| {
state.stack.last().unwrap() == &pred && state.transition.is_none()
})
.chain(should_run_adapter::<T>)
.pipe(should_run_adapter::<T>)
.after(DriverLabel::of::<T>())
}

Expand All @@ -95,7 +95,7 @@ where
Some(_) => false,
None => *is_inactive,
})
.chain(should_run_adapter::<T>)
.pipe(should_run_adapter::<T>)
.after(DriverLabel::of::<T>())
}

Expand All @@ -118,7 +118,7 @@ where
Some(_) => false,
None => *is_in_stack,
})
.chain(should_run_adapter::<T>)
.pipe(should_run_adapter::<T>)
.after(DriverLabel::of::<T>())
}

Expand All @@ -133,7 +133,7 @@ where
_ => false,
})
})
.chain(should_run_adapter::<T>)
.pipe(should_run_adapter::<T>)
.after(DriverLabel::of::<T>())
}

Expand All @@ -148,7 +148,7 @@ where
_ => false,
})
})
.chain(should_run_adapter::<T>)
.pipe(should_run_adapter::<T>)
.after(DriverLabel::of::<T>())
}

Expand All @@ -162,7 +162,7 @@ where
_ => false,
})
})
.chain(should_run_adapter::<T>)
.pipe(should_run_adapter::<T>)
.after(DriverLabel::of::<T>())
}

Expand All @@ -176,7 +176,7 @@ where
_ => false,
})
})
.chain(should_run_adapter::<T>)
.pipe(should_run_adapter::<T>)
.after(DriverLabel::of::<T>())
}

Expand Down
18 changes: 9 additions & 9 deletions crates/bevy_ecs/src/system/function_system.rs
Expand Up @@ -499,7 +499,7 @@ impl<T> Copy for SystemTypeIdLabel<T> {}
///
/// # Example
///
/// To create something like [`ChainSystem`], but in entirely safe code.
/// To create something like [`PipeSystem`], but in entirely safe code.
///
/// ```rust
/// use std::num::ParseIntError;
Expand All @@ -510,8 +510,8 @@ impl<T> Copy for SystemTypeIdLabel<T> {}
/// // Unfortunately, we need all of these generics. `A` is the first system, with its
/// // parameters and marker type required for coherence. `B` is the second system, and
/// // the other generics are for the input/output types of `A` and `B`.
/// /// Chain creates a new system which calls `a`, then calls `b` with the output of `a`
/// pub fn chain<AIn, Shared, BOut, A, AParam, AMarker, B, BParam, BMarker>(
/// /// Pipe creates a new system which calls `a`, then calls `b` with the output of `a`
/// pub fn pipe<AIn, Shared, BOut, A, AParam, AMarker, B, BParam, BMarker>(
/// mut a: A,
/// mut b: B,
/// ) -> impl FnMut(In<AIn>, ParamSet<(SystemParamItem<AParam>, SystemParamItem<BParam>)>) -> BOut
Expand All @@ -529,15 +529,15 @@ impl<T> Copy for SystemTypeIdLabel<T> {}
/// }
/// }
///
/// // Usage example for `chain`:
/// // Usage example for `pipe`:
/// fn main() {
/// let mut world = World::default();
/// world.insert_resource(Message("42".to_string()));
///
/// // chain the `parse_message_system`'s output into the `filter_system`s input
/// let mut chained_system = IntoSystem::into_system(chain(parse_message, filter));
/// chained_system.initialize(&mut world);
/// assert_eq!(chained_system.run((), &mut world), Some(42));
/// // pipe the `parse_message_system`'s output into the `filter_system`s input
/// let mut piped_system = IntoSystem::into_system(pipe(parse_message, filter));
/// piped_system.initialize(&mut world);
/// assert_eq!(piped_system.run((), &mut world), Some(42));
/// }
///
/// #[derive(Resource)]
Expand All @@ -551,7 +551,7 @@ impl<T> Copy for SystemTypeIdLabel<T> {}
/// result.ok().filter(|&n| n < 100)
/// }
/// ```
/// [`ChainSystem`]: crate::system::ChainSystem
/// [`PipeSystem`]: crate::system::PipeSystem
/// [`ParamSet`]: crate::system::ParamSet
pub trait SystemParamFunction<In, Out, Param: SystemParam, Marker>: Send + Sync + 'static {
fn run(&mut self, input: In, param_value: SystemParamItem<Param>) -> Out;
Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_ecs/src/system/mod.rs
Expand Up @@ -75,17 +75,17 @@ mod function_system;
mod query;
#[allow(clippy::module_inception)]
mod system;
mod system_chaining;
mod system_param;
mod system_piping;

pub use commands::*;
pub use exclusive_function_system::*;
pub use exclusive_system_param::*;
pub use function_system::*;
pub use query::*;
pub use system::*;
pub use system_chaining::*;
pub use system_param::*;
pub use system_piping::*;

/// Ensure that a given function is a system
///
Expand Down
Expand Up @@ -7,10 +7,11 @@ use crate::{
};
use std::borrow::Cow;

/// A [`System`] that chains two systems together, creating a new system that routes the output of
/// the first system into the input of the second system, yielding the output of the second system.
/// A [`System`] created by piping the output of the first system into the input of the second.
///
/// Given two systems `A` and `B`, A may be chained with `B` as `A.chain(B)` if the output type of `A` is
/// This can be repeated indefinitely, but system pipes cannot branch: the output is consumed by the receiving system.
///
/// Given two systems `A` and `B`, A may be piped into `B` as `A.pipe(B)` if the output type of `A` is
/// equal to the input type of `B`.
///
/// Note that for [`FunctionSystem`](crate::system::FunctionSystem)s the output is the return value
Expand All @@ -28,10 +29,10 @@ use std::borrow::Cow;
/// let mut world = World::default();
/// world.insert_resource(Message("42".to_string()));
///
/// // chain the `parse_message_system`'s output into the `filter_system`s input
/// let mut chained_system = parse_message_system.chain(filter_system);
/// chained_system.initialize(&mut world);
/// assert_eq!(chained_system.run((), &mut world), Some(42));
/// // pipe the `parse_message_system`'s output into the `filter_system`s input
/// let mut piped_system = parse_message_system.pipe(filter_system);
/// piped_system.initialize(&mut world);
/// assert_eq!(piped_system.run((), &mut world), Some(42));
/// }
///
/// #[derive(Resource)]
Expand All @@ -45,15 +46,15 @@ use std::borrow::Cow;
/// result.ok().filter(|&n| n < 100)
/// }
/// ```
pub struct ChainSystem<SystemA, SystemB> {
pub struct PipeSystem<SystemA, SystemB> {
system_a: SystemA,
system_b: SystemB,
name: Cow<'static, str>,
component_access: Access<ComponentId>,
archetype_component_access: Access<ArchetypeComponentId>,
}

impl<SystemA: System, SystemB: System<In = SystemA::Out>> System for ChainSystem<SystemA, SystemB> {
impl<SystemA: System, SystemB: System<In = SystemA::Out>> System for PipeSystem<SystemA, SystemB> {
type In = SystemA::In;
type Out = SystemB::Out;

Expand Down Expand Up @@ -121,33 +122,34 @@ impl<SystemA: System, SystemB: System<In = SystemA::Out>> System for ChainSystem
}
}

/// An extension trait providing the [`IntoChainSystem::chain`] method for convenient [`System`]
/// chaining.
/// An extension trait providing the [`IntoPipeSystem::pipe`] method to pass input from one system into the next.
///
/// The first system must have return type `T`
/// and the second system must have [`In<T>`](crate::system::In) as its first system parameter.
///
/// This trait is blanket implemented for all system pairs that fulfill the chaining requirement.
/// This trait is blanket implemented for all system pairs that fulfill the type requirements.
///
/// See [`ChainSystem`].
pub trait IntoChainSystem<ParamA, Payload, SystemB, ParamB, Out>:
/// See [`PipeSystem`].
pub trait IntoPipeSystem<ParamA, Payload, SystemB, ParamB, Out>:
IntoSystem<(), Payload, ParamA> + Sized
where
SystemB: IntoSystem<Payload, Out, ParamB>,
{
/// Chain this system `A` with another system `B` creating a new system that feeds system A's
/// output into system `B`, returning the output of system `B`.
fn chain(self, system: SystemB) -> ChainSystem<Self::System, SystemB::System>;
/// Pass the output of this system `A` into a second system `B`, creating a new compound system.
fn pipe(self, system: SystemB) -> PipeSystem<Self::System, SystemB::System>;
}

impl<SystemA, ParamA, Payload, SystemB, ParamB, Out>
IntoChainSystem<ParamA, Payload, SystemB, ParamB, Out> for SystemA
IntoPipeSystem<ParamA, Payload, SystemB, ParamB, Out> for SystemA
where
SystemA: IntoSystem<(), Payload, ParamA>,
SystemB: IntoSystem<Payload, Out, ParamB>,
{
fn chain(self, system: SystemB) -> ChainSystem<SystemA::System, SystemB::System> {
fn pipe(self, system: SystemB) -> PipeSystem<SystemA::System, SystemB::System> {
let system_a = IntoSystem::into_system(self);
let system_b = IntoSystem::into_system(system);
ChainSystem {
name: Cow::Owned(format!("Chain({}, {})", system_a.name(), system_b.name())),
PipeSystem {
name: Cow::Owned(format!("Pipe({}, {})", system_a.name(), system_b.name())),
system_a,
system_b,
archetype_component_access: Default::default(),
Expand All @@ -156,7 +158,7 @@ where
}
}

/// A collection of common adapters for [chaining](super::ChainSystem) the result of a system.
/// A collection of common adapters for [piping](super::PipeSystem) the result of a system.
pub mod adapter {
use crate::system::In;
use std::fmt::Debug;
Expand All @@ -168,9 +170,9 @@ pub mod adapter {
/// use bevy_ecs::prelude::*;
///
/// return1
/// .chain(system_adapter::new(u32::try_from))
/// .chain(system_adapter::unwrap)
/// .chain(print);
/// .pipe(system_adapter::new(u32::try_from))
/// .pipe(system_adapter::unwrap)
/// .pipe(print);
///
/// fn return1() -> u64 { 1 }
/// fn print(In(x): In<impl std::fmt::Debug>) {
Expand Down Expand Up @@ -204,7 +206,7 @@ pub mod adapter {
/// .add_system_to_stage(
/// CoreStage::Update,
/// // Panic if the load system returns an error.
/// load_save_system.chain(system_adapter::unwrap)
/// load_save_system.pipe(system_adapter::unwrap)
/// )
/// // ...
/// # ;
Expand All @@ -224,7 +226,7 @@ pub mod adapter {
res.unwrap()
}

/// System adapter that ignores the output of the previous system in a chain.
/// System adapter that ignores the output of the previous system in a pipe.
/// This is useful for fallible systems that should simply return early in case of an `Err`/`None`.
///
/// # Examples
Expand All @@ -248,7 +250,7 @@ pub mod adapter {
/// .add_system_to_stage(
/// CoreStage::Update,
/// // If the system fails, just move on and try again next frame.
/// fallible_system.chain(system_adapter::ignore)
/// fallible_system.pipe(system_adapter::ignore)
/// )
/// // ...
/// # ;
Expand Down Expand Up @@ -278,8 +280,8 @@ pub mod adapter {
unimplemented!()
}

assert_is_system(returning::<Result<u32, std::io::Error>>.chain(unwrap));
assert_is_system(returning::<Option<()>>.chain(ignore));
assert_is_system(returning::<&str>.chain(new(u64::from_str)).chain(unwrap));
assert_is_system(returning::<Result<u32, std::io::Error>>.pipe(unwrap));
assert_is_system(returning::<Option<()>>.pipe(ignore));
assert_is_system(returning::<&str>.pipe(new(u64::from_str)).pipe(unwrap));
}
}
2 changes: 1 addition & 1 deletion examples/README.md
Expand Up @@ -199,9 +199,9 @@ Example | Description
[Removal Detection](../examples/ecs/removal_detection.rs) | Query for entities that had a specific component removed in a previous stage during the current frame
[Startup System](../examples/ecs/startup_system.rs) | Demonstrates a startup system (one that runs once when the app starts up)
[State](../examples/ecs/state.rs) | Illustrates how to use States to control transitioning from a Menu state to an InGame state
[System Chaining](../examples/ecs/system_chaining.rs) | Chain two systems together, specifying a return type in a system (such as `Result`)
[System Closure](../examples/ecs/system_closure.rs) | Show how to use closures as systems, and how to configure `Local` variables by capturing external state
[System Parameter](../examples/ecs/system_param.rs) | Illustrates creating custom system parameters with `SystemParam`
[System Piping](../examples/ecs/system_piping.rs) | Pipe the output of one system into a second, allowing you to handle any errors gracefully
[System Sets](../examples/ecs/system_sets.rs) | Shows `SystemSet` use along with run criterion
[Timers](../examples/ecs/timers.rs) | Illustrates ticking `Timer` resources inside systems and handling their state

Expand Down
@@ -1,13 +1,13 @@
//! Illustrates how to make a single system from multiple functions running in sequence and sharing
//! their inputs and outputs.
//! Illustrates how to make a single system from multiple functions running in sequence,
//! passing the output of the first into the input of the next.

use anyhow::Result;
use bevy::prelude::*;

fn main() {
App::new()
.insert_resource(Message("42".to_string()))
.add_system(parse_message_system.chain(handler_system))
.add_system(parse_message_system.pipe(handler_system))
.run();
}

Expand Down