Skip to content

Increase upper limit of children! #18865

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
merged 2 commits into from
May 6, 2025

Conversation

CorvusPrudens
Copy link
Contributor

Objective

Currently, bevy_ecs's children! macro only supports spawning up to twelve children at once. Ideally there would be no limit.

Solution

children! is limited because SpawnableList, the primary trait bound here, uses the fake variadics pattern on tuples of up to twelve elements. However, since a tuple itself implements SpawnableList, we can simply nest tuples of entities when we run out of room.

This PR achieves this using macro_rules macros with a bit of brute force, following some discussion on Discord. If we create patterns for lists of up to eleven bundles, then use a repetition pattern to handle the rest, we can "special-case" the recursion into a nested tuple.

In principle, this would permit an arbitrary number of children, but Rust's recursion limits will cut things short at around 1400 elements by default. Of course, it's generally not a good idea to stick that many bundles in a single invocation, but it might be worth mentioning in the docs.

Implementation notes

Why are cases 0-11 expanded by hand?

We could make use of a tertiary macro:

macro_rules! recursive_spawn {
    // so that this...
    ($a:expr, $b:expr) => {
        (
            $crate::spawn::Spawn($a),
            $crate::spawn::Spawn($b),
        )
    };
    
    // becomes this...
    ($a:expr, $b:expr) => {
        $crate::spawn_tuple!($a, $b)
    };
}

But I already feel a little bad exporting recursive_spawn. I'd really like to avoid exposing more internals, even if they are annotated with #[doc(hidden)]. If I had to guess, I'd say it'll also make the expansion a tiny bit slower.

Do we really need to handle up to twelve elements in the macro?

The macro is a little long, but doing it this way maximizes the "flatness" of the types to be spawned. This should improve the codegen a bit and makes the macro output a little bit easier to look at.

Future work

The related! macro is essentially the same as children!, so if this direction is accepted, related! should receive the same treatment. I imagine we'd want to extract out the recursive_spawn macro into its own file since it can be used for both. If this should be tackled in this PR, let me know!

Testing

This change is fairly trivial, but I added a single test to verify that it compiles and nothing goes wrong once recursion starts happening. It's pretty easy to verify that the change works in practice -- just spawn over twelve entities as children at once!

Copy link
Contributor

Welcome, new contributor!

Please make sure you've read our contributing guide and we look forward to reviewing your pull request shortly ✨

Copy link
Contributor

@ElliottjPierce ElliottjPierce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good to me. There's definitely easier ways to do this, but they all involve changing Spawn stuff. This is a solid fix for now. Could you do the same thing for the spawn::related macro? And then make children call related. That way its all together.

@ElliottjPierce ElliottjPierce added C-Bug An unexpected or incorrect behavior A-ECS Entities, components, systems, and events S-Needs-Review Needs reviewer attention (from anyone!) to move forward D-Macros Code that generates Rust code labels Apr 17, 2025
@CorvusPrudens
Copy link
Contributor Author

I moved the recursive_spawn! macro to spawn.rs, which felt a little more appropriate. In the process, I set up both related! and children! to use it. Like you mentioned @ElliottjPierce, we could easily make children! simply call related!, but I don't mind the very minimal hardcoding of children! since it avoids one additional macro call.

Copy link
Contributor

@ElliottjPierce ElliottjPierce left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@JaySpruce JaySpruce added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Apr 29, 2025
@alice-i-cecile alice-i-cecile added the C-Usability A targeted quality-of-life change that makes Bevy easier to use label May 6, 2025
@alice-i-cecile alice-i-cecile added this pull request to the merge queue May 6, 2025
Merged via the queue into bevyengine:main with commit a312170 May 6, 2025
36 checks passed
@CorvusPrudens CorvusPrudens deleted the recursive-children branch May 6, 2025 19:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-ECS Entities, components, systems, and events C-Bug An unexpected or incorrect behavior C-Usability A targeted quality-of-life change that makes Bevy easier to use D-Macros Code that generates Rust code S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants