bevy icon indicating copy to clipboard operation
bevy copied to clipboard

SystemRunner param and macro syntax

Open ecoskey opened this issue 1 month ago • 2 comments

Objective

NOTE: blocked on #21917 and #21923

resolves #16680

Add a new system param for running systems inside other systems. Also, I've included some macros for nice syntax on top.

I'm pretty proud of how nice I was able to make this, but there's still a bit of work to do, especially around generic code :)

Testing

  • Ran examples
  • Tried to migrate existing pipe and map impls, but failed. This PR is pretty robust for most use cases but isn't fully ready for generic code yet. In particular, it's difficult to make sure the input types match (often have to wrap with StaticSystemInput) and ReadOnlySystem bound is inferred correctly when using for run conditions. These only really matter for combinators like pipe and map though, since otherwise they're run exactly the same.

Showcase

Click to view showcase
fn count_a(a: Query<&A>) -> u32 {
    a.count()
}

fn count_b(b: Query<&B>) -> u32 {
    b.count()
}

let get_sum = (
    ParamBuilder::system(count_a),
    ParamBuilder::system(count_b)
)
.build_system(
    |mut run_a: SystemRunner<(), u32>, mut run_b: SystemRunner<(), u32>| -> Result<u32, RunSystemError> {
        let a = run_a.run()?;
        let b = run_b.run()?;
        Ok(a + b)
    }
);

let get_sum = compose! {
    || -> Result<u32, RunSystemError> {
        let a = run!(count_a)?;
        let b = run!(count_b)?;
        Ok(a + b)
    }
}

ecoskey avatar Nov 12 '25 01:11 ecoskey

  • Tried to migrate existing pipe and map impls, but failed. This PR is pretty robust for most use cases but isn't fully ready for generic code yet. In particular, it's difficult to make sure the input types match (often have to wrap with StaticSystemInput) and ReadOnlySystem bound is inferred correctly when using for run conditions. These only really matter for combinators like pipe and map though, since otherwise they're run exactly the same.

I think I got pipe and and mostly working on this branch! I had to add lots of 'static annotations, but I think those are mostly harmless.

As you mentioned, the big problem is that the resulting systems take StaticSystemInput<In> instead of In, which means they can't be used in the schedule because that expects In = () and not In = StaticSystemInput<()>. Maybe we could create a wrapper type that converts a System<In = StaticSystemInput<In>> to a System<In = In>?

pub trait IntoSystem<In: SystemInput, Out, Marker>: Sized {
// ...
    fn pipe2<B, BIn, BOut, MarkerB>(
        self,
        system: B,
    ) -> impl System<In = StaticSystemInput<'static, In>, Out = BOut>
    where
        Out: 'static,
        B: IntoSystem<BIn, BOut, MarkerB> + 'static,
        for<'a> BIn: SystemInput<Inner<'a> = Out> + 'static,
        In: 'static,
        BOut: 'static,
        Marker: 'static,
        MarkerB: 'static,
        Self: 'static,
    {
        compose_with!(
            |StaticSystemInput(input): StaticSystemInput<In>| -> Result<BOut, RunSystemError> {
                let value = run!(self, input)?;
                run!(system, value)
            }
        )
    }
pub trait SystemCondition<Marker, In: SystemInput = ()>:
// ...
    fn and2<M: 'static, C: SystemCondition<M, In> + 'static>(
        self,
        and: C,
    ) -> impl ReadOnlySystem<In = StaticSystemInput<'static, In>, Out = bool>
    where
        for<'a> In: SystemInput<Inner<'a>: Copy> + 'static,
        Self: 'static,
        Marker: 'static,
    {
        compose_with!(
            |StaticSystemInput(input): StaticSystemInput<In>| -> Result<bool, RunSystemError> {
                Ok(run!(self, input)? && run!(and, input)?)
            }
        )
    }

chescock avatar Nov 12 '25 21:11 chescock

Thanks for the input! I'll spin up a few PRs for BuilderSystem and RemapInputSystem (or whatever we call it) and start cleaning things up tonight or tomorrow

Also I realized SystemInput::unwrap is probably unnecessary since you can just destructure StaticSystemInput :P

ecoskey avatar Nov 12 '25 22:11 ecoskey