Skip to content
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

Merged
merged 4 commits into from
Feb 7, 2018

Conversation

SimonSapin
Copy link
Contributor

@SimonSapin SimonSapin commented Jan 21, 2018

This is a follow-up to its stabilization in #46952. Tracking issue: #27730.

@rust-highfive
Copy link
Collaborator

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.


/// Cast to a pointer of another type
#[unstable(feature = "nonnull", issue = "27730")]
pub fn cast<U>(self) -> NonNull<U> {
Copy link
Member

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?

Copy link
Contributor Author

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.

Copy link
Contributor Author

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

Copy link
Member

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?

@KodrAus
Copy link
Contributor

KodrAus commented Jan 21, 2018

Thanks @SimonSapin!

Should we also add PartialOrd and Ord? Raw pointers implement them.

I think so.

@SimonSapin
Copy link
Contributor Author

General question: when should methods in libcore / libstd have #[inline]?

@SimonSapin SimonSapin force-pushed the nonnull branch 2 times, most recently from 3e1a159 to f229511 Compare January 21, 2018 09:33
@kennytm kennytm added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels Jan 21, 2018

/// Cast to a pointer of another type
#[unstable(feature = "nonnull_cast", issue = /* FIXME */ "0")]
pub fn cast<U>(self) -> NonNull<U> where T: Sized {
Copy link
Member

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.

Copy link
Member

@eddyb eddyb Jan 21, 2018

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.

Copy link
Contributor Author

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.

@SimonSapin
Copy link
Contributor Author

If cast requires more discussion I’ll split it into a separate PR so that the derives can land in Nightly. Let me know. It’s unstable though, we can always change it later.

Copy link
Member

@dtolnay dtolnay left a 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.

@KodrAus
Copy link
Contributor

KodrAus commented Jan 22, 2018

General question: when should methods in libcore / libstd have #[inline]?

@SimonSapin My understanding is we should add the #[inline] attribute to public non-generic functions/methods that we expect to get inlined, because generic functions are monomorphised in the consuming crate so they're candidates for inlining, but non generic functions aren't. At least that's roughly how @sfackler explained it to me, there might be more to it though.

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);
}

@KodrAus
Copy link
Contributor

KodrAus commented Jan 22, 2018

This looks good to me too!

@rfcbot fcp merge

@rfcbot
Copy link

rfcbot commented Jan 22, 2018

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.

@rfcbot rfcbot added the proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. label Jan 22, 2018
This is less verbose than going through raw pointers to cast with `as`.
@SimonSapin
Copy link
Contributor Author

@dtolnay Done: #47653

@kennytm kennytm added S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Jan 31, 2018
@kennytm
Copy link
Member

kennytm commented Jan 31, 2018

Triage ping, ticky boxes for you @BurntSushi!

@pietroalbini
Copy link
Member

@BurntSushi there is a nice checkbox in #47631 (comment) waiting for you!

@rfcbot
Copy link

rfcbot commented Feb 6, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot
Copy link

rfcbot commented Feb 6, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

@rfcbot rfcbot added final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. and removed proposed-final-comment-period Proposed to merge/close by relevant subteam, see T-<team> label. Will enter FCP once signed off. labels Feb 6, 2018
@alexcrichton
Copy link
Member

@bors: r+

@bors
Copy link
Contributor

bors commented Feb 6, 2018

📌 Commit b8ffc8a has been approved by alexcrichton

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-team Status: Awaiting decision from the relevant subteam (see the T-<team> label). labels Feb 6, 2018
@bors
Copy link
Contributor

bors commented Feb 7, 2018

⌛ Testing commit b8ffc8a with merge 161ca1128f172a843e19cab030c6cb2c9e06c6f4...

@bors
Copy link
Contributor

bors commented Feb 7, 2018

💔 Test failed - status-travis

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Feb 7, 2018
@kennytm
Copy link
Member

kennytm commented Feb 7, 2018

@bors retry rollup

3 hour timeout...

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Feb 7, 2018
Manishearth added a commit to Manishearth/rust that referenced this pull request Feb 7, 2018
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).
bors added a commit that referenced this pull request Feb 7, 2018
Rollup of 10 pull requests

- Successful merges: #47613, #47631, #47810, #47883, #47922, #47944, #48014, #48018, #48020, #48028
- Failed merges:
@bors bors merged commit b8ffc8a into rust-lang:master Feb 7, 2018
@SimonSapin SimonSapin deleted the nonnull branch February 16, 2018 10:24
bors pushed a commit to rust-lang-ci/rust that referenced this pull request Mar 28, 2022
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.
bors added a commit to rust-lang-ci/rust that referenced this pull request Mar 28, 2022
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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
final-comment-period In the final comment period and will be merged soon unless new substantive objections are raised. S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

10 participants