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] - Support returning data out of with_children #4708

Closed
wants to merge 9 commits into from
71 changes: 61 additions & 10 deletions crates/bevy_hierarchy/src/child_builder.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
use crate::prelude::{Children, Parent, PreviousParent};
use smallvec::SmallVec;

use bevy_ecs::{
bundle::Bundle,
entity::Entity,
system::{Command, Commands, EntityCommands},
world::{EntityMut, World},
};
use smallvec::SmallVec;

use crate::prelude::{Children, Parent, PreviousParent};
Copy link
Member

Choose a reason for hiding this comment

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

We really need automated tooling for our imports. It's unclear to me why these have moved, but possibly it's our style?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think CLion tries to organize imports as external, internal, crate. I can revert if desired.


/// Command that adds a child to an entity
#[derive(Debug)]
Expand Down Expand Up @@ -166,6 +168,34 @@ impl<'w, 's, 'a> ChildBuilder<'w, 's, 'a> {
pub trait BuildChildren {
/// Creates a [`ChildBuilder`] with the given children built in the given closure
fn with_children(&mut self, f: impl FnOnce(&mut ChildBuilder)) -> &mut Self;
/// Creates a [`ChildBuilder`] with the given children built in the given closure
SUPERCILEX marked this conversation as resolved.
Show resolved Hide resolved
///
/// Compared to [`with_children`][BuildChildren::with_children], this method lets you
/// return data out of the closure like so:
SUPERCILEX marked this conversation as resolved.
Show resolved Hide resolved
///
/// ```
/// # use bevy_ecs::prelude::*;
/// # use bevy_hierarchy::*;
/// #
/// # #[derive(Component)]
/// # struct SomethingElse;
/// #
/// # #[derive(Component)]
/// # struct MoreStuff;
/// #
/// # fn foo(mut commands: Commands) {
SUPERCILEX marked this conversation as resolved.
Show resolved Hide resolved
/// let mut parent_commands = commands.spawn();
/// let child_id = parent_commands.add_children(|parent| {
/// parent.spawn().id()
/// });
///
/// parent_commands.insert(SomethingElse);
/// commands.entity(child_id).with_children(|parent| {
/// parent.spawn().insert(MoreStuff);
/// });
/// # }
/// ```
fn add_children<T>(&mut self, f: impl FnOnce(&mut ChildBuilder) -> T) -> T;
/// Pushes children to the back of the builder's children
fn push_children(&mut self, children: &[Entity]) -> &mut Self;
/// Inserts children at the given index
Expand Down Expand Up @@ -195,6 +225,23 @@ impl<'w, 's, 'a> BuildChildren for EntityCommands<'w, 's, 'a> {
self
}

fn add_children<T>(&mut self, spawn_children: impl FnOnce(&mut ChildBuilder) -> T) -> T {
SUPERCILEX marked this conversation as resolved.
Show resolved Hide resolved
let parent = self.id();
let (out, push_children) = {
SUPERCILEX marked this conversation as resolved.
Show resolved Hide resolved
let mut builder = ChildBuilder {
commands: self.commands(),
push_children: PushChildren {
children: SmallVec::default(),
parent,
},
};
(spawn_children(&mut builder), builder.push_children)
};

self.commands().add(push_children);
out
}

fn push_children(&mut self, children: &[Entity]) -> &mut Self {
let parent = self.id();
self.commands().add(PushChildren {
Expand Down Expand Up @@ -460,15 +507,18 @@ impl<'w> BuildWorldChildren for WorldChildBuilder<'w> {

#[cfg(test)]
mod tests {
use super::{BuildChildren, BuildWorldChildren};
use crate::prelude::{Children, Parent, PreviousParent};
use smallvec::{smallvec, SmallVec};

use bevy_ecs::{
component::Component,
entity::Entity,
system::{CommandQueue, Commands},
world::World,
};
use smallvec::{smallvec, SmallVec};

use crate::prelude::{Children, Parent, PreviousParent};

use super::{BuildChildren, BuildWorldChildren};

#[derive(Component)]
struct C(u32);
Expand All @@ -479,12 +529,13 @@ mod tests {
let mut queue = CommandQueue::default();
let mut commands = Commands::new(&mut queue, &world);

let mut children = Vec::new();
let parent = commands.spawn().insert(C(1)).id();
commands.entity(parent).with_children(|parent| {
children.push(parent.spawn().insert(C(2)).id());
children.push(parent.spawn().insert(C(3)).id());
children.push(parent.spawn().insert(C(4)).id());
let children = commands.entity(parent).add_children(|parent| {
[
SUPERCILEX marked this conversation as resolved.
Show resolved Hide resolved
parent.spawn().insert(C(2)).id(),
parent.spawn().insert(C(3)).id(),
parent.spawn().insert(C(4)).id(),
]
});

queue.apply(&mut world);
Expand Down