impl Command for <impl FnOnce(&mut World)> (#2996)

This is my first contribution to this exciting project! Thanks so much for your wonderful work. If there is anything that I can improve about this PR, please let me know :)

# Objective

- Fixes #2899
- If a simple one-off command is needed to be added within a System, this simplifies that process so that we can simply do `commands.add(|world: &mut World| { /* code here */ })` instead of defining a custom type implementing `Command`.

## Solution

- This is achieved by `impl Command for F where F: FnOnce(&mut World) + Send + Sync + 'static` as just calling the function.

I am not sure if the bounds can be further relaxed but needed the whole `Send`, `Sync`, and `'static` to get it to compile.
This commit is contained in:
Stefan Seemayer 2022-02-03 04:11:19 +00:00
parent 69e9a47d92
commit 21ac4bc0ae

View File

@ -544,6 +544,15 @@ impl<'w, 's, 'a> EntityCommands<'w, 's, 'a> {
}
}
impl<F> Command for F
where
F: FnOnce(&mut World) + Send + Sync + 'static,
{
fn write(self, world: &mut World) {
self(world)
}
}
#[derive(Debug)]
pub struct Spawn<T> {
pub bundle: T,
@ -760,6 +769,10 @@ mod tests {
#[derive(Component)]
struct W<T>(T);
fn simple_command(world: &mut World) {
world.spawn().insert_bundle((W(0u32), W(42u64)));
}
#[test]
fn commands() {
let mut world = World::default();
@ -788,6 +801,27 @@ mod tests {
.map(|(a, b)| (a.0, b.0))
.collect::<Vec<_>>();
assert_eq!(results2, vec![]);
// test adding simple (FnOnce) commands
{
let mut commands = Commands::new(&mut command_queue, &world);
// set up a simple command using a closure that adds one additional entity
commands.add(|world: &mut World| {
world.spawn().insert_bundle((W(42u32), W(0u64)));
});
// set up a simple command using a function that adds one additional entity
commands.add(simple_command);
}
command_queue.apply(&mut world);
let results3 = world
.query::<(&W<u32>, &W<u64>)>()
.iter(&world)
.map(|(a, b)| (a.0, b.0))
.collect::<Vec<_>>();
assert_eq!(results3, vec![(42u32, 0u64), (0u32, 42u64)]);
}
#[test]