Skip to content

Commit a0a14aa

Browse files
committed
Support returning data out of with_children (#4708)
# Objective Support returning data out of with_children to enable the use case of changing the parent commands with data created inside the child builder. ## Solution Change the with_children closure to return T. Closes #2817. --- ## Changelog `BuildChildren::add_children` was added with the ability to return data to use outside the closure (for spawning a new child builder on a returned entity for example).
1 parent 7da21b1 commit a0a14aa

File tree

1 file changed

+65
-22
lines changed

1 file changed

+65
-22
lines changed

crates/bevy_hierarchy/src/child_builder.rs

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
1-
use crate::prelude::{Children, Parent, PreviousParent};
1+
use smallvec::SmallVec;
2+
23
use bevy_ecs::{
34
bundle::Bundle,
45
entity::Entity,
56
system::{Command, Commands, EntityCommands},
67
world::{EntityMut, World},
78
};
8-
use smallvec::SmallVec;
9+
10+
use crate::prelude::{Children, Parent, PreviousParent};
911

1012
/// Command that adds a child to an entity
1113
#[derive(Debug)]
@@ -165,7 +167,40 @@ impl<'w, 's, 'a> ChildBuilder<'w, 's, 'a> {
165167
/// Trait defining how to build children
166168
pub trait BuildChildren {
167169
/// Creates a [`ChildBuilder`] with the given children built in the given closure
170+
///
171+
/// Compared to [`add_children`][BuildChildren::add_children], this method returns self
172+
/// to allow chaining.
168173
fn with_children(&mut self, f: impl FnOnce(&mut ChildBuilder)) -> &mut Self;
174+
/// Creates a [`ChildBuilder`] with the given children built in the given closure
175+
///
176+
/// Compared to [`with_children`][BuildChildren::with_children], this method returns the
177+
/// the value returned from the closure, but doesn't allow chaining.
178+
///
179+
/// ## Example
180+
///
181+
/// ```no_run
182+
/// # use bevy_ecs::prelude::*;
183+
/// # use bevy_hierarchy::*;
184+
/// #
185+
/// # #[derive(Component)]
186+
/// # struct SomethingElse;
187+
/// #
188+
/// # #[derive(Component)]
189+
/// # struct MoreStuff;
190+
/// #
191+
/// # fn foo(mut commands: Commands) {
192+
/// let mut parent_commands = commands.spawn();
193+
/// let child_id = parent_commands.add_children(|parent| {
194+
/// parent.spawn().id()
195+
/// });
196+
///
197+
/// parent_commands.insert(SomethingElse);
198+
/// commands.entity(child_id).with_children(|parent| {
199+
/// parent.spawn().insert(MoreStuff);
200+
/// });
201+
/// # }
202+
/// ```
203+
fn add_children<T>(&mut self, f: impl FnOnce(&mut ChildBuilder) -> T) -> T;
169204
/// Pushes children to the back of the builder's children
170205
fn push_children(&mut self, children: &[Entity]) -> &mut Self;
171206
/// Inserts children at the given index
@@ -178,21 +213,25 @@ pub trait BuildChildren {
178213

179214
impl<'w, 's, 'a> BuildChildren for EntityCommands<'w, 's, 'a> {
180215
fn with_children(&mut self, spawn_children: impl FnOnce(&mut ChildBuilder)) -> &mut Self {
216+
self.add_children(spawn_children);
217+
self
218+
}
219+
220+
fn add_children<T>(&mut self, spawn_children: impl FnOnce(&mut ChildBuilder) -> T) -> T {
181221
let parent = self.id();
182-
let push_children = {
183-
let mut builder = ChildBuilder {
184-
commands: self.commands(),
185-
push_children: PushChildren {
186-
children: SmallVec::default(),
187-
parent,
188-
},
189-
};
190-
spawn_children(&mut builder);
191-
builder.push_children
222+
let mut builder = ChildBuilder {
223+
commands: self.commands(),
224+
push_children: PushChildren {
225+
children: SmallVec::default(),
226+
parent,
227+
},
192228
};
193229

194-
self.commands().add(push_children);
195-
self
230+
let result = spawn_children(&mut builder);
231+
let children = builder.push_children;
232+
self.commands().add(children);
233+
234+
result
196235
}
197236

198237
fn push_children(&mut self, children: &[Entity]) -> &mut Self {
@@ -460,15 +499,18 @@ impl<'w> BuildWorldChildren for WorldChildBuilder<'w> {
460499

461500
#[cfg(test)]
462501
mod tests {
463-
use super::{BuildChildren, BuildWorldChildren};
464-
use crate::prelude::{Children, Parent, PreviousParent};
502+
use smallvec::{smallvec, SmallVec};
503+
465504
use bevy_ecs::{
466505
component::Component,
467506
entity::Entity,
468507
system::{CommandQueue, Commands},
469508
world::World,
470509
};
471-
use smallvec::{smallvec, SmallVec};
510+
511+
use crate::prelude::{Children, Parent, PreviousParent};
512+
513+
use super::{BuildChildren, BuildWorldChildren};
472514

473515
#[derive(Component)]
474516
struct C(u32);
@@ -479,12 +521,13 @@ mod tests {
479521
let mut queue = CommandQueue::default();
480522
let mut commands = Commands::new(&mut queue, &world);
481523

482-
let mut children = Vec::new();
483524
let parent = commands.spawn().insert(C(1)).id();
484-
commands.entity(parent).with_children(|parent| {
485-
children.push(parent.spawn().insert(C(2)).id());
486-
children.push(parent.spawn().insert(C(3)).id());
487-
children.push(parent.spawn().insert(C(4)).id());
525+
let children = commands.entity(parent).add_children(|parent| {
526+
[
527+
parent.spawn().insert(C(2)).id(),
528+
parent.spawn().insert(C(3)).id(),
529+
parent.spawn().insert(C(4)).id(),
530+
]
488531
});
489532

490533
queue.apply(&mut world);

0 commit comments

Comments
 (0)