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}