-
Notifications
You must be signed in to change notification settings - Fork 220
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adds StorageEntry to Storage for convenience #274
Conversation
src/storage/mod.rs
Outdated
@@ -203,6 +317,20 @@ where | |||
} | |||
} | |||
|
|||
/// Returns an entry to the component associated to the entity. | |||
/// | |||
/// Note: This does not immediately error if the entity is dead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should use Result
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are we sure? That would make this require a bit more boilerplate for this stuff then:
if let Ok(entry) = storage.entry(entity) {
entry.or_insert(component);
}
At least until we get try
to work outside of just functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And now the boilerplate is at another location
if let Some(component) = storage.entry(entity).or_insert(...) {
...
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm somewhat worried about enforcing that Entry
is only created with a live Entity
, is there a case where an entity could be deleted after you create an entry?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It can be killed atomically. But atomically killed enities are considered alive until maintenance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, I messed around with it and couldn't find an easy way to kill the entity while having an entry, so I guess it should be fine.
src/storage/mod.rs
Outdated
pub fn or_insert_with<F>(self, component: F) -> Option<&'a mut T> | ||
where F: FnOnce() -> T, | ||
{ | ||
self.or_insert(component()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole idea of the method is not to call closure unless component is required.
Instead or_insert
should be implemented as or_insert_with(|| component)
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addition to the comments below, could you please add tests which
- explicitly match the enum and
- insert by using an entry and create another entry checking if it's now occupied
@@ -203,6 +317,25 @@ where | |||
} | |||
} | |||
|
|||
/// Returns an entry to the component associated to the entity. | |||
/// |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please add a usage example here.
src/storage/mod.rs
Outdated
} | ||
|
||
/// Returns the entity of the current entry. | ||
pub fn entity(&self) -> &Entity { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason for us to give a reference to the entity?
src/storage/mod.rs
Outdated
self.or_insert_with(|| component) | ||
} | ||
|
||
/// Inserts a component using a default function. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"using a default function"? Why "default"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default should probaby be "lazily called function"
src/storage/mod.rs
Outdated
Vacant(VacantEntry<'a, 'b, T, D>), | ||
} | ||
|
||
pub enum EntryError { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This belongs into the error
module. Also, we should not have enums with just a single variant.
src/storage/mod.rs
Outdated
|
||
/// Inserts a value into the storage and returns the old one. | ||
/// | ||
/// Return value can be `None` if the entity passed in was dead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this still true? Given that we now return an error, shouldn't this return just T
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This isn't true, thought I removedid that line.
src/storage/mod.rs
Outdated
/// Removes the component from the storage and returns it. | ||
/// | ||
/// Return value can be `None` if the entity passed in was dead. | ||
pub fn remove(&mut self) -> Option<T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here.
src/storage/mod.rs
Outdated
{ | ||
/// Inserts a value into the storage and returns the old one. | ||
/// | ||
/// Return value can be `None` if the entity passed in was dead. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
a4d3065
to
72efbc5
Compare
src/error.rs
Outdated
|
||
/// Storage entry error when the request entity was dead. | ||
#[derive(Debug)] | ||
pub struct EntryIsDead(pub Entity); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why aren't you just using WrongGeneration
? And in case this actually needs its own error, it should still be representable with specs::error::Error
(see WrongGeneration
; the idea is that every error can be converted to that enum).
src/storage/mod.rs
Outdated
D: Deref<Target = MaskedStorage<T>>, | ||
{ | ||
/// Get a reference to the component associated with the entity. | ||
pub fn get(&self) -> Option<&T> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the entry is occupied, how could this call return None
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, missed that one when removing all the others.
src/storage/mod.rs
Outdated
pub fn get_mut(self) -> &'a mut T { | ||
match self.storage.get_mut(self.entity) { | ||
Some(component) => component, | ||
None => { panic!("`OccupiedEntry` on an entity without a component."); }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for {
and }
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know why the coverage goes down: coveralls thinks that this is an uncovered line, but that's not the case. Speaking of which, this should use unreachable!
.
src/storage/mod.rs
Outdated
pub fn remove(self) -> T { | ||
match self.storage.remove(self.entity) { | ||
Some(old) => old, | ||
None => { panic!("`OccupiedEntry` on an entity without a component."); }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meh, the whole sense of Entry API is that you usually don't do any checks twice which is the case for all these methods :(
src/storage/mod.rs
Outdated
/// Inserts a value into the storage. | ||
pub fn insert(self, component: T) -> &'a mut T { | ||
match self.storage.insert(self.entity, component) { | ||
InsertResult::Updated(_) => { panic!("`VacantEntry` on an entity with a component."); }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No need for {
and }
src/storage/mod.rs
Outdated
None => { panic!("Storage insertion into entity {:?} failed on `VacantEntry`", self.entity); }, | ||
} | ||
}, | ||
InsertResult::EntityIsDead(_) => { panic!("`VacantEntry` on a dead entity: {:?}.", self.entity); }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here
src/storage/mod.rs
Outdated
/// | ||
/// Behaves somewhat similarly to `std::collections::HashMap`'s entry api. | ||
/// | ||
///## Example |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing space
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had them previously and it makes them not render correctly for whatever reason.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's strange; our other examples have spaces, too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, seems to work now?
src/storage/mod.rs
Outdated
///## Example | ||
/// | ||
/// ```rust | ||
///# extern crate specs; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
missing space in this and the following lines
Are you still interested in this feature? I'm not sure now if I should be waiting for it, that's why I'm asking. |
I'll finish it up, just kind of got carried away with other stuff |
5c093ae
to
904003e
Compare
src/storage/mod.rs
Outdated
|
||
/// Inserts a value into the storage and returns the old one. | ||
pub fn insert(&mut self, mut component: T) -> T { | ||
std::mem::swap(&mut component, unsafe { self.storage.data.inner.get_mut(self.entity.id()) }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could use self.get_mut()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Annoyingly I can't figure out the lifetimes that would work for get_mut
that allows just &mut self
, so I can't get that to work properly.
} | ||
|
||
/// Removes the component from the storage and returns it. | ||
pub fn remove(self) -> T { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
random impractical thought: would be fun to return (T, VacantEntry<...>)
src/storage/mod.rs
Outdated
} | ||
|
||
impl<'a, 'b, T, D> StorageEntry<'a, 'b, T, D> | ||
where T: Component, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this an actual formatting of rustfmt-nightly?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, I don't think so
src/storage/mod.rs
Outdated
|
||
/// Inserts a component using a lazily called function that is only called | ||
/// when inserting the component. | ||
pub fn or_insert_with<F>(self, component: F) -> &'a mut T |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the F
-typed argument should be named something other than component
? stdlib uses default
src/storage/mod.rs
Outdated
/// } | ||
/// # } | ||
/// ``` | ||
pub fn entry<'a>(&'a mut self, e: Entity) -> Result<StorageEntry<'a, 'e, T, D>, ::error::WrongGeneration> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
any reason we need to use a global type path here?
src/storage/mod.rs
Outdated
let gen = self.entities | ||
.alloc | ||
.generations.get(e.id() as usize) | ||
.map(|gen| *gen) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: could be cloned
?
Only conflicts left to resolve 👍 Once that's done, feel free to merge. bors delegate=@Aceeri |
✌️ Aceeri can now approve this pull request |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good!
6a8a53f
to
55c6180
Compare
bors r+ |
274: Adds StorageEntry to Storage for convenience r=Aceeri a=Aceeri Fixes #268 Adds `StorageEntry` to allow for in place insertions, also some other methods for dealing with the occupied and vacant entries, similar to `std`s HashMap Entry. Still need to add some tests for further verification (I'll do this tomorrow).
Should probably add this to the changelog. bors r- |
Canceled |
bors r+ |
274: Adds StorageEntry to Storage for convenience r=Aceeri a=Aceeri Fixes #268 Adds `StorageEntry` to allow for in place insertions, also some other methods for dealing with the occupied and vacant entries, similar to `std`s HashMap Entry. Still need to add some tests for further verification (I'll do this tomorrow).
Build succeeded |
Fixes #268
Adds
StorageEntry
to allow for in place insertions, also some other methods for dealing with the occupied and vacant entries, similar tostd
s HashMap Entry.Still need to add some tests for further verification (I'll do this tomorrow).