-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
SystemRunner param and macro syntax #21811
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
base: main
Are you sure you want to change the base?
Conversation
bbc70c7 to
e0c905c
Compare
chescock
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really cool!
I think this will close #16680, so you might want to link that in the PR description.
I left a lot of comments, but they're mostly style nitpicks and brainstorming for future possibilities. The only thing that I think really needs attention is the map_err(RunSystemError::Skipped) part, since that will silently ignore missing resources. And the CI failure :).
| Uninitialized { | ||
| builder: Builder, | ||
| func: Func, | ||
| meta: SystemMeta, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this here only to support with_name? (It's also used in get_last_run/set_last_run, but I think those are only supposed to be valid on initialized systems.) It might be better to just store a DebugName. If the builder is large, this could wind up being the largest variant and taking up space even after the system is built.
| /// ParamBuilder::system(count_b) | ||
| /// ) | ||
| /// .build_state(&mut world) | ||
| /// .build_system( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other CI failure is because it can't tell whether the return type is u32 or Result<u32>. You can supply it like
| /// .build_system( | |
| /// .build_system::<_, u32, _, _>( |
But it might look nicer to run the system and annotate the result, like
/// let result: usize = world.run_system_once(get_sum).unwrap();
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how does add_systems infer which to use?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how does
add_systemsinfer which to use?
It just always requires Out = () for systems and Out = bool for conditions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh yeah true. And the other combinators can set it explicitly, sounds good.
| /// ```ignore | ||
| /// let system_a = |world: &mut World| { 10 }; | ||
| /// let system_b = |a: In<u32>, world: &mut World| { println!("{}", *a + 12) }; | ||
| /// compose! { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to accept a function definition instead of or in addition to a closure? That would make it easier for these systems to have names. Something like
compose! {
fn system_name() -> Result<(), RunSystemError> {
run!(system_a)
}
}For that matter, would it make sense to use an attribute macro, like
#[compose]
fn system_name() -> Result<(), RunSystemError> {
run!(system_a)
}?
... Oh, maybe not, because what you'd really want that to expand to is const system_name: impl System = const { ... };, but there's no way to write the type for the const.
I think I got As you mentioned, the big problem is that the resulting systems take 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)?)
}
)
} |
|
Thanks for the input! I'll spin up a few PRs for Also I realized |
cf12de9 to
6443d66
Compare
6443d66 to
c8cfcc1
Compare
c8cfcc1 to
8ac61d3
Compare
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
pipeandmapimpls, 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 withStaticSystemInput) andReadOnlySystembound is inferred correctly when using for run conditions. These only really matter for combinators likepipeandmapthough, since otherwise they're run exactly the same.Showcase
Click to view showcase