-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Improve ThinSlicePtr API
#21823
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
base: main
Are you sure you want to change the base?
Improve ThinSlicePtr API
#21823
Conversation
`debug_assert!()` already handles this for us!
This makes it more clear to a reviewer looking over code that the `get()` is not bounds checked. It also is consistent with `slice::get_unchecked()`.
It wasn't caught previously because `ThinSlicePtr` is `Copy`, but we don't want to clone the pointer every time we dereference it. Additionally, this makes the method consistent with `slice::get_unchecked()`.
|
This is my first time writing a migration guide using the new system. (Crazy, right?!) Let me know if I did anything wrong :) |
crates/bevy_ptr/src/lib.rs
Outdated
| #[inline] | ||
| /// Indexes the slice without doing bounds checks | ||
| pub unsafe fn get_unchecked(&self, index: usize) -> &'a T { | ||
| debug_assert!(index < self.len, "tried to index out-of-bounds of a slice"); |
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.
non-blocking comment: I noticed you removed the #[cfg(debug_assertions)] line that was above this previously (in the deprecated function). With debug_assert!, as far as I can read from documentation, that line is actually not needed, right? It seems like there are other places in the codebase where this redundant line is placed above a debug_assert!
(new here and new to Rust!)
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.
Yup! I removed the #[cfg(...)] because it was redundant. The reason is because debug_assert!() actually compiles down to:
if cfg!(debug_assertions) {
assert!(...);
}Adding #[cfg(debug_assertions)] to this if statement is redundant because we'd be checking if debug_assertions is enabled twice!
It seems like there are other places in the codebase where this redundant line is placed above a
debug_assert!
Where else did you find cases like this? I can open up a follow-up issue for getting rid of them 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.
Hopefully this link works for you: https://github.com/search?q=repo%3Abevyengine%2Fbevy+%22%23%5Bcfg%28debug_assertions%29%5D%22+debug_assert%21&type=code (if not, you can search for usages via typing repo:bevyengine/bevy "#[cfg(debug_assertions)]" debug_assert!) in the search bar). You may have to expand the matches per file since GitHub likes to consolidate them.
It seems there are a few other places, although in my search I did find a useful comment in unsafe_world_cell.rs above one usage:
// This annotation is needed because the
// allows_mutable_access field doesn't exist otherwise.
// Kinda weird, since debug_assert would never be called,
// but CI complained in https://github.com/bevyengine/bevy/pull/17393
So I wonder if your pull request might run into this issue because self.len is also only defined in the debug config? Something to keep in mind if the CI complains about it
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.
Actually, that's a really good point. I just tested it and my branch fails to check with --release:
error[E0609]: no field `len` on type `&ThinSlicePtr<'a, T>`
--> crates/bevy_ptr/src/lib.rs:1097:36
|
1097 | debug_assert!(index < self.len, "tried to index out-of-bounds of a slice");
| ^^^ unknown field
|
= note: available fields are: `ptr`, `_marker`
I replaced debug_assert!() with a #[cfg(debug_assertions)] assert!() call instead, which does the same thing in debug mode but will skip compiling index < self.len in release mode. Thanks for pointing this out!
kfc35
left a comment
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.
New here so my approval may not mean as much, but it LGTM!
Objective
ThinSlicePtr::get()doesn't signal that it doesn't perform bounds checking unless you are familiar with the API.ThinSlicePtr::get()takesself, not&self, meaning it consumes theThinSlicePtreach timeget()is called. This does not match the behavior ofslice.get(), which takes&self.ThinSlicePtrimplementsCopy. This isn't a large issue because it all compiles down to the same machine code, but there's no point toget()requiringself.ThinSlicePtrcould use better documentation, and could be improved a little in some areas.Solution
ThinSlicePtr::get()toget_unchecked(), making the API mirrorslice.get_unchecked(). The oldget()is kept as a deprecated method, to be removed in 1.19.0.slice.get_unchecked()take&selfrather thanself.Testing