bevy_ecs/world/entity_access/
entry.rs

1use crate::{
2    component::{Component, Mutable},
3    world::{EntityWorldMut, Mut},
4};
5
6use core::marker::PhantomData;
7
8/// A view into a single entity and component in a world, which may either be vacant or occupied.
9///
10/// This `enum` can only be constructed from the [`entry`] method on [`EntityWorldMut`].
11///
12/// [`entry`]: EntityWorldMut::entry
13pub enum ComponentEntry<'w, 'a, T: Component> {
14    /// An occupied entry.
15    Occupied(OccupiedComponentEntry<'w, 'a, T>),
16    /// A vacant entry.
17    Vacant(VacantComponentEntry<'w, 'a, T>),
18}
19
20impl<'w, 'a, T: Component<Mutability = Mutable>> ComponentEntry<'w, 'a, T> {
21    /// Provides in-place mutable access to an occupied entry.
22    ///
23    /// # Examples
24    ///
25    /// ```
26    /// # use bevy_ecs::prelude::*;
27    /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
28    /// struct Comp(u32);
29    ///
30    /// # let mut world = World::new();
31    /// let mut entity = world.spawn(Comp(0));
32    ///
33    /// entity.entry::<Comp>().and_modify(|mut c| c.0 += 1);
34    /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 1);
35    /// ```
36    #[inline]
37    pub fn and_modify<F: FnOnce(Mut<'_, T>)>(self, f: F) -> Self {
38        match self {
39            ComponentEntry::Occupied(mut entry) => {
40                f(entry.get_mut());
41                ComponentEntry::Occupied(entry)
42            }
43            ComponentEntry::Vacant(entry) => ComponentEntry::Vacant(entry),
44        }
45    }
46}
47
48impl<'w, 'a, T: Component> ComponentEntry<'w, 'a, T> {
49    /// Replaces the component of the entry, and returns an [`OccupiedComponentEntry`].
50    ///
51    /// # Examples
52    ///
53    /// ```
54    /// # use bevy_ecs::prelude::*;
55    /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
56    /// struct Comp(u32);
57    ///
58    /// # let mut world = World::new();
59    /// let mut entity = world.spawn_empty();
60    ///
61    /// let entry = entity.entry().insert_entry(Comp(4));
62    /// assert_eq!(entry.get(), &Comp(4));
63    ///
64    /// let entry = entity.entry().insert_entry(Comp(2));
65    /// assert_eq!(entry.get(), &Comp(2));
66    /// ```
67    #[inline]
68    pub fn insert_entry(self, component: T) -> OccupiedComponentEntry<'w, 'a, T> {
69        match self {
70            ComponentEntry::Occupied(mut entry) => {
71                entry.insert(component);
72                entry
73            }
74            ComponentEntry::Vacant(entry) => entry.insert(component),
75        }
76    }
77
78    /// Ensures the entry has this component by inserting the given default if empty, and
79    /// returns a mutable reference to this component in the entry.
80    ///
81    /// # Examples
82    ///
83    /// ```
84    /// # use bevy_ecs::prelude::*;
85    /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
86    /// struct Comp(u32);
87    ///
88    /// # let mut world = World::new();
89    /// let mut entity = world.spawn_empty();
90    ///
91    /// entity.entry().or_insert(Comp(4));
92    /// # let entity_id = entity.id();
93    /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 4);
94    ///
95    /// # let mut entity = world.get_entity_mut(entity_id).unwrap();
96    /// entity.entry().or_insert(Comp(15)).into_mut().0 *= 2;
97    /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 8);
98    /// ```
99    #[inline]
100    pub fn or_insert(self, default: T) -> OccupiedComponentEntry<'w, 'a, T> {
101        match self {
102            ComponentEntry::Occupied(entry) => entry,
103            ComponentEntry::Vacant(entry) => entry.insert(default),
104        }
105    }
106
107    /// Ensures the entry has this component by inserting the result of the default function if
108    /// empty, and returns a mutable reference to this component in the entry.
109    ///
110    /// # Examples
111    ///
112    /// ```
113    /// # use bevy_ecs::prelude::*;
114    /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
115    /// struct Comp(u32);
116    ///
117    /// # let mut world = World::new();
118    /// let mut entity = world.spawn_empty();
119    ///
120    /// entity.entry().or_insert_with(|| Comp(4));
121    /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 4);
122    /// ```
123    #[inline]
124    pub fn or_insert_with<F: FnOnce() -> T>(self, default: F) -> OccupiedComponentEntry<'w, 'a, T> {
125        match self {
126            ComponentEntry::Occupied(entry) => entry,
127            ComponentEntry::Vacant(entry) => entry.insert(default()),
128        }
129    }
130}
131
132impl<'w, 'a, T: Component + Default> ComponentEntry<'w, 'a, T> {
133    /// Ensures the entry has this component by inserting the default value if empty, and
134    /// returns a mutable reference to this component in the entry.
135    ///
136    /// # Examples
137    ///
138    /// ```
139    /// # use bevy_ecs::prelude::*;
140    /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
141    /// struct Comp(u32);
142    ///
143    /// # let mut world = World::new();
144    /// let mut entity = world.spawn_empty();
145    ///
146    /// entity.entry::<Comp>().or_default();
147    /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 0);
148    /// ```
149    #[inline]
150    pub fn or_default(self) -> OccupiedComponentEntry<'w, 'a, T> {
151        match self {
152            ComponentEntry::Occupied(entry) => entry,
153            ComponentEntry::Vacant(entry) => entry.insert(Default::default()),
154        }
155    }
156}
157
158/// A view into an occupied entry in a [`EntityWorldMut`]. It is part of the [`OccupiedComponentEntry`] enum.
159///
160/// The contained entity must have the component type parameter if we have this struct.
161pub struct OccupiedComponentEntry<'w, 'a, T: Component> {
162    pub(crate) entity_world: &'a mut EntityWorldMut<'w>,
163    pub(crate) _marker: PhantomData<T>,
164}
165
166impl<'w, 'a, T: Component> OccupiedComponentEntry<'w, 'a, T> {
167    /// Gets a reference to the component in the entry.
168    ///
169    /// # Examples
170    ///
171    /// ```
172    /// # use bevy_ecs::{prelude::*, world::ComponentEntry};
173    /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
174    /// struct Comp(u32);
175    ///
176    /// # let mut world = World::new();
177    /// let mut entity = world.spawn(Comp(5));
178    ///
179    /// if let ComponentEntry::Occupied(o) = entity.entry::<Comp>() {
180    ///     assert_eq!(o.get().0, 5);
181    /// }
182    /// ```
183    #[inline]
184    pub fn get(&self) -> &T {
185        // This shouldn't panic because if we have an OccupiedComponentEntry the component must exist.
186        self.entity_world.get::<T>().unwrap()
187    }
188
189    /// Replaces the component of the entry.
190    ///
191    /// # Examples
192    ///
193    /// ```
194    /// # use bevy_ecs::{prelude::*, world::ComponentEntry};
195    /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
196    /// struct Comp(u32);
197    ///
198    /// # let mut world = World::new();
199    /// let mut entity = world.spawn(Comp(5));
200    ///
201    /// if let ComponentEntry::Occupied(mut o) = entity.entry::<Comp>() {
202    ///     o.insert(Comp(10));
203    /// }
204    ///
205    /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 10);
206    /// ```
207    #[inline]
208    pub fn insert(&mut self, component: T) {
209        self.entity_world.insert(component);
210    }
211
212    /// Removes the component from the entry and returns it.
213    ///
214    /// # Examples
215    ///
216    /// ```
217    /// # use bevy_ecs::{prelude::*, world::ComponentEntry};
218    /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
219    /// struct Comp(u32);
220    ///
221    /// # let mut world = World::new();
222    /// let mut entity = world.spawn(Comp(5));
223    ///
224    /// if let ComponentEntry::Occupied(o) = entity.entry::<Comp>() {
225    ///     assert_eq!(o.take(), Comp(5));
226    /// }
227    ///
228    /// assert_eq!(world.query::<&Comp>().iter(&world).len(), 0);
229    /// ```
230    #[inline]
231    pub fn take(self) -> T {
232        // This shouldn't panic because if we have an OccupiedComponentEntry the component must exist.
233        self.entity_world.take().unwrap()
234    }
235}
236
237impl<'w, 'a, T: Component<Mutability = Mutable>> OccupiedComponentEntry<'w, 'a, T> {
238    /// Gets a mutable reference to the component in the entry.
239    ///
240    /// If you need a reference to the [`OccupiedComponentEntry`] which may outlive the destruction of
241    /// the [`OccupiedComponentEntry`] value, see [`into_mut`].
242    ///
243    /// [`into_mut`]: Self::into_mut
244    ///
245    /// # Examples
246    ///
247    /// ```
248    /// # use bevy_ecs::{prelude::*, world::ComponentEntry};
249    /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
250    /// struct Comp(u32);
251    ///
252    /// # let mut world = World::new();
253    /// let mut entity = world.spawn(Comp(5));
254    ///
255    /// if let ComponentEntry::Occupied(mut o) = entity.entry::<Comp>() {
256    ///     o.get_mut().0 += 10;
257    ///     assert_eq!(o.get().0, 15);
258    ///
259    ///     // We can use the same Entry multiple times.
260    ///     o.get_mut().0 += 2
261    /// }
262    ///
263    /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 17);
264    /// ```
265    #[inline]
266    pub fn get_mut(&mut self) -> Mut<'_, T> {
267        // This shouldn't panic because if we have an OccupiedComponentEntry the component must exist.
268        self.entity_world.get_mut::<T>().unwrap()
269    }
270
271    /// Converts the [`OccupiedComponentEntry`] into a mutable reference to the value in the entry with
272    /// a lifetime bound to the `EntityWorldMut`.
273    ///
274    /// If you need multiple references to the [`OccupiedComponentEntry`], see [`get_mut`].
275    ///
276    /// [`get_mut`]: Self::get_mut
277    ///
278    /// # Examples
279    ///
280    /// ```
281    /// # use bevy_ecs::{prelude::*, world::ComponentEntry};
282    /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
283    /// struct Comp(u32);
284    ///
285    /// # let mut world = World::new();
286    /// let mut entity = world.spawn(Comp(5));
287    ///
288    /// if let ComponentEntry::Occupied(o) = entity.entry::<Comp>() {
289    ///     o.into_mut().0 += 10;
290    /// }
291    ///
292    /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 15);
293    /// ```
294    #[inline]
295    pub fn into_mut(self) -> Mut<'a, T> {
296        // This shouldn't panic because if we have an OccupiedComponentEntry the component must exist.
297        self.entity_world.get_mut().unwrap()
298    }
299}
300
301/// A view into a vacant entry in a [`EntityWorldMut`]. It is part of the [`ComponentEntry`] enum.
302pub struct VacantComponentEntry<'w, 'a, T: Component> {
303    pub(crate) entity_world: &'a mut EntityWorldMut<'w>,
304    pub(crate) _marker: PhantomData<T>,
305}
306
307impl<'w, 'a, T: Component> VacantComponentEntry<'w, 'a, T> {
308    /// Inserts the component into the [`VacantComponentEntry`] and returns an [`OccupiedComponentEntry`].
309    ///
310    /// # Examples
311    ///
312    /// ```
313    /// # use bevy_ecs::{prelude::*, world::ComponentEntry};
314    /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)]
315    /// struct Comp(u32);
316    ///
317    /// # let mut world = World::new();
318    /// let mut entity = world.spawn_empty();
319    ///
320    /// if let ComponentEntry::Vacant(v) = entity.entry::<Comp>() {
321    ///     v.insert(Comp(10));
322    /// }
323    ///
324    /// assert_eq!(world.query::<&Comp>().single(&world).unwrap().0, 10);
325    /// ```
326    #[inline]
327    pub fn insert(self, component: T) -> OccupiedComponentEntry<'w, 'a, T> {
328        self.entity_world.insert(component);
329        OccupiedComponentEntry {
330            entity_world: self.entity_world,
331            _marker: PhantomData,
332        }
333    }
334}