From 7dc910ae462a4d4fcb6095b3cad7222f2b4dd5c5 Mon Sep 17 00:00:00 2001 From: William Rose Date: Sun, 19 Nov 2023 23:37:44 +0000 Subject: [PATCH 01/20] Added `Entry`, `OccupiedEntry` and `VacantEntry` --- crates/bevy_ecs/src/world/entity_ref.rs | 31 ++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 274daeed05547..b6d8518584a09 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -10,7 +10,7 @@ use crate::{ }; use bevy_ptr::{OwningPtr, Ptr}; use bevy_utils::tracing::debug; -use std::any::TypeId; +use std::{any::TypeId, marker::PhantomData}; use super::{unsafe_world_cell::UnsafeEntityCell, Ref}; @@ -1032,6 +1032,35 @@ impl<'w> EntityWorldMut<'w> { pub fn update_location(&mut self) { self.location = self.world.entities().get(self.entity).unwrap(); } + + pub fn entry<'a, T: Component>(&'a mut self) -> Entry<'w, 'a, T> { + if let Some(_) = self.get::() { + Entry::Occupied(OccupiedEntry { + _marker: PhantomData::default(), + entity_world: self, + }) + } else { + Entry::Vacant(VacantEntry { + _marker: PhantomData::default(), + entity_world: self, + }) + } + } +} + +pub enum Entry<'w, 'a, T: Component> { + Occupied(OccupiedEntry<'w, 'a, T>), + Vacant(VacantEntry<'w, 'a, T>), +} + +pub struct OccupiedEntry<'w, 'a, T: Component> { + _marker: PhantomData, + entity_world: &'a mut EntityWorldMut<'w>, +} + +pub struct VacantEntry<'w, 'a, T: Component> { + _marker: PhantomData, + entity_world: &'a mut EntityWorldMut<'w>, } /// Inserts a dynamic [`Bundle`] into the entity. From d5c0e23bfd840ad3403d36d18a798dc33667dc4a Mon Sep 17 00:00:00 2001 From: William Rose Date: Sun, 19 Nov 2023 23:39:08 +0000 Subject: [PATCH 02/20] Added Entry.add_modify which uses OccupiedEntry.get_mut, which does lifetime transmutation with questionable safety, question for the future --- crates/bevy_ecs/src/world/entity_ref.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index b6d8518584a09..36d932a42e28a 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1053,11 +1053,32 @@ pub enum Entry<'w, 'a, T: Component> { Vacant(VacantEntry<'w, 'a, T>), } +impl<'w, 'a, T: Component> Entry<'w, 'a, T> { + #[inline] + pub fn and_modify)>(self, f: F) -> Self { + match self { + Entry::Occupied(mut entry) => { + f(entry.get_mut()); + Entry::Occupied(entry) + } + Entry::Vacant(entry) => Entry::Vacant(entry), + } + } +} pub struct OccupiedEntry<'w, 'a, T: Component> { _marker: PhantomData, entity_world: &'a mut EntityWorldMut<'w>, } +impl<'a, T: Component> OccupiedEntry<'_, 'a, T> { + #[inline] + pub fn get_mut(&mut self) -> Mut<'a, T> { + // TODO: YUCKITY YUCK + // SAFETY: If we have an OccupiedEntry the component must exist. + unsafe { std::mem::transmute(self.entity_world.get_mut::().unwrap_unchecked()) } + } +} + pub struct VacantEntry<'w, 'a, T: Component> { _marker: PhantomData, entity_world: &'a mut EntityWorldMut<'w>, From 17b924eb25c0c53d5a8ea43659dc941a2ace36e0 Mon Sep 17 00:00:00 2001 From: William Rose Date: Sun, 19 Nov 2023 23:40:05 +0000 Subject: [PATCH 03/20] Added Entry.or_default, using OccupiedEntry.into_mut and VacantEntry.insert (more questionable transmutation) --- crates/bevy_ecs/src/world/entity_ref.rs | 26 +++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 36d932a42e28a..eaad8b447ff1e 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1065,6 +1065,16 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { } } } + +impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> { + #[inline] + pub fn or_default(self) -> Mut<'a, T> { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(mut entry) => entry.insert(Default::default()), + } + } +} pub struct OccupiedEntry<'w, 'a, T: Component> { _marker: PhantomData, entity_world: &'a mut EntityWorldMut<'w>, @@ -1077,6 +1087,12 @@ impl<'a, T: Component> OccupiedEntry<'_, 'a, T> { // SAFETY: If we have an OccupiedEntry the component must exist. unsafe { std::mem::transmute(self.entity_world.get_mut::().unwrap_unchecked()) } } + + #[inline] + pub fn into_mut(self) -> Mut<'a, T> { + // SAFETY: If we have an OccupiedEntry the component must exist. + unsafe { self.entity_world.get_mut().unwrap_unchecked() } + } } pub struct VacantEntry<'w, 'a, T: Component> { @@ -1084,6 +1100,16 @@ pub struct VacantEntry<'w, 'a, T: Component> { entity_world: &'a mut EntityWorldMut<'w>, } +impl<'a, T: Component> VacantEntry<'_, 'a, T> { + #[inline] + pub fn insert(&mut self, component: T) -> Mut<'a, T> { + self.entity_world.insert(component); + // TODO: Again, yuck + // SAFETY: We just added this component. + unsafe { std::mem::transmute(self.entity_world.get_mut::().unwrap_unchecked()) } + } +} + /// Inserts a dynamic [`Bundle`] into the entity. /// /// # Safety From 808e2b1b59ca74bb3ae68b2a75afb921b212965d Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 00:22:44 +0000 Subject: [PATCH 04/20] Added Entry.insert_entry --- crates/bevy_ecs/src/world/entity_ref.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index eaad8b447ff1e..e50d2cfd5486d 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1064,6 +1064,20 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { Entry::Vacant(entry) => Entry::Vacant(entry), } } + + #[inline] + pub fn insert_entry(self, component: T) -> OccupiedEntry<'w, 'a, T> { + match self { + Entry::Occupied(entry) => entry, + Entry::Vacant(mut entry) => { + entry.insert(component); + OccupiedEntry { + _marker: PhantomData::default(), + entity_world: entry.entity_world, + } + } + } + } } impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> { @@ -1075,6 +1089,7 @@ impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> { } } } + pub struct OccupiedEntry<'w, 'a, T: Component> { _marker: PhantomData, entity_world: &'a mut EntityWorldMut<'w>, From 35804b05d8d01674d46e181b79d839b44348cf6d Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 00:23:01 +0000 Subject: [PATCH 05/20] Added Entry.or_insert --- crates/bevy_ecs/src/world/entity_ref.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index e50d2cfd5486d..6ef2f006ca669 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1078,6 +1078,14 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { } } } + + #[inline] + pub fn or_insert(self, default: T) -> Mut<'a, T> { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(mut entry) => entry.insert(default), + } + } } impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> { From 568cfca3ac63a80de2b6cfe1207f73f6029c74bd Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 00:23:11 +0000 Subject: [PATCH 06/20] Added Entry.or_insert_with --- crates/bevy_ecs/src/world/entity_ref.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 6ef2f006ca669..0e215ad40fc8f 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1086,6 +1086,14 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { Entry::Vacant(mut entry) => entry.insert(default), } } + + #[inline] + pub fn or_insert_with T>(self, default: F) -> Mut<'a, T> { + match self { + Entry::Occupied(entry) => entry.into_mut(), + Entry::Vacant(mut entry) => entry.insert(default()), + } + } } impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> { From a68f11407413b185756a2089ab395e5b59545699 Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 00:45:45 +0000 Subject: [PATCH 07/20] Fixed `Entry.insert_entry` so that it will change the value if Occupied (otherwise we should be using `or_insert`) --- crates/bevy_ecs/src/world/entity_ref.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 0e215ad40fc8f..c5e8021415df8 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1068,14 +1068,11 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { #[inline] pub fn insert_entry(self, component: T) -> OccupiedEntry<'w, 'a, T> { match self { - Entry::Occupied(entry) => entry, - Entry::Vacant(mut entry) => { + Entry::Occupied(mut entry) => { entry.insert(component); - OccupiedEntry { - _marker: PhantomData::default(), - entity_world: entry.entity_world, - } + entry } + Entry::Vacant(entry) => entry.insert_entry(component), } } From fa5ed2bffc5a356073b721d761c8fd49cb956a49 Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 00:46:19 +0000 Subject: [PATCH 08/20] Fixed lifetimes and signatures to avoid the insane lifetime alchemy --- crates/bevy_ecs/src/world/entity_ref.rs | 34 +++++++++++++++++-------- 1 file changed, 23 insertions(+), 11 deletions(-) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index c5e8021415df8..8cbc29e562bae 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1055,7 +1055,7 @@ pub enum Entry<'w, 'a, T: Component> { impl<'w, 'a, T: Component> Entry<'w, 'a, T> { #[inline] - pub fn and_modify)>(self, f: F) -> Self { + pub fn and_modify)>(self, f: F) -> Self { match self { Entry::Occupied(mut entry) => { f(entry.get_mut()); @@ -1080,7 +1080,7 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { pub fn or_insert(self, default: T) -> Mut<'a, T> { match self { Entry::Occupied(entry) => entry.into_mut(), - Entry::Vacant(mut entry) => entry.insert(default), + Entry::Vacant(entry) => entry.insert(default), } } @@ -1088,7 +1088,7 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { pub fn or_insert_with T>(self, default: F) -> Mut<'a, T> { match self { Entry::Occupied(entry) => entry.into_mut(), - Entry::Vacant(mut entry) => entry.insert(default()), + Entry::Vacant(entry) => entry.insert(default()), } } } @@ -1098,7 +1098,7 @@ impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> { pub fn or_default(self) -> Mut<'a, T> { match self { Entry::Occupied(entry) => entry.into_mut(), - Entry::Vacant(mut entry) => entry.insert(Default::default()), + Entry::Vacant(entry) => entry.insert(Default::default()), } } } @@ -1110,10 +1110,9 @@ pub struct OccupiedEntry<'w, 'a, T: Component> { impl<'a, T: Component> OccupiedEntry<'_, 'a, T> { #[inline] - pub fn get_mut(&mut self) -> Mut<'a, T> { - // TODO: YUCKITY YUCK + pub fn get_mut(&mut self) -> Mut<'_, T> { // SAFETY: If we have an OccupiedEntry the component must exist. - unsafe { std::mem::transmute(self.entity_world.get_mut::().unwrap_unchecked()) } + unsafe { self.entity_world.get_mut::().unwrap_unchecked() } } #[inline] @@ -1121,6 +1120,11 @@ impl<'a, T: Component> OccupiedEntry<'_, 'a, T> { // SAFETY: If we have an OccupiedEntry the component must exist. unsafe { self.entity_world.get_mut().unwrap_unchecked() } } + + #[inline] + pub fn insert(&mut self, component: T) { + self.entity_world.insert(component); + } } pub struct VacantEntry<'w, 'a, T: Component> { @@ -1128,13 +1132,21 @@ pub struct VacantEntry<'w, 'a, T: Component> { entity_world: &'a mut EntityWorldMut<'w>, } -impl<'a, T: Component> VacantEntry<'_, 'a, T> { +impl<'w, 'a, T: Component> VacantEntry<'w, 'a, T> { #[inline] - pub fn insert(&mut self, component: T) -> Mut<'a, T> { + pub fn insert(self, component: T) -> Mut<'a, T> { self.entity_world.insert(component); - // TODO: Again, yuck // SAFETY: We just added this component. - unsafe { std::mem::transmute(self.entity_world.get_mut::().unwrap_unchecked()) } + unsafe { self.entity_world.get_mut::().unwrap_unchecked() } + } + + #[inline] + pub fn insert_entry(self, component: T) -> OccupiedEntry<'w, 'a, T> { + self.entity_world.insert(component); + OccupiedEntry { + _marker: PhantomData::default(), + entity_world: self.entity_world, + } } } From 215ab4cc94204a46804cee9ad7bad9dd0b5cacb4 Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 01:01:52 +0000 Subject: [PATCH 09/20] Added OccupiedEntry.get and OccupiedEntry.take --- crates/bevy_ecs/src/world/entity_ref.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 8cbc29e562bae..b0a200517e14c 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1108,7 +1108,13 @@ pub struct OccupiedEntry<'w, 'a, T: Component> { entity_world: &'a mut EntityWorldMut<'w>, } -impl<'a, T: Component> OccupiedEntry<'_, 'a, T> { +impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { + #[inline] + pub fn get(&self) -> &T { + // SAFETY: If we have an OccupiedEntry the component must exist. + unsafe { self.entity_world.get::().unwrap_unchecked() } + } + #[inline] pub fn get_mut(&mut self) -> Mut<'_, T> { // SAFETY: If we have an OccupiedEntry the component must exist. @@ -1125,6 +1131,12 @@ impl<'a, T: Component> OccupiedEntry<'_, 'a, T> { pub fn insert(&mut self, component: T) { self.entity_world.insert(component); } + + #[inline] + pub fn take(self) -> T { + // SAFETY: If we have an OccupiedEntry the component must exist. + unsafe { self.entity_world.take().unwrap_unchecked() } + } } pub struct VacantEntry<'w, 'a, T: Component> { From 1e27ce213d198825b76ebe58096e6d24b3756128 Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 01:03:24 +0000 Subject: [PATCH 10/20] Moved _marker to after entity_world --- crates/bevy_ecs/src/world/entity_ref.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index b0a200517e14c..8ad0e8a2e869b 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1036,13 +1036,13 @@ impl<'w> EntityWorldMut<'w> { pub fn entry<'a, T: Component>(&'a mut self) -> Entry<'w, 'a, T> { if let Some(_) = self.get::() { Entry::Occupied(OccupiedEntry { - _marker: PhantomData::default(), entity_world: self, + _marker: PhantomData::default(), }) } else { Entry::Vacant(VacantEntry { - _marker: PhantomData::default(), entity_world: self, + _marker: PhantomData::default(), }) } } @@ -1104,8 +1104,8 @@ impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> { } pub struct OccupiedEntry<'w, 'a, T: Component> { - _marker: PhantomData, entity_world: &'a mut EntityWorldMut<'w>, + _marker: PhantomData, } impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { @@ -1140,8 +1140,8 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { } pub struct VacantEntry<'w, 'a, T: Component> { - _marker: PhantomData, entity_world: &'a mut EntityWorldMut<'w>, + _marker: PhantomData, } impl<'w, 'a, T: Component> VacantEntry<'w, 'a, T> { @@ -1156,8 +1156,8 @@ impl<'w, 'a, T: Component> VacantEntry<'w, 'a, T> { pub fn insert_entry(self, component: T) -> OccupiedEntry<'w, 'a, T> { self.entity_world.insert(component); OccupiedEntry { - _marker: PhantomData::default(), entity_world: self.entity_world, + _marker: PhantomData::default(), } } } From d936215d457df692a044f2e96edd06f8af23df98 Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 01:21:43 +0000 Subject: [PATCH 11/20] Added basic docs (no examples yet) --- crates/bevy_ecs/src/world/entity_ref.rs | 27 +++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 8ad0e8a2e869b..b394b34ec5e70 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1033,6 +1033,7 @@ impl<'w> EntityWorldMut<'w> { self.location = self.world.entities().get(self.entity).unwrap(); } + /// Gets an Entry into the world for this entity and component for in-place manipulation. pub fn entry<'a, T: Component>(&'a mut self) -> Entry<'w, 'a, T> { if let Some(_) = self.get::() { Entry::Occupied(OccupiedEntry { @@ -1048,12 +1049,16 @@ impl<'w> EntityWorldMut<'w> { } } +/// A view into a single entity and component in a world, which may either be vacant or occupied. +/// +/// This `enum` is constructed from the [`entry`] method on [`WorldEntityMut`]. pub enum Entry<'w, 'a, T: Component> { Occupied(OccupiedEntry<'w, 'a, T>), Vacant(VacantEntry<'w, 'a, T>), } impl<'w, 'a, T: Component> Entry<'w, 'a, T> { + /// Provides in-place mutable access to an occupied entry. #[inline] pub fn and_modify)>(self, f: F) -> Self { match self { @@ -1065,6 +1070,7 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { } } + /// Sets the value of the entry, and returns an [`OccupiedEntry`]. #[inline] pub fn insert_entry(self, component: T) -> OccupiedEntry<'w, 'a, T> { match self { @@ -1076,6 +1082,8 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { } } + /// Ensures the entry has this component by inserting the default if empty, and returns a + /// mutable reference to this component in the entry. #[inline] pub fn or_insert(self, default: T) -> Mut<'a, T> { match self { @@ -1084,6 +1092,8 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { } } + /// Ensures the entry has this component by inserting the result of the default function if + /// empty, and returns a mutable reference to this component in the entry. #[inline] pub fn or_insert_with T>(self, default: F) -> Mut<'a, T> { match self { @@ -1094,6 +1104,8 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { } impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> { + /// Ensures the entry has this component by inserting the default value if empty, and + /// returns a mutable reference to this component in the entry. #[inline] pub fn or_default(self) -> Mut<'a, T> { match self { @@ -1103,35 +1115,47 @@ impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> { } } +/// A view into an occupied entry in a [`WorldEntityMut`]. It is part of the [`Entry`] enum. pub struct OccupiedEntry<'w, 'a, T: Component> { entity_world: &'a mut EntityWorldMut<'w>, _marker: PhantomData, } impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { + /// Gets a reference to the component in the entry. #[inline] pub fn get(&self) -> &T { // SAFETY: If we have an OccupiedEntry the component must exist. unsafe { self.entity_world.get::().unwrap_unchecked() } } + /// Gets a mutable reference to the component in the entry. + /// + /// If you need a reference to the `OccupiedEntry` which may outlive the destruction of + /// the `Entry` value, see [`into_mut`]. #[inline] pub fn get_mut(&mut self) -> Mut<'_, T> { // SAFETY: If we have an OccupiedEntry the component must exist. unsafe { self.entity_world.get_mut::().unwrap_unchecked() } } + /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry with + /// a lifetime bound to the `EntityWorldMut`. + /// + /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. #[inline] pub fn into_mut(self) -> Mut<'a, T> { // SAFETY: If we have an OccupiedEntry the component must exist. unsafe { self.entity_world.get_mut().unwrap_unchecked() } } + /// Replaces the component of the entry. #[inline] pub fn insert(&mut self, component: T) { self.entity_world.insert(component); } + /// Removes the component from the entry and returns its value. #[inline] pub fn take(self) -> T { // SAFETY: If we have an OccupiedEntry the component must exist. @@ -1139,12 +1163,14 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { } } +/// A view into a vacant entry in a [`WorldEntityMut`]. It is part of the [`Entry`] enum. pub struct VacantEntry<'w, 'a, T: Component> { entity_world: &'a mut EntityWorldMut<'w>, _marker: PhantomData, } impl<'w, 'a, T: Component> VacantEntry<'w, 'a, T> { + /// Inserts the component into the `VacantEntry` and returns a mutable reference to it. #[inline] pub fn insert(self, component: T) -> Mut<'a, T> { self.entity_world.insert(component); @@ -1152,6 +1178,7 @@ impl<'w, 'a, T: Component> VacantEntry<'w, 'a, T> { unsafe { self.entity_world.get_mut::().unwrap_unchecked() } } + /// Inserts the component into the `VacantEntry` and returns an `OccupiedEntry`. #[inline] pub fn insert_entry(self, component: T) -> OccupiedEntry<'w, 'a, T> { self.entity_world.insert(component); From 6636a5293cbd2bf946e68919e4773d44b5aa71cb Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 01:41:26 +0000 Subject: [PATCH 12/20] Fixed some doc-links and made these types public so they show up in the documentation --- crates/bevy_ecs/src/world/entity_ref.rs | 14 +++++++++++--- crates/bevy_ecs/src/world/mod.rs | 2 +- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index b394b34ec5e70..9d99246f6e63b 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1051,9 +1051,13 @@ impl<'w> EntityWorldMut<'w> { /// A view into a single entity and component in a world, which may either be vacant or occupied. /// -/// This `enum` is constructed from the [`entry`] method on [`WorldEntityMut`]. +/// This `enum` is constructed from the [`entry`] method on [`EntityWorldMut`]. +/// +/// [`entry`]: EntityWorldMut::entry pub enum Entry<'w, 'a, T: Component> { + /// An occupied entry. Occupied(OccupiedEntry<'w, 'a, T>), + /// A vacant entry. Vacant(VacantEntry<'w, 'a, T>), } @@ -1115,7 +1119,7 @@ impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> { } } -/// A view into an occupied entry in a [`WorldEntityMut`]. It is part of the [`Entry`] enum. +/// A view into an occupied entry in a [`EntityWorldMut`]. It is part of the [`Entry`] enum. pub struct OccupiedEntry<'w, 'a, T: Component> { entity_world: &'a mut EntityWorldMut<'w>, _marker: PhantomData, @@ -1133,6 +1137,8 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { /// /// If you need a reference to the `OccupiedEntry` which may outlive the destruction of /// the `Entry` value, see [`into_mut`]. + /// + /// [`into_mut`]: Self::into_mut #[inline] pub fn get_mut(&mut self) -> Mut<'_, T> { // SAFETY: If we have an OccupiedEntry the component must exist. @@ -1143,6 +1149,8 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { /// a lifetime bound to the `EntityWorldMut`. /// /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. + /// + /// [`get_mut`]: Self::get_mut #[inline] pub fn into_mut(self) -> Mut<'a, T> { // SAFETY: If we have an OccupiedEntry the component must exist. @@ -1163,7 +1171,7 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { } } -/// A view into a vacant entry in a [`WorldEntityMut`]. It is part of the [`Entry`] enum. +/// A view into a vacant entry in a [`EntityWorldMut`]. It is part of the [`Entry`] enum. pub struct VacantEntry<'w, 'a, T: Component> { entity_world: &'a mut EntityWorldMut<'w>, _marker: PhantomData, diff --git a/crates/bevy_ecs/src/world/mod.rs b/crates/bevy_ecs/src/world/mod.rs index 0919dfd6324c6..0de995257fc4d 100644 --- a/crates/bevy_ecs/src/world/mod.rs +++ b/crates/bevy_ecs/src/world/mod.rs @@ -7,7 +7,7 @@ pub mod unsafe_world_cell; mod world_cell; pub use crate::change_detection::{Mut, Ref, CHECK_TICK_THRESHOLD}; -pub use entity_ref::{EntityMut, EntityRef, EntityWorldMut}; +pub use entity_ref::{EntityMut, EntityRef, EntityWorldMut, Entry, OccupiedEntry, VacantEntry}; pub use spawn_batch::*; pub use world_cell::*; From 1ce81c272a6c70ecc81a202c62b6ff2235d52e64 Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 02:04:04 +0000 Subject: [PATCH 13/20] Added examples to all of Entry's methods --- crates/bevy_ecs/src/world/entity_ref.rs | 80 ++++++++++++++++++++++++- 1 file changed, 79 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 9d99246f6e63b..6be44d44aed7c 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1063,6 +1063,20 @@ pub enum Entry<'w, 'a, T: Component> { impl<'w, 'a, T: Component> Entry<'w, 'a, T> { /// Provides in-place mutable access to an occupied entry. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] + /// struct Comp(u32); + /// + /// # let mut world = World::new(); + /// let mut entity = world.spawn(Comp(0)); + /// + /// entity.entry::().and_modify(|mut c| c.0 += 1); + /// assert_eq!(world.query::<&Comp>().single(&world).0, 1); + /// ``` #[inline] pub fn and_modify)>(self, f: F) -> Self { match self { @@ -1074,7 +1088,24 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { } } - /// Sets the value of the entry, and returns an [`OccupiedEntry`]. + /// Replaces the component of the entry, and returns an [`OccupiedEntry`]. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] + /// struct Comp(u32); + /// + /// # let mut world = World::new(); + /// let mut entity = world.spawn_empty(); + /// + /// let entry = entity.entry().insert_entry(Comp(4)); + /// assert_eq!(entry.get(), &Comp(4)); + /// + /// let entry = entity.entry().insert_entry(Comp(2)); + /// assert_eq!(entry.get(), &Comp(2)); + /// ``` #[inline] pub fn insert_entry(self, component: T) -> OccupiedEntry<'w, 'a, T> { match self { @@ -1088,6 +1119,25 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { /// Ensures the entry has this component by inserting the default if empty, and returns a /// mutable reference to this component in the entry. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] + /// struct Comp(u32); + /// + /// # let mut world = World::new(); + /// let mut entity = world.spawn_empty(); + /// + /// entity.entry().or_insert(Comp(4)); + /// # let entity_id = entity.id(); + /// assert_eq!(world.query::<&Comp>().single(&world).0, 4); + /// + /// # let mut entity = world.get_entity_mut(entity_id).unwrap(); + /// entity.entry().or_insert(Comp(15)).0 *= 2; + /// assert_eq!(world.query::<&Comp>().single(&world).0, 8); + /// ``` #[inline] pub fn or_insert(self, default: T) -> Mut<'a, T> { match self { @@ -1098,6 +1148,20 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { /// Ensures the entry has this component by inserting the result of the default function if /// empty, and returns a mutable reference to this component in the entry. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] + /// struct Comp(u32); + /// + /// # let mut world = World::new(); + /// let mut entity = world.spawn_empty(); + /// + /// entity.entry().or_insert_with(|| Comp(4)); + /// assert_eq!(world.query::<&Comp>().single(&world).0, 4); + /// ``` #[inline] pub fn or_insert_with T>(self, default: F) -> Mut<'a, T> { match self { @@ -1110,6 +1174,20 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> { /// Ensures the entry has this component by inserting the default value if empty, and /// returns a mutable reference to this component in the entry. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] + /// struct Comp(u32); + /// + /// # let mut world = World::new(); + /// let mut entity = world.spawn_empty(); + /// + /// entity.entry::().or_default(); + /// assert_eq!(world.query::<&Comp>().single(&world).0, 0); + /// ``` #[inline] pub fn or_default(self) -> Mut<'a, T> { match self { From b7ebc408bb82185f0c85e4589f59cc00b66e43db Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 02:28:23 +0000 Subject: [PATCH 14/20] Added examples to the methods of OccupiedEntry and VacantEntry --- crates/bevy_ecs/src/world/entity_ref.rs | 123 +++++++++++++++++++++++- 1 file changed, 122 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 6be44d44aed7c..d3cb097b4339a 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1205,6 +1205,21 @@ pub struct OccupiedEntry<'w, 'a, T: Component> { impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { /// Gets a reference to the component in the entry. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::{prelude::*, world::Entry}; + /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] + /// struct Comp(u32); + /// + /// # let mut world = World::new(); + /// let mut entity = world.spawn(Comp(5)); + /// + /// if let Entry::Occupied(o) = entity.entry::() { + /// assert_eq!(o.get().0, 5); + /// } + /// ``` #[inline] pub fn get(&self) -> &T { // SAFETY: If we have an OccupiedEntry the component must exist. @@ -1217,6 +1232,27 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { /// the `Entry` value, see [`into_mut`]. /// /// [`into_mut`]: Self::into_mut + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::{prelude::*, world::Entry}; + /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] + /// struct Comp(u32); + /// + /// # let mut world = World::new(); + /// let mut entity = world.spawn(Comp(5)); + /// + /// if let Entry::Occupied(mut o) = entity.entry::() { + /// o.get_mut().0 += 10; + /// assert_eq!(o.get().0, 15); + /// + /// // We can use the same Entry multiple times. + /// o.get_mut().0 += 2 + /// } + /// + /// assert_eq!(world.query::<&Comp>().single(&world).0, 17); + /// ``` #[inline] pub fn get_mut(&mut self) -> Mut<'_, T> { // SAFETY: If we have an OccupiedEntry the component must exist. @@ -1229,6 +1265,23 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. /// /// [`get_mut`]: Self::get_mut + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::{prelude::*, world::Entry}; + /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] + /// struct Comp(u32); + /// + /// # let mut world = World::new(); + /// let mut entity = world.spawn(Comp(5)); + /// + /// if let Entry::Occupied(o) = entity.entry::() { + /// o.into_mut().0 += 10; + /// } + /// + /// assert_eq!(world.query::<&Comp>().single(&world).0, 15); + /// ``` #[inline] pub fn into_mut(self) -> Mut<'a, T> { // SAFETY: If we have an OccupiedEntry the component must exist. @@ -1236,12 +1289,46 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { } /// Replaces the component of the entry. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::{prelude::*, world::Entry}; + /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] + /// struct Comp(u32); + /// + /// # let mut world = World::new(); + /// let mut entity = world.spawn(Comp(5)); + /// + /// if let Entry::Occupied(mut o) = entity.entry::() { + /// o.insert(Comp(10)); + /// } + /// + /// assert_eq!(world.query::<&Comp>().single(&world).0, 10); + /// ``` #[inline] pub fn insert(&mut self, component: T) { self.entity_world.insert(component); } - /// Removes the component from the entry and returns its value. + /// Removes the component from the entry and returns it. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::{prelude::*, world::Entry}; + /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] + /// struct Comp(u32); + /// + /// # let mut world = World::new(); + /// let mut entity = world.spawn(Comp(5)); + /// + /// if let Entry::Occupied(o) = entity.entry::() { + /// assert_eq!(o.take(), Comp(5)); + /// } + /// + /// assert_eq!(world.query::<&Comp>().iter(&world).len(), 0); + /// ``` #[inline] pub fn take(self) -> T { // SAFETY: If we have an OccupiedEntry the component must exist. @@ -1257,6 +1344,23 @@ pub struct VacantEntry<'w, 'a, T: Component> { impl<'w, 'a, T: Component> VacantEntry<'w, 'a, T> { /// Inserts the component into the `VacantEntry` and returns a mutable reference to it. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::{prelude::*, world::Entry}; + /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] + /// struct Comp(u32); + /// + /// # let mut world = World::new(); + /// let mut entity = world.spawn_empty(); + /// + /// if let Entry::Vacant(v) = entity.entry::() { + /// v.insert(Comp(10)); + /// } + /// + /// assert_eq!(world.query::<&Comp>().single(&world).0, 10); + /// ``` #[inline] pub fn insert(self, component: T) -> Mut<'a, T> { self.entity_world.insert(component); @@ -1265,6 +1369,23 @@ impl<'w, 'a, T: Component> VacantEntry<'w, 'a, T> { } /// Inserts the component into the `VacantEntry` and returns an `OccupiedEntry`. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::{prelude::*, world::Entry}; + /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] + /// struct Comp(u32); + /// + /// # let mut world = World::new(); + /// let mut entity = world.spawn_empty(); + /// + /// if let Entry::Vacant(v) = entity.entry::() { + /// v.insert_entry(Comp(10)); + /// } + /// + /// assert_eq!(world.query::<&Comp>().single(&world).0, 10); + /// ``` #[inline] pub fn insert_entry(self, component: T) -> OccupiedEntry<'w, 'a, T> { self.entity_world.insert(component); From 2190952e6d3ae8101f8c0bf3410cc9a00bb00bdb Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 02:48:03 +0000 Subject: [PATCH 15/20] Appeased clippy --- crates/bevy_ecs/src/world/entity_ref.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index d3cb097b4339a..18473e3c1ac6c 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1035,15 +1035,15 @@ impl<'w> EntityWorldMut<'w> { /// Gets an Entry into the world for this entity and component for in-place manipulation. pub fn entry<'a, T: Component>(&'a mut self) -> Entry<'w, 'a, T> { - if let Some(_) = self.get::() { + if self.contains::() { Entry::Occupied(OccupiedEntry { entity_world: self, - _marker: PhantomData::default(), + _marker: PhantomData, }) } else { Entry::Vacant(VacantEntry { entity_world: self, - _marker: PhantomData::default(), + _marker: PhantomData, }) } } @@ -1391,7 +1391,7 @@ impl<'w, 'a, T: Component> VacantEntry<'w, 'a, T> { self.entity_world.insert(component); OccupiedEntry { entity_world: self.entity_world, - _marker: PhantomData::default(), + _marker: PhantomData, } } } From 71e0e8106f17dfa049d5c7419faf352a671ee388 Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 02:54:17 +0000 Subject: [PATCH 16/20] Adjusted doc comment 'default' -> 'given default' --- crates/bevy_ecs/src/world/entity_ref.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 18473e3c1ac6c..e69007ea7e3c0 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1117,8 +1117,8 @@ impl<'w, 'a, T: Component> Entry<'w, 'a, T> { } } - /// Ensures the entry has this component by inserting the default if empty, and returns a - /// mutable reference to this component in the entry. + /// Ensures the entry has this component by inserting the given default if empty, and + /// returns a mutable reference to this component in the entry. /// /// # Examples /// From d69e4fa7491942c341fe0e8f716972bff755cab9 Mon Sep 17 00:00:00 2001 From: Alice Cecile Date: Mon, 20 Nov 2023 07:55:56 -0500 Subject: [PATCH 17/20] Add doc test Co-authored-by: Pascal Hertleif --- crates/bevy_ecs/src/world/entity_ref.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index e69007ea7e3c0..d081ec6c82716 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1034,6 +1034,26 @@ impl<'w> EntityWorldMut<'w> { } /// Gets an Entry into the world for this entity and component for in-place manipulation. + /// + /// The type parameter specifies which component to get. + /// + /// # Examples + /// + /// ``` + /// # use bevy_ecs::prelude::*; + /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] + /// struct Comp(u32); + /// + /// let mut world = World::new(); + /// + /// let mut entity = world.spawn(Comp(0)); + /// entity.entry::().and_modify(|mut c| c.0 += 1); + /// # assert_eq!(world.query::<&Comp>().single(&world).0, 1); + /// + /// let mut new_entity = world.spawn_empty(); + /// entity.entry().or_insert_with(|| Comp(4)); + /// # assert_eq!(world.query::<&Comp>().single(&world).0, 4); + /// ``` pub fn entry<'a, T: Component>(&'a mut self) -> Entry<'w, 'a, T> { if self.contains::() { Entry::Occupied(OccupiedEntry { From 0c989d86c88664e789fd51e3661b8d9063897d0d Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 20:04:55 +0000 Subject: [PATCH 18/20] Fixed doc-test --- crates/bevy_ecs/src/world/entity_ref.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index d081ec6c82716..e267c4127ae87 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1044,15 +1044,16 @@ impl<'w> EntityWorldMut<'w> { /// #[derive(Component, Default, Clone, Copy, Debug, PartialEq)] /// struct Comp(u32); /// - /// let mut world = World::new(); + /// # let mut world = World::new(); + /// let mut entity = world.spawn_empty(); + /// entity.entry().or_insert_with(|| Comp(4)); + /// # let entity_id = entity.id(); + /// assert_eq!(world.query::<&Comp>().single(&world).0, 4); /// - /// let mut entity = world.spawn(Comp(0)); + /// # let mut entity = world.get_entity_mut(entity_id).unwrap(); /// entity.entry::().and_modify(|mut c| c.0 += 1); - /// # assert_eq!(world.query::<&Comp>().single(&world).0, 1); + /// assert_eq!(world.query::<&Comp>().single(&world).0, 5); /// - /// let mut new_entity = world.spawn_empty(); - /// entity.entry().or_insert_with(|| Comp(4)); - /// # assert_eq!(world.query::<&Comp>().single(&world).0, 4); /// ``` pub fn entry<'a, T: Component>(&'a mut self) -> Entry<'w, 'a, T> { if self.contains::() { From 55c688baf77adfb83da32d16883d43008d50aeff Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 20:14:22 +0000 Subject: [PATCH 19/20] Adjusted doc comment and added an extra comment to `OccupiedEntry` explaining how it must be occupied before being created (it has private fields so this shouldn't be a problem for user code). --- crates/bevy_ecs/src/world/entity_ref.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index e267c4127ae87..6e2581acc4c35 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1072,7 +1072,7 @@ impl<'w> EntityWorldMut<'w> { /// A view into a single entity and component in a world, which may either be vacant or occupied. /// -/// This `enum` is constructed from the [`entry`] method on [`EntityWorldMut`]. +/// This `enum` can only be constructed from the [`entry`] method on [`EntityWorldMut`]. /// /// [`entry`]: EntityWorldMut::entry pub enum Entry<'w, 'a, T: Component> { @@ -1219,6 +1219,8 @@ impl<'w, 'a, T: Component + Default> Entry<'w, 'a, T> { } /// A view into an occupied entry in a [`EntityWorldMut`]. It is part of the [`Entry`] enum. +/// +/// The contained entity must have the component type parameter if we have this struct. pub struct OccupiedEntry<'w, 'a, T: Component> { entity_world: &'a mut EntityWorldMut<'w>, _marker: PhantomData, From 0ec411cd0578a2c7580cc6f9ffcad779cdc863bb Mon Sep 17 00:00:00 2001 From: William Rose Date: Mon, 20 Nov 2023 20:14:56 +0000 Subject: [PATCH 20/20] Replaced unwrap_unchecked with unwrap and changed safety comments to comments explaining why it should never panic. --- crates/bevy_ecs/src/world/entity_ref.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/bevy_ecs/src/world/entity_ref.rs b/crates/bevy_ecs/src/world/entity_ref.rs index 6e2581acc4c35..c94b45dad10ee 100644 --- a/crates/bevy_ecs/src/world/entity_ref.rs +++ b/crates/bevy_ecs/src/world/entity_ref.rs @@ -1245,8 +1245,8 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { /// ``` #[inline] pub fn get(&self) -> &T { - // SAFETY: If we have an OccupiedEntry the component must exist. - unsafe { self.entity_world.get::().unwrap_unchecked() } + // This shouldn't panic because if we have an OccupiedEntry the component must exist. + self.entity_world.get::().unwrap() } /// Gets a mutable reference to the component in the entry. @@ -1278,8 +1278,8 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { /// ``` #[inline] pub fn get_mut(&mut self) -> Mut<'_, T> { - // SAFETY: If we have an OccupiedEntry the component must exist. - unsafe { self.entity_world.get_mut::().unwrap_unchecked() } + // This shouldn't panic because if we have an OccupiedEntry the component must exist. + self.entity_world.get_mut::().unwrap() } /// Converts the `OccupiedEntry` into a mutable reference to the value in the entry with @@ -1307,8 +1307,8 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { /// ``` #[inline] pub fn into_mut(self) -> Mut<'a, T> { - // SAFETY: If we have an OccupiedEntry the component must exist. - unsafe { self.entity_world.get_mut().unwrap_unchecked() } + // This shouldn't panic because if we have an OccupiedEntry the component must exist. + self.entity_world.get_mut().unwrap() } /// Replaces the component of the entry. @@ -1354,8 +1354,8 @@ impl<'w, 'a, T: Component> OccupiedEntry<'w, 'a, T> { /// ``` #[inline] pub fn take(self) -> T { - // SAFETY: If we have an OccupiedEntry the component must exist. - unsafe { self.entity_world.take().unwrap_unchecked() } + // This shouldn't panic because if we have an OccupiedEntry the component must exist. + self.entity_world.take().unwrap() } } @@ -1387,8 +1387,8 @@ impl<'w, 'a, T: Component> VacantEntry<'w, 'a, T> { #[inline] pub fn insert(self, component: T) -> Mut<'a, T> { self.entity_world.insert(component); - // SAFETY: We just added this component. - unsafe { self.entity_world.get_mut::().unwrap_unchecked() } + // This shouldn't panic because we just added this component + self.entity_world.get_mut::().unwrap() } /// Inserts the component into the `VacantEntry` and returns an `OccupiedEntry`.