-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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
Add some APIs to ptr::NonNull and fix since
attributes
#47631
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @KodrAus (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
src/libcore/ptr.rs
Outdated
|
||
/// Cast to a pointer of another type | ||
#[unstable(feature = "nonnull", issue = "27730")] | ||
pub fn cast<U>(self) -> NonNull<U> { |
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.
Shouldn't this be U: ?Sized
?
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 should. I’ll also add some tests.
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.
… or not:
error[E0606]: casting `*mut T` as `*mut U` is invalid
= note: vtable kinds may not match
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.
Then maybe this method should also require T: Sized
?
Thanks @SimonSapin!
I think so. |
General question: when should methods in libcore / libstd have |
3e1a159
to
f229511
Compare
src/libcore/ptr.rs
Outdated
|
||
/// Cast to a pointer of another type | ||
#[unstable(feature = "nonnull_cast", issue = /* FIXME */ "0")] | ||
pub fn cast<U>(self) -> NonNull<U> where T: Sized { |
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.
What's wrong with T: ?Sized
here? It makes sense to me to cast the data pointer of NonNull<[u8]>
to NonNull<[u8; 64]>
after performing a length check.
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's asymmetric because there's no trait that models as
precisely, so U
can't also be unsized.
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 you mean the called doing a length check themselves? I added where T: Sized
because I assumed as
would not compile without it, but it looks like it does. Updated.
If |
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 trait impls match what is already available on raw pointers so that seems non-controversial. NonNull::cast looks good to me as an unstable addition. Please create a tracking issue for cast and then this should be ready to merge! Thanks.
@SimonSapin My understanding is we should add the For example in a quick test in a library the following do/don't seem to get inlined in a consuming binary: // Inlined
pub fn generic<T>(t: T) -> T { t }
// Inlined
#[inline]
pub fn generic_inline<T>(t: T) -> T { t }
// Not inlined
pub fn non_generic(i: i32) -> i32 { i + 10 }
// Inlined
#[inline]
pub fn non_generic_inline(i: i32) -> i32 { i + 10 }
impl GenericTrait<i32> for i32 {
// Not inlined
fn generic(self) -> i32 { self }
// Inlined
#[inline]
fn generic_inline(self) -> i32 { self }
// Inlined
fn generic_method<U>(self, u: U) -> (i32, U) { (self, u) }
// Inlined
#[inline]
fn generic_method_inline<U>(self, u: U) -> (i32, U) { (self, u) }
}
pub trait GenericTrait<T> {
fn generic(self) -> T;
fn generic_inline(self) -> T;
fn generic_method<U>(self, u: U) -> (T, U);
fn generic_method_inline<U>(self, u: U) -> (T, U);
} |
This looks good to me too! @rfcbot fcp merge |
Team member @KodrAus has proposed to merge this. The next step is review by the rest of the tagged teams: No concerns currently listed. Once these reviewers reach consensus, this will enter its final comment period. If you spot a major issue that hasn't been raised at any point in this process, please speak up! See this document for info about what commands tagged team members can give me. |
This is less verbose than going through raw pointers to cast with `as`.
Triage ping, ticky boxes for you @BurntSushi! |
@BurntSushi there is a nice checkbox in #47631 (comment) waiting for you! |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
🔔 This is now entering its final comment period, as per the review above. 🔔 |
@bors: r+ |
📌 Commit b8ffc8a has been approved by |
⌛ Testing commit b8ffc8a with merge 161ca1128f172a843e19cab030c6cb2c9e06c6f4... |
💔 Test failed - status-travis |
@bors retry rollup 3 hour timeout... |
Add some APIs to ptr::NonNull and fix `since` attributes This is a follow-up to its stabilization in rust-lang#46952. Tracking issue: rust-lang#27730. * These trait impls are insta-stable: `Hash`, `PartialEq`, `Eq`, `PartialOrd` and `Ord`. * The new `cast<U>() -> NonNull<U>` method is `#[unstable]`. It was proposed in rust-lang#46952 (comment).
By reversing the arguments we achieve several clarifications: - The function closely resembles `cast` but with an argument to initialized the metadata. This is easier to teach and answers an long outstanding question that had restricted cast to `Sized` targets initially. See multiples reviews of <rust-lang#47631> - The 'object identity', in the form or provenance, is now preserved from the call receiver to the result. This helps explain the method as a builder-style, instead of some kind of setter that would modify something in-place. Ensuring that the result has the identity of the `self` argument is also beneficial for an intuition of effects. - An outstanding concern, 'Correct argument type', is avoided by not committing to any specific argument type. This is consistent with cast which does not require its receiver to be a raw address.
Refactor set_ptr_value as with_metadata_of Replaces `set_ptr_value` (rust-lang#75091) with methods of reversed argument order: ```rust impl<T: ?Sized> *mut T { pub fn with_metadata_of<U: ?Sized>(self, val: *mut U) -> *mut U; } impl<T: ?Sized> *const T { pub fn with_metadata_of<U: ?Sized>(self, val: *const U) -> *const U; } ``` By reversing the arguments we achieve several clarifications: - The function closely resembles `cast` with an argument to initialize the metadata. This is easier to teach and answers a long outstanding question that had restricted cast to `Sized` pointee targets. See multiples reviews of <rust-lang#47631> - The 'object identity', in the form of provenance, is now preserved from the receiver argument to the result. This helps explain the method as a builder-style, instead of some kind of setter that would modify something in-place. Ensuring that the result has the identity of the `self` argument is also beneficial for an intuition of effects. - An outstanding concern, 'Correct argument type', is avoided by not committing to any specific argument type. This is consistent with cast which does not require its receiver to be a 'raw address'. Hopefully the usage examples in `sync/rc.rs` serve as sufficient examples of the style to convince the reader of the readability improvements of this style, when compared to the previous order of arguments. I want to take the opportunity to motivate inclusion of this method _separate_ from metadata API, separate from `feature(ptr_metadata)`. It does _not_ involve the `Pointee` trait in any form. This may be regarded as a very, very light form that does not commit to any details of the pointee trait, or its associated metadata. There are several use cases for which this is already sufficient and no further inspection of metadata is necessary. - Storing the coercion of `*mut T` into `*mut dyn Trait` as a way to dynamically cast some an arbitrary instance of the same type to a dyn trait instance. In particular, one can have a field of type `Option<*mut dyn io::Seek>` to memorize if a particular writer is seekable. Then a method `fn(self: &T) -> Option<&dyn Seek>` can be provided, which does _not_ involve the static trait bound `T: Seek`. This makes it possible to create an API that is capable of utilizing seekable streams and non-seekable streams (instead of a possible less efficient manner such as more buffering) through the same entry-point. - Enabling more generic forms of unsizing for no-`std` smart pointers. Using the stable APIs only few concrete cases are available. One can unsize arrays to `[T]` by `ptr::slice_from_raw_parts` but unsizing a custom smart pointer to, e.g., `dyn Iterator`, `dyn Future`, `dyn Debug`, can't easily be done generically. Exposing `with_metadata_of` would allow smart pointers to offer their own `unsafe` escape hatch with similar parameters where the caller provides the unsized metadata. This is particularly interesting for embedded where `dyn`-trait usage can drastically reduce code size.
This is a follow-up to its stabilization in #46952. Tracking issue: #27730.
Hash
,PartialEq
,Eq
,PartialOrd
andOrd
.cast<U>() -> NonNull<U>
method is#[unstable]
. It was proposed in Rename std::ptr::Shared to NonNull and stabilize it #46952 (comment).