-
Notifications
You must be signed in to change notification settings - Fork 221
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
implement get_mut_or_default #562
Conversation
src/storage/generic.rs
Outdated
@@ -103,6 +106,13 @@ where | |||
WriteStorage::get_mut(self, entity) | |||
} | |||
|
|||
fn get_mut_or_default(&mut self, entity: Entity) -> &mut Self::Component where Self::Component: Default { | |||
if self.get(entity).is_none() { | |||
self.insert(entity, Default::default()).unwrap(); |
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 don't think an unwrap should be best here. Maybe at least an expect.
The one under does not need an except, but maybe an explanation in the comment explaining why it will never be triggered.
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 any situation where the expect could be hit?
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 believe the specs does not guarantee it would never happen. It's not very expensive to make sure it doesn't go wrong.
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 the only possible error case that the component has been added between the check and the insertion? In that case we could ignore the result entirely.
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, this would not even be an error, insert overwrites the previous component.
@torkleyy What do you think?
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.
+1 to expect()
instead of unwrap()
.
Is the only possible error case that the component has been added between the check and the insertion?
it's a mutable borrow ofself
, so nothing can insert it between
by the way, WriteStorage
is a Storage
, and has a contains
method, so perhaps it expresses the intent better.
if !self.contains(entity) {
self.insert(entity, Default::default()).expect("..");
}
self.get_mut(entity).expect("..")
The alternate implementation feels a bit verbose
if let Some(component) = self.get_mut(entity) {
component
} else {
self.insert(entity, Default::default()).expect("..");
self.get_mut(entity).expect("..")
}
Same comment for the below implementation
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.
Switched to expect.
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.
yo, this is useful!
have some recommendations, but then realized there's also existing tech debt
src/storage/generic.rs
Outdated
@@ -103,6 +106,13 @@ where | |||
WriteStorage::get_mut(self, entity) | |||
} | |||
|
|||
fn get_mut_or_default(&mut self, entity: Entity) -> &mut Self::Component where Self::Component: Default { | |||
if self.get(entity).is_none() { | |||
self.insert(entity, Default::default()).unwrap(); |
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.
+1 to expect()
instead of unwrap()
.
Is the only possible error case that the component has been added between the check and the insertion?
it's a mutable borrow ofself
, so nothing can insert it between
by the way, WriteStorage
is a Storage
, and has a contains
method, so perhaps it expresses the intent better.
if !self.contains(entity) {
self.insert(entity, Default::default()).expect("..");
}
self.get_mut(entity).expect("..")
The alternate implementation feels a bit verbose
if let Some(component) = self.get_mut(entity) {
component
} else {
self.insert(entity, Default::default()).expect("..");
self.get_mut(entity).expect("..")
}
Same comment for the below implementation
} | ||
} | ||
|
||
for i in 0..1_000 { |
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.
hm, what are these loops and magic numbers? am finding I have to think quite a bit to understand the logic, and then think again to figure out what its intent is.
if the loops are necessary, it's worth writing the rationale in a comment
- is it to get the entity index high enough?
- can we use a smaller backing storage to achieve the same effect?
not obvious to understand what the test is doing 🤔:
- insert 500 entities with
n + 1290
as its value. - mutate 1000 entities with
get_mut_or_default()
to ben + n + 710
- assert the first 500 are
2n + 2000
- assert the last 500 are
n + 710
ah 💡! while it is logically correct and does test the effect, it's considerable mental effort to turn the code back into understanding. could you try to make it easier, otherwise my head is like this: 🤕, haha
edit: just expanded the diff, and saw the existing code is like that. oh man 😂
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 removed the magic numbers & commented it.
d6f3c7a
to
a983117
Compare
Squashed & pushed with relevant modifications. |
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.
🚀
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.
Thanks, looks useful. I'm a little unsure how to handle dead entities here.
@@ -103,6 +111,14 @@ where | |||
WriteStorage::get_mut(self, entity) | |||
} | |||
|
|||
fn get_mut_or_default(&mut self, entity: Entity) -> &mut Self::Component where Self::Component: Default { | |||
if !self.contains(entity) { | |||
self.insert(entity, Default::default()).expect("Insertion of default component failed"); |
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 will panic for dead entities.
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.
Oh boy. I didn't think of that.
@@ -126,6 +142,14 @@ where | |||
WriteStorage::get_mut(*self, entity) | |||
} | |||
|
|||
fn get_mut_or_default(&mut self, entity: Entity) -> &mut Self::Component where Self::Component: Default { | |||
if !self.contains(entity) { | |||
self.insert(entity, Default::default()).expect("Insertion of default component failed"); |
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
a983117
to
0585eb5
Compare
Marked that it will panic if the entity is dead. Another option is to return an Option, which'd make the usage slightly less ergonomic, but in most cases still nice enough. |
^ Opened a separate PR for that. Pick one. |
537: Update rand requirement from 0.5.5 to 0.6.1 r=torkleyy a=dependabot[bot] Updates the requirements on [rand](https://github.com/rust-random/rand) to permit the latest version. <details> <summary>Changelog</summary> *Sourced from [rand's changelog](https://github.com/rust-random/rand/blob/master/CHANGELOG.md).* > ## [0.6.1] - 2018-11-22 > - Support sampling `Duration` also for `no_std` (only since Rust 1.25) ([amethyst#649](https://github-redirect.dependabot.com/rust-random/rand/issues/649)) > - Disable default features of `libc` ([amethyst#647](https://github-redirect.dependabot.com/rust-random/rand/issues/647)) > > ## [0.6.0] - 2018-11-14 > > ### Project organisation > - Rand has moved from [rust-lang-nursery](https://github.com/rust-lang-nursery/rand) > to [rust-random](https://github.com/rust-random/rand)! ([amethyst#578](https://github-redirect.dependabot.com/rust-random/rand/issues/578)) > - Created [The Rust Random Book](https://rust-random.github.io/book/) > ([source](https://github.com/rust-random/book)) > - Update copyright and licence notices ([amethyst#591](https://github-redirect.dependabot.com/rust-random/rand/issues/591), [amethyst#611](https://github-redirect.dependabot.com/rust-random/rand/issues/611)) > - Migrate policy documentation from the wiki ([amethyst#544](https://github-redirect.dependabot.com/rust-random/rand/issues/544)) > > ### Platforms > - Add fork protection on Unix ([amethyst#466](https://github-redirect.dependabot.com/rust-random/rand/issues/466)) > - Added support for wasm-bindgen. ([amethyst#541](https://github-redirect.dependabot.com/rust-random/rand/issues/541), [amethyst#559](https://github-redirect.dependabot.com/rust-random/rand/issues/559), [amethyst#562](https://github-redirect.dependabot.com/rust-random/rand/issues/562), [amethyst#600](https://github-redirect.dependabot.com/rust-random/rand/issues/600)) > - Enable `OsRng` for powerpc64, sparc and sparc64 ([amethyst#609](https://github-redirect.dependabot.com/rust-random/rand/issues/609)) > - Use `syscall` from `libc` on Linux instead of redefining it ([amethyst#629](https://github-redirect.dependabot.com/rust-random/rand/issues/629)) > > ### RNGs > - Switch `SmallRng` to use PCG ([amethyst#623](https://github-redirect.dependabot.com/rust-random/rand/issues/623)) > - Implement `Pcg32` and `Pcg64Mcg` generators ([amethyst#632](https://github-redirect.dependabot.com/rust-random/rand/issues/632)) > - Move ISAAC RNGs to a dedicated crate ([amethyst#551](https://github-redirect.dependabot.com/rust-random/rand/issues/551)) > - Move Xorshift RNG to its own crate ([amethyst#557](https://github-redirect.dependabot.com/rust-random/rand/issues/557)) > - Move ChaCha and HC128 RNGs to dedicated crates ([amethyst#607](https://github-redirect.dependabot.com/rust-random/rand/issues/607), [amethyst#636](https://github-redirect.dependabot.com/rust-random/rand/issues/636)) > - Remove usage of `Rc` from `ThreadRng` ([amethyst#615](https://github-redirect.dependabot.com/rust-random/rand/issues/615)) > > ### Sampling and distributions > - Implement `Rng.gen_ratio()` and `Bernoulli::new_ratio()` ([amethyst#491](https://github-redirect.dependabot.com/rust-random/rand/issues/491)) > - Make `Uniform` strictly respect `f32` / `f64` high/low bounds ([amethyst#477](https://github-redirect.dependabot.com/rust-random/rand/issues/477)) > - Allow `gen_range` and `Uniform` to work on non-`Copy` types ([amethyst#506](https://github-redirect.dependabot.com/rust-random/rand/issues/506)) > - `Uniform` supports inclusive ranges: `Uniform::from(a..=b)`. This is > automatically enabled for Rust >= 1.27. ([amethyst#566](https://github-redirect.dependabot.com/rust-random/rand/issues/566)) > - Implement `TrustedLen` and `FusedIterator` for `DistIter` ([amethyst#620](https://github-redirect.dependabot.com/rust-random/rand/issues/620)) > > #### New distributions > - Add the `Dirichlet` distribution ([amethyst#485](https://github-redirect.dependabot.com/rust-random/rand/issues/485)) > - Added sampling from the unit sphere and circle. ([amethyst#567](https://github-redirect.dependabot.com/rust-random/rand/issues/567)) > - Implement the triangular distribution ([amethyst#575](https://github-redirect.dependabot.com/rust-random/rand/issues/575)) > - Implement the Weibull distribution ([amethyst#576](https://github-redirect.dependabot.com/rust-random/rand/issues/576)) > - Implement the Beta distribution ([amethyst#574](https://github-redirect.dependabot.com/rust-random/rand/issues/574)) > > #### Optimisations > > - Optimise `Bernoulli::new` ([amethyst#500](https://github-redirect.dependabot.com/rust-random/rand/issues/500)) > - Optimise `char` sampling ([amethyst#519](https://github-redirect.dependabot.com/rust-random/rand/issues/519)) > - Optimise sampling of `std::time::Duration` ([amethyst#583](https://github-redirect.dependabot.com/rust-random/rand/issues/583)) > > ### Sequences ></table> ... (truncated) </details> <details> <summary>Commits</summary> - See full diff in [compare view](https://github.com/rust-random/rand/commits/0.6.1) </details> <br /> Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting `@dependabot rebase`. [//]: # (dependabot-automerge-start) [//]: # (dependabot-automerge-end) --- **Note:** This repo was added to Dependabot recently, so you'll receive a maximum of 5 PRs for your first few update runs. Once an update run creates fewer than 5 PRs we'll remove that limit. You can always request more updates by clicking `Bump now` in your [Dependabot dashboard](https://app.dependabot.com). <details> <summary>Dependabot commands and options</summary> <br /> You can trigger Dependabot actions by commenting on this PR: - `@dependabot rebase` will rebase this PR - `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it - `@dependabot merge` will merge this PR after your CI passes on it - `@dependabot cancel merge` will cancel a previously requested merge - `@dependabot reopen` will reopen this PR if it is closed - `@dependabot ignore this [patch|minor|major] version` will close this PR and stop Dependabot creating any more for this minor/major version (unless you reopen the PR or upgrade to it yourself) - `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself) - `@dependabot use these labels` will set the current labels as the default for future PRs for this repo and language - `@dependabot use these reviewers` will set the current reviewers as the default for future PRs for this repo and language - `@dependabot use these assignees` will set the current assignees as the default for future PRs for this repo and language - `@dependabot use this milestone` will set the current milestone as the default for future PRs for this repo and language - `@dependabot badge me` will comment on this PR with code to add a "Dependabot enabled" badge to your readme Additionally, you can set the following in your Dependabot [dashboard](https://app.dependabot.com): - Update frequency (including time of day and day of week) - Automerge options (never/patch/minor, and dev/runtime dependencies) - Pull request limits (per update run and/or open at any time) - Out-of-range updates (receive only lockfile updates, if desired) - Security updates (receive only security updates, if desired) Finally, you can contact us by mentioning @dependabot. </details> Co-authored-by: dependabot[bot] <[email protected]> Co-authored-by: Thomas Schaller <[email protected]>
Fixes #561
Checklist
API changes
New function:
GenericWriteStorage::get_mut_or_default
for Default component types. Not breaking.This change is