Thanks to visit codestin.com
Credit goes to docs.rs

bevy_ecs/
lifecycle.rs

1//! This module contains various tools to allow you to react to component insertion or removal,
2//! as well as entity spawning and despawning.
3//!
4//! There are four main ways to react to these lifecycle events:
5//!
6//! 1. Using component hooks, which act as inherent constructors and destructors for components.
7//! 2. Using [observers], which are a user-extensible way to respond to events, including component lifecycle events.
8//! 3. Using the [`RemovedComponents`] system parameter, which offers an event-style interface.
9//! 4. Using the [`Added`] query filter, which checks each component to see if it has been added since the last time a system ran.
10//!
11//! [observers]: crate::observer
12//! [`Added`]: crate::query::Added
13//!
14//! # Types of lifecycle events
15//!
16//! There are five types of lifecycle events, split into two categories. First, we have lifecycle events that are triggered
17//! when a component is added to an entity:
18//!
19//! - [`Add`]: Triggered when a component is added to an entity that did not already have it.
20//! - [`Insert`]: Triggered when a component is added to an entity, regardless of whether it already had it.
21//!
22//! When both events occur, [`Add`] hooks are evaluated before [`Insert`].
23//!
24//! Next, we have lifecycle events that are triggered when a component is removed from an entity:
25//!
26//! - [`Replace`]: Triggered when a component is removed from an entity, regardless if it is then replaced with a new value.
27//! - [`Remove`]: Triggered when a component is removed from an entity and not replaced, before the component is removed.
28//! - [`Despawn`]: Triggered for each component on an entity when it is despawned.
29//!
30//! [`Replace`] hooks are evaluated before [`Remove`], then finally [`Despawn`] hooks are evaluated.
31//!
32//! [`Add`] and [`Remove`] are counterparts: they are only triggered when a component is added or removed
33//! from an entity in such a way as to cause a change in the component's presence on that entity.
34//! Similarly, [`Insert`] and [`Replace`] are counterparts: they are triggered when a component is added or replaced
35//! on an entity, regardless of whether this results in a change in the component's presence on that entity.
36//!
37//! To reliably synchronize data structures using with component lifecycle events,
38//! you can combine [`Insert`] and [`Replace`] to fully capture any changes to the data.
39//! This is particularly useful in combination with immutable components,
40//! to avoid any lifecycle-bypassing mutations.
41//!
42//! ## Lifecycle events and component types
43//!
44//! Despite the absence of generics, each lifecycle event is associated with a specific component.
45//! When defining a component hook for a [`Component`] type, that component is used.
46//! When observers watch lifecycle events, the `B: Bundle` generic is used.
47//!
48//! Each of these lifecycle events also corresponds to a fixed [`ComponentId`],
49//! which are assigned during [`World`] initialization.
50//! For example, [`Add`] corresponds to [`ADD`].
51//! This is used to skip [`TypeId`](core::any::TypeId) lookups in hot paths.
52use crate::{
53    change_detection::MaybeLocation,
54    component::{Component, ComponentId, ComponentIdFor, Tick},
55    entity::Entity,
56    event::{EntityComponentsTrigger, EntityEvent, EventKey},
57    message::{
58        Message, MessageCursor, MessageId, MessageIterator, MessageIteratorWithId, Messages,
59    },
60    query::FilteredAccessSet,
61    relationship::RelationshipHookMode,
62    storage::SparseSet,
63    system::{Local, ReadOnlySystemParam, SystemMeta, SystemParam},
64    world::{unsafe_world_cell::UnsafeWorldCell, DeferredWorld, World},
65};
66
67use derive_more::derive::Into;
68
69#[cfg(feature = "bevy_reflect")]
70use bevy_reflect::Reflect;
71use core::{
72    fmt::Debug,
73    iter,
74    marker::PhantomData,
75    ops::{Deref, DerefMut},
76    option,
77};
78
79/// The type used for [`Component`] lifecycle hooks such as `on_add`, `on_insert` or `on_remove`.
80pub type ComponentHook = for<'w> fn(DeferredWorld<'w>, HookContext);
81
82/// Context provided to a [`ComponentHook`].
83#[derive(Clone, Copy, Debug)]
84pub struct HookContext {
85    /// The [`Entity`] this hook was invoked for.
86    pub entity: Entity,
87    /// The [`ComponentId`] this hook was invoked for.
88    pub component_id: ComponentId,
89    /// The caller location is `Some` if the `track_caller` feature is enabled.
90    pub caller: MaybeLocation,
91    /// Configures how relationship hooks will run
92    pub relationship_hook_mode: RelationshipHookMode,
93}
94
95/// [`World`]-mutating functions that run as part of lifecycle events of a [`Component`].
96///
97/// Hooks are functions that run when a component is added, overwritten, or removed from an entity.
98/// These are intended to be used for structural side effects that need to happen when a component is added or removed,
99/// and are not intended for general-purpose logic.
100///
101/// For example, you might use a hook to update a cached index when a component is added,
102/// to clean up resources when a component is removed,
103/// or to keep hierarchical data structures across entities in sync.
104///
105/// This information is stored in the [`ComponentInfo`](crate::component::ComponentInfo) of the associated component.
106///
107/// There are two ways of configuring hooks for a component:
108/// 1. Defining the relevant hooks on the [`Component`] implementation
109/// 2. Using the [`World::register_component_hooks`] method
110///
111/// # Example
112///
113/// ```
114/// use bevy_ecs::prelude::*;
115/// use bevy_platform::collections::HashSet;
116///
117/// #[derive(Component)]
118/// struct MyTrackedComponent;
119///
120/// #[derive(Resource, Default)]
121/// struct TrackedEntities(HashSet<Entity>);
122///
123/// let mut world = World::new();
124/// world.init_resource::<TrackedEntities>();
125///
126/// // No entities with `MyTrackedComponent` have been added yet, so we can safely add component hooks
127/// let mut tracked_component_query = world.query::<&MyTrackedComponent>();
128/// assert!(tracked_component_query.iter(&world).next().is_none());
129///
130/// world.register_component_hooks::<MyTrackedComponent>().on_add(|mut world, context| {
131///    let mut tracked_entities = world.resource_mut::<TrackedEntities>();
132///   tracked_entities.0.insert(context.entity);
133/// });
134///
135/// world.register_component_hooks::<MyTrackedComponent>().on_remove(|mut world, context| {
136///   let mut tracked_entities = world.resource_mut::<TrackedEntities>();
137///   tracked_entities.0.remove(&context.entity);
138/// });
139///
140/// let entity = world.spawn(MyTrackedComponent).id();
141/// let tracked_entities = world.resource::<TrackedEntities>();
142/// assert!(tracked_entities.0.contains(&entity));
143///
144/// world.despawn(entity);
145/// let tracked_entities = world.resource::<TrackedEntities>();
146/// assert!(!tracked_entities.0.contains(&entity));
147/// ```
148#[derive(Debug, Clone, Default)]
149pub struct ComponentHooks {
150    pub(crate) on_add: Option<ComponentHook>,
151    pub(crate) on_insert: Option<ComponentHook>,
152    pub(crate) on_replace: Option<ComponentHook>,
153    pub(crate) on_remove: Option<ComponentHook>,
154    pub(crate) on_despawn: Option<ComponentHook>,
155}
156
157impl ComponentHooks {
158    pub(crate) fn update_from_component<C: Component + ?Sized>(&mut self) -> &mut Self {
159        if let Some(hook) = C::on_add() {
160            self.on_add(hook);
161        }
162        if let Some(hook) = C::on_insert() {
163            self.on_insert(hook);
164        }
165        if let Some(hook) = C::on_replace() {
166            self.on_replace(hook);
167        }
168        if let Some(hook) = C::on_remove() {
169            self.on_remove(hook);
170        }
171        if let Some(hook) = C::on_despawn() {
172            self.on_despawn(hook);
173        }
174
175        self
176    }
177
178    /// Register a [`ComponentHook`] that will be run when this component is added to an entity.
179    /// An `on_add` hook will always run before `on_insert` hooks. Spawning an entity counts as
180    /// adding all of its components.
181    ///
182    /// # Panics
183    ///
184    /// Will panic if the component already has an `on_add` hook
185    pub fn on_add(&mut self, hook: ComponentHook) -> &mut Self {
186        self.try_on_add(hook)
187            .expect("Component already has an on_add hook")
188    }
189
190    /// Register a [`ComponentHook`] that will be run when this component is added (with `.insert`)
191    /// or replaced.
192    ///
193    /// An `on_insert` hook always runs after any `on_add` hooks (if the entity didn't already have the component).
194    ///
195    /// # Warning
196    ///
197    /// The hook won't run if the component is already present and is only mutated, such as in a system via a query.
198    /// As a result, this needs to be combined with immutable components to serve as a mechanism for reliably updating indexes and other caches.
199    ///
200    /// # Panics
201    ///
202    /// Will panic if the component already has an `on_insert` hook
203    pub fn on_insert(&mut self, hook: ComponentHook) -> &mut Self {
204        self.try_on_insert(hook)
205            .expect("Component already has an on_insert hook")
206    }
207
208    /// Register a [`ComponentHook`] that will be run when this component is about to be dropped,
209    /// such as being replaced (with `.insert`) or removed.
210    ///
211    /// If this component is inserted onto an entity that already has it, this hook will run before the value is replaced,
212    /// allowing access to the previous data just before it is dropped.
213    /// This hook does *not* run if the entity did not already have this component.
214    ///
215    /// An `on_replace` hook always runs before any `on_remove` hooks (if the component is being removed from the entity).
216    ///
217    /// # Warning
218    ///
219    /// The hook won't run if the component is already present and is only mutated, such as in a system via a query.
220    /// As a result, this needs to be combined with immutable components to serve as a mechanism for reliably updating indexes and other caches.
221    ///
222    /// # Panics
223    ///
224    /// Will panic if the component already has an `on_replace` hook
225    pub fn on_replace(&mut self, hook: ComponentHook) -> &mut Self {
226        self.try_on_replace(hook)
227            .expect("Component already has an on_replace hook")
228    }
229
230    /// Register a [`ComponentHook`] that will be run when this component is removed from an entity.
231    /// Despawning an entity counts as removing all of its components.
232    ///
233    /// # Panics
234    ///
235    /// Will panic if the component already has an `on_remove` hook
236    pub fn on_remove(&mut self, hook: ComponentHook) -> &mut Self {
237        self.try_on_remove(hook)
238            .expect("Component already has an on_remove hook")
239    }
240
241    /// Register a [`ComponentHook`] that will be run for each component on an entity when it is despawned.
242    ///
243    /// # Panics
244    ///
245    /// Will panic if the component already has an `on_despawn` hook
246    pub fn on_despawn(&mut self, hook: ComponentHook) -> &mut Self {
247        self.try_on_despawn(hook)
248            .expect("Component already has an on_despawn hook")
249    }
250
251    /// Attempt to register a [`ComponentHook`] that will be run when this component is added to an entity.
252    ///
253    /// This is a fallible version of [`Self::on_add`].
254    ///
255    /// Returns `None` if the component already has an `on_add` hook.
256    pub fn try_on_add(&mut self, hook: ComponentHook) -> Option<&mut Self> {
257        if self.on_add.is_some() {
258            return None;
259        }
260        self.on_add = Some(hook);
261        Some(self)
262    }
263
264    /// Attempt to register a [`ComponentHook`] that will be run when this component is added (with `.insert`)
265    ///
266    /// This is a fallible version of [`Self::on_insert`].
267    ///
268    /// Returns `None` if the component already has an `on_insert` hook.
269    pub fn try_on_insert(&mut self, hook: ComponentHook) -> Option<&mut Self> {
270        if self.on_insert.is_some() {
271            return None;
272        }
273        self.on_insert = Some(hook);
274        Some(self)
275    }
276
277    /// Attempt to register a [`ComponentHook`] that will be run when this component is replaced (with `.insert`) or removed
278    ///
279    /// This is a fallible version of [`Self::on_replace`].
280    ///
281    /// Returns `None` if the component already has an `on_replace` hook.
282    pub fn try_on_replace(&mut self, hook: ComponentHook) -> Option<&mut Self> {
283        if self.on_replace.is_some() {
284            return None;
285        }
286        self.on_replace = Some(hook);
287        Some(self)
288    }
289
290    /// Attempt to register a [`ComponentHook`] that will be run when this component is removed from an entity.
291    ///
292    /// This is a fallible version of [`Self::on_remove`].
293    ///
294    /// Returns `None` if the component already has an `on_remove` hook.
295    pub fn try_on_remove(&mut self, hook: ComponentHook) -> Option<&mut Self> {
296        if self.on_remove.is_some() {
297            return None;
298        }
299        self.on_remove = Some(hook);
300        Some(self)
301    }
302
303    /// Attempt to register a [`ComponentHook`] that will be run for each component on an entity when it is despawned.
304    ///
305    /// This is a fallible version of [`Self::on_despawn`].
306    ///
307    /// Returns `None` if the component already has an `on_despawn` hook.
308    pub fn try_on_despawn(&mut self, hook: ComponentHook) -> Option<&mut Self> {
309        if self.on_despawn.is_some() {
310            return None;
311        }
312        self.on_despawn = Some(hook);
313        Some(self)
314    }
315}
316
317/// [`EventKey`] for [`Add`]
318pub const ADD: EventKey = EventKey(ComponentId::new(0));
319/// [`EventKey`] for [`Insert`]
320pub const INSERT: EventKey = EventKey(ComponentId::new(1));
321/// [`EventKey`] for [`Replace`]
322pub const REPLACE: EventKey = EventKey(ComponentId::new(2));
323/// [`EventKey`] for [`Remove`]
324pub const REMOVE: EventKey = EventKey(ComponentId::new(3));
325/// [`EventKey`] for [`Despawn`]
326pub const DESPAWN: EventKey = EventKey(ComponentId::new(4));
327
328/// Trigger emitted when a component is inserted onto an entity that does not already have that
329/// component. Runs before `Insert`.
330/// See [`ComponentHooks::on_add`](`crate::lifecycle::ComponentHooks::on_add`) for more information.
331#[derive(Debug, Clone, EntityEvent)]
332#[entity_event(trigger = EntityComponentsTrigger<'a>)]
333#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
334#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
335#[doc(alias = "OnAdd")]
336pub struct Add {
337    /// The entity this component was added to.
338    pub entity: Entity,
339}
340
341/// Trigger emitted when a component is inserted, regardless of whether or not the entity already
342/// had that component. Runs after `Add`, if it ran.
343/// See [`ComponentHooks::on_insert`](`crate::lifecycle::ComponentHooks::on_insert`) for more information.
344#[derive(Debug, Clone, EntityEvent)]
345#[entity_event(trigger = EntityComponentsTrigger<'a>)]
346#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
347#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
348#[doc(alias = "OnInsert")]
349pub struct Insert {
350    /// The entity this component was inserted into.
351    pub entity: Entity,
352}
353
354/// Trigger emitted when a component is removed from an entity, regardless
355/// of whether or not it is later replaced.
356///
357/// Runs before the value is replaced, so you can still access the original component data.
358/// See [`ComponentHooks::on_replace`](`crate::lifecycle::ComponentHooks::on_replace`) for more information.
359#[derive(Debug, Clone, EntityEvent)]
360#[entity_event(trigger = EntityComponentsTrigger<'a>)]
361#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
362#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
363#[doc(alias = "OnReplace")]
364pub struct Replace {
365    /// The entity that held this component before it was replaced.
366    pub entity: Entity,
367}
368
369/// Trigger emitted when a component is removed from an entity, and runs before the component is
370/// removed, so you can still access the component data.
371/// See [`ComponentHooks::on_remove`](`crate::lifecycle::ComponentHooks::on_remove`) for more information.
372#[derive(Debug, Clone, EntityEvent)]
373#[entity_event(trigger = EntityComponentsTrigger<'a>)]
374#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
375#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
376#[doc(alias = "OnRemove")]
377pub struct Remove {
378    /// The entity this component was removed from.
379    pub entity: Entity,
380}
381
382/// [`EntityEvent`] emitted for each component on an entity when it is despawned.
383/// See [`ComponentHooks::on_despawn`](`crate::lifecycle::ComponentHooks::on_despawn`) for more information.
384#[derive(Debug, Clone, EntityEvent)]
385#[entity_event(trigger = EntityComponentsTrigger<'a>)]
386#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
387#[cfg_attr(feature = "bevy_reflect", reflect(Debug))]
388#[doc(alias = "OnDespawn")]
389pub struct Despawn {
390    /// The entity that held this component before it was despawned.
391    pub entity: Entity,
392}
393
394/// Deprecated in favor of [`Add`].
395#[deprecated(since = "0.17.0", note = "Renamed to `Add`.")]
396pub type OnAdd = Add;
397
398/// Deprecated in favor of [`Insert`].
399#[deprecated(since = "0.17.0", note = "Renamed to `Insert`.")]
400pub type OnInsert = Insert;
401
402/// Deprecated in favor of [`Replace`].
403#[deprecated(since = "0.17.0", note = "Renamed to `Replace`.")]
404pub type OnReplace = Replace;
405
406/// Deprecated in favor of [`Remove`].
407#[deprecated(since = "0.17.0", note = "Renamed to `Remove`.")]
408pub type OnRemove = Remove;
409
410/// Deprecated in favor of [`Despawn`].
411#[deprecated(since = "0.17.0", note = "Renamed to `Despawn`.")]
412pub type OnDespawn = Despawn;
413
414/// Wrapper around [`Entity`] for [`RemovedComponents`].
415/// Internally, `RemovedComponents` uses these as an [`Messages<RemovedComponentEntity>`].
416#[derive(Message, Debug, Clone, Into)]
417#[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
418#[cfg_attr(feature = "bevy_reflect", reflect(Debug, Clone))]
419pub struct RemovedComponentEntity(Entity);
420
421/// Wrapper around a [`MessageCursor<RemovedComponentEntity>`] so that we
422/// can differentiate messages between components.
423#[derive(Debug)]
424pub struct RemovedComponentReader<T>
425where
426    T: Component,
427{
428    reader: MessageCursor<RemovedComponentEntity>,
429    marker: PhantomData<T>,
430}
431
432impl<T: Component> Default for RemovedComponentReader<T> {
433    fn default() -> Self {
434        Self {
435            reader: Default::default(),
436            marker: PhantomData,
437        }
438    }
439}
440
441impl<T: Component> Deref for RemovedComponentReader<T> {
442    type Target = MessageCursor<RemovedComponentEntity>;
443    fn deref(&self) -> &Self::Target {
444        &self.reader
445    }
446}
447
448impl<T: Component> DerefMut for RemovedComponentReader<T> {
449    fn deref_mut(&mut self) -> &mut Self::Target {
450        &mut self.reader
451    }
452}
453/// Renamed to [`RemovedComponentMessages`].
454#[deprecated(since = "0.17.0", note = "Use `RemovedComponentMessages` instead.")]
455pub type RemovedComponentEvents = RemovedComponentMessages;
456
457/// Stores the [`RemovedComponents`] event buffers for all types of component in a given [`World`].
458#[derive(Default, Debug)]
459pub struct RemovedComponentMessages {
460    event_sets: SparseSet<ComponentId, Messages<RemovedComponentEntity>>,
461}
462
463impl RemovedComponentMessages {
464    /// Creates an empty storage buffer for component removal messages.
465    pub fn new() -> Self {
466        Self::default()
467    }
468
469    /// For each type of component, swaps the event buffers and clears the oldest event buffer.
470    /// In general, this should be called once per frame/update.
471    pub fn update(&mut self) {
472        for (_component_id, messages) in self.event_sets.iter_mut() {
473            messages.update();
474        }
475    }
476
477    /// Returns an iterator over components and their entity messages.
478    pub fn iter(&self) -> impl Iterator<Item = (&ComponentId, &Messages<RemovedComponentEntity>)> {
479        self.event_sets.iter()
480    }
481
482    /// Gets the event storage for a given component.
483    pub fn get(
484        &self,
485        component_id: impl Into<ComponentId>,
486    ) -> Option<&Messages<RemovedComponentEntity>> {
487        self.event_sets.get(component_id.into())
488    }
489
490    /// Sends a removal message for the specified component.
491    #[deprecated(
492        since = "0.17.0",
493        note = "Use `RemovedComponentMessages:write` instead."
494    )]
495    pub fn send(&mut self, component_id: impl Into<ComponentId>, entity: Entity) {
496        self.write(component_id, entity);
497    }
498
499    /// Writes a removal message for the specified component.
500    pub fn write(&mut self, component_id: impl Into<ComponentId>, entity: Entity) {
501        self.event_sets
502            .get_or_insert_with(component_id.into(), Default::default)
503            .write(RemovedComponentEntity(entity));
504    }
505}
506
507/// A [`SystemParam`] that yields entities that had their `T` [`Component`]
508/// removed or have been despawned with it.
509///
510/// This acts effectively the same as a [`MessageReader`](crate::message::MessageReader).
511///
512/// Unlike hooks or observers (see the [lifecycle](crate) module docs),
513/// this does not allow you to see which data existed before removal.
514///
515/// If you are using `bevy_ecs` as a standalone crate,
516/// note that the [`RemovedComponents`] list will not be automatically cleared for you,
517/// and will need to be manually flushed using [`World::clear_trackers`](World::clear_trackers).
518///
519/// For users of `bevy` and `bevy_app`, [`World::clear_trackers`](World::clear_trackers) is
520/// automatically called by `bevy_app::App::update` and `bevy_app::SubApp::update`.
521/// For the main world, this is delayed until after all `SubApp`s have run.
522///
523/// # Examples
524///
525/// Basic usage:
526///
527/// ```
528/// # use bevy_ecs::component::Component;
529/// # use bevy_ecs::system::IntoSystem;
530/// # use bevy_ecs::lifecycle::RemovedComponents;
531/// #
532/// # #[derive(Component)]
533/// # struct MyComponent;
534/// fn react_on_removal(mut removed: RemovedComponents<MyComponent>) {
535///     removed.read().for_each(|removed_entity| println!("{}", removed_entity));
536/// }
537/// # bevy_ecs::system::assert_is_system(react_on_removal);
538/// ```
539#[derive(SystemParam)]
540pub struct RemovedComponents<'w, 's, T: Component> {
541    component_id: ComponentIdFor<'s, T>,
542    reader: Local<'s, RemovedComponentReader<T>>,
543    message_sets: &'w RemovedComponentMessages,
544}
545
546/// Iterator over entities that had a specific component removed.
547///
548/// See [`RemovedComponents`].
549pub type RemovedIter<'a> = iter::Map<
550    iter::Flatten<option::IntoIter<iter::Cloned<MessageIterator<'a, RemovedComponentEntity>>>>,
551    fn(RemovedComponentEntity) -> Entity,
552>;
553
554/// Iterator over entities that had a specific component removed.
555///
556/// See [`RemovedComponents`].
557pub type RemovedIterWithId<'a> = iter::Map<
558    iter::Flatten<option::IntoIter<MessageIteratorWithId<'a, RemovedComponentEntity>>>,
559    fn(
560        (&RemovedComponentEntity, MessageId<RemovedComponentEntity>),
561    ) -> (Entity, MessageId<RemovedComponentEntity>),
562>;
563
564fn map_id_messages(
565    (entity, id): (&RemovedComponentEntity, MessageId<RemovedComponentEntity>),
566) -> (Entity, MessageId<RemovedComponentEntity>) {
567    (entity.clone().into(), id)
568}
569
570// For all practical purposes, the api surface of `RemovedComponents<T>`
571// should be similar to `MessageReader<T>` to reduce confusion.
572impl<'w, 's, T: Component> RemovedComponents<'w, 's, T> {
573    /// Fetch underlying [`MessageCursor`].
574    pub fn reader(&self) -> &MessageCursor<RemovedComponentEntity> {
575        &self.reader
576    }
577
578    /// Fetch underlying [`MessageCursor`] mutably.
579    pub fn reader_mut(&mut self) -> &mut MessageCursor<RemovedComponentEntity> {
580        &mut self.reader
581    }
582
583    /// Fetch underlying [`Messages`].
584    #[deprecated(since = "0.17.0", note = "Renamed to `messages`.")]
585    pub fn events(&self) -> Option<&Messages<RemovedComponentEntity>> {
586        self.messages()
587    }
588
589    /// Fetch underlying [`Messages`].
590    pub fn messages(&self) -> Option<&Messages<RemovedComponentEntity>> {
591        self.message_sets.get(self.component_id.get())
592    }
593
594    /// Destructures to get a mutable reference to the `MessageCursor`
595    /// and a reference to `Messages`.
596    ///
597    /// This is necessary since Rust can't detect destructuring through methods and most
598    /// usecases of the reader uses the `Messages` as well.
599    pub fn reader_mut_with_messages(
600        &mut self,
601    ) -> Option<(
602        &mut RemovedComponentReader<T>,
603        &Messages<RemovedComponentEntity>,
604    )> {
605        self.message_sets
606            .get(self.component_id.get())
607            .map(|messages| (&mut *self.reader, messages))
608    }
609
610    /// Destructures to get a reference to the `MessageCursor`
611    /// and a reference to `Messages`.
612    #[deprecated(since = "0.17.0", note = "Renamed to `reader_mut_with_messages`.")]
613    pub fn reader_mut_with_events(
614        &mut self,
615    ) -> Option<(
616        &mut RemovedComponentReader<T>,
617        &Messages<RemovedComponentEntity>,
618    )> {
619        self.reader_mut_with_messages()
620    }
621
622    /// Iterates over the messages this [`RemovedComponents`] has not seen yet. This updates the
623    /// [`RemovedComponents`]'s message counter, which means subsequent message reads will not include messages
624    /// that happened before now.
625    pub fn read(&mut self) -> RemovedIter<'_> {
626        self.reader_mut_with_messages()
627            .map(|(reader, messages)| reader.read(messages).cloned())
628            .into_iter()
629            .flatten()
630            .map(RemovedComponentEntity::into)
631    }
632
633    /// Like [`read`](Self::read), except also returning the [`MessageId`] of the messages.
634    pub fn read_with_id(&mut self) -> RemovedIterWithId<'_> {
635        self.reader_mut_with_messages()
636            .map(|(reader, messages)| reader.read_with_id(messages))
637            .into_iter()
638            .flatten()
639            .map(map_id_messages)
640    }
641
642    /// Determines the number of removal messages available to be read from this [`RemovedComponents`] without consuming any.
643    pub fn len(&self) -> usize {
644        self.messages()
645            .map(|messages| self.reader.len(messages))
646            .unwrap_or(0)
647    }
648
649    /// Returns `true` if there are no messages available to read.
650    pub fn is_empty(&self) -> bool {
651        self.messages()
652            .is_none_or(|messages| self.reader.is_empty(messages))
653    }
654
655    /// Consumes all available messages.
656    ///
657    /// This means these messages will not appear in calls to [`RemovedComponents::read()`] or
658    /// [`RemovedComponents::read_with_id()`] and [`RemovedComponents::is_empty()`] will return `true`.
659    pub fn clear(&mut self) {
660        if let Some((reader, messages)) = self.reader_mut_with_messages() {
661            reader.clear(messages);
662        }
663    }
664}
665
666// SAFETY: Only reads World removed component messages
667unsafe impl<'a> ReadOnlySystemParam for &'a RemovedComponentMessages {}
668
669// SAFETY: no component value access.
670unsafe impl<'a> SystemParam for &'a RemovedComponentMessages {
671    type State = ();
672    type Item<'w, 's> = &'w RemovedComponentMessages;
673
674    fn init_state(_world: &mut World) -> Self::State {}
675
676    fn init_access(
677        _state: &Self::State,
678        _system_meta: &mut SystemMeta,
679        _component_access_set: &mut FilteredAccessSet,
680        _world: &mut World,
681    ) {
682    }
683
684    #[inline]
685    unsafe fn get_param<'w, 's>(
686        _state: &'s mut Self::State,
687        _system_meta: &SystemMeta,
688        world: UnsafeWorldCell<'w>,
689        _change_tick: Tick,
690    ) -> Self::Item<'w, 's> {
691        world.removed_components()
692    }
693}