bevy/crates/bevy_ecs/src/system
JoJoJet d26b63a04d Add a SystemParam primitive for deferred mutations; allow #[derive]ing more types of SystemParam (#6817)
# Objective

One pattern to increase parallelism is deferred mutation: instead of directly mutating the world (and preventing other systems from running at the same time), you queue up operations to be applied to the world at the end of the stage. The most common example of this pattern uses the `Commands` SystemParam.

In order to avoid the overhead associated with commands, some power users may want to add their own deferred mutation behavior. To do this, you must implement the unsafe trait `SystemParam`, which interfaces with engine internals in a way that we'd like users to be able to avoid.

## Solution

Add the `Deferred<T>` primitive `SystemParam`, which encapsulates the deferred mutation pattern.
This can be combined with other types of `SystemParam` to safely and ergonomically create powerful custom types.

Essentially, this is just a variant of `Local<T>` which can run code at the end of the stage.

This type is used in the engine to derive `Commands` and `ParallelCommands`, which removes a bunch of unsafe boilerplate.

### Example

```rust
use bevy_ecs::system::{Deferred, SystemBuffer};

/// Sends events with a delay, but may run in parallel with other event writers.
#[derive(SystemParam)]
pub struct BufferedEventWriter<'s, E: Event> {
    queue: Deferred<'s, EventQueue<E>>,
}

struct EventQueue<E>(Vec<E>);

impl<'s, E: Event> BufferedEventWriter<'s, E> {
    /// Queues up an event to be sent at the end of this stage.
    pub fn send(&mut self, event: E) {
        self.queue.0.push(event);
    }
}

// The `SystemBuffer` trait controls how [`Deferred`] gets applied at the end of the stage.
impl<E: Event> SystemBuffer for EventQueue<E> {
    fn apply(&mut self, world: &mut World) {
        let mut events = world.resource_mut::<Events<E>>();
        for e in self.0.drain(..) {
            events.send(e);
        }
    }
}
```

---

## Changelog

+ Added the `SystemParam` type `Deferred<T>`, which can be used to defer `World` mutations. Powered by the new trait `SystemBuffer`.
2023-02-06 21:57:57 +00:00
..
commands Add a SystemParam primitive for deferred mutations; allow #[derive]ing more types of SystemParam (#6817) 2023-02-06 21:57:57 +00:00
exclusive_function_system.rs Rename schedule v3 to schedule (#7519) 2023-02-06 18:44:40 +00:00
exclusive_system_param.rs Remove ExclusiveSystemParam::apply (#7489) 2023-02-04 00:25:09 +00:00
function_system.rs Rename schedule v3 to schedule (#7519) 2023-02-06 18:44:40 +00:00
mod.rs Rename schedule v3 to schedule (#7519) 2023-02-06 18:44:40 +00:00
query.rs add UnsafeWorldCell abstraction (#6404) 2023-01-27 00:12:13 +00:00
system.rs Rename schedule v3 to schedule (#7519) 2023-02-06 18:44:40 +00:00
system_param.rs Add a SystemParam primitive for deferred mutations; allow #[derive]ing more types of SystemParam (#6817) 2023-02-06 21:57:57 +00:00
system_piping.rs Rename schedule v3 to schedule (#7519) 2023-02-06 18:44:40 +00:00