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

Change 'unsafe_Unpin' to UpperCamelCase (UnsafeUnpin) #40

Merged
merged 1 commit into from
Aug 11, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pin-project-internal/src/pin_project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl Parse for Args {
let i = input.parse::<Ident>()?;
match &*i.to_string() {
"PinnedDrop" => pinned_drop = Some(i.span()),
"unsafe_Unpin" => unsafe_unpin = Some(i.span()),
"UnsafeUnpin" => unsafe_unpin = Some(i.span()),
_ => return Err(error!(i, "an invalid argument was passed")),
}
}
Expand Down
32 changes: 16 additions & 16 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,7 @@ pub use pin_project_internal::project;
/// To enforce this, this attribute will automatically generate an `Unpin` implementation
/// for you, which will require that all structurally pinned fields be `Unpin`
/// If you wish to provide an manual `Unpin` impl, you can do so via the
/// `unsafe_Unpin` argument.
/// `UnsafeUnpin` argument.
///
/// 2. The destructor of the struct must not move structural fields out of its argument.
///
Expand Down Expand Up @@ -300,14 +300,14 @@ pub use pin_project_internal::project;
/// ```
///
/// If you want to implement [`Unpin`] manually,
/// you must use the `unsafe_Unpin` argument to
/// you must use the `UnsafeUnpin` argument to
/// `#[pin_project]`.
///
/// ```rust
/// use pin_project::{pin_project, UnsafeUnpin};
/// use std::pin::Pin;
///
/// #[pin_project(unsafe_Unpin)]
/// #[pin_project(UnsafeUnpin)]
/// struct Foo<T, U> {
/// #[pin]
/// future: T,
Expand Down Expand Up @@ -509,7 +509,7 @@ pub use pin_project_internal::pin_project;
pub use pin_project_internal::pinned_drop;

/// A trait used for custom implementations of [`Unpin`].
/// This trait is used in conjunction with the `unsafe_Unpin`
/// This trait is used in conjunction with the `UnsafeUnpin`
/// argument to [`pin_project`]
///
/// The Rust [`Unpin`] trait is safe to implement - by itself,
Expand All @@ -532,10 +532,10 @@ pub use pin_project_internal::pinned_drop;
/// this crate will generate an `Unpin` impl for your type that 'forwards' to
/// your `UnsafeUnpin` impl. However, this trait is `unsafe` - since your type
/// uses structural pinning (otherwise, you wouldn't be using this crate!),
/// you must be sure that your `UnsafeUnpinned` impls follows all of
/// you must be sure that your `UnsafeUnpin` impls follows all of
/// the requirements for an `Unpin` impl of a structurally-pinned type.
///
/// Note that if you specify `#[pin_project(unsafe_Unpin)]`, but do *not*
/// Note that if you specify `#[pin_project(UnsafeUnpin)]`, but do *not*
/// provide an impl of `UnsafeUnpin`, your type will never implement `Unpin`.
/// This is effectly the same thing as adding a `PhantomUnpin` to your type
///
Expand All @@ -550,7 +550,7 @@ pub use pin_project_internal::pinned_drop;
/// ```rust
/// use pin_project::{pin_project, UnsafeUnpin};
///
/// #[pin_project(unsafe_Unpin)]
/// #[pin_project(UnsafeUnpin)]
/// struct Foo<K, V> {
/// #[pin]
/// field_1: K,
Expand Down Expand Up @@ -586,47 +586,47 @@ pub mod __private {

// This is an internal helper struct used by `pin-project-internal`.
// This allows us to force an error if the user tries to provide
// a regular `Unpin` impl when they specify the `unsafe_Unpin` argument.
// a regular `Unpin` impl when they specify the `UnsafeUnpin` argument.
// This is why we need Wrapper:
//
// Supposed we have the following code:
//
// #[pin_project(unsafe_Unpin)]
// #[pin_project(UnsafeUnpin)]
// struct MyStruct<T> {
// #[pin] field: T
// }
//
// impl<T> Unpin for MyStruct<T> where MyStruct<T>: UnsafeUnpinned {} // generated by pin-project-internal
// impl<T> Unpin for MyStruct<T> where MyStruct<T>: UnsafeUnpin {} // generated by pin-project-internal
// impl<T> Unpin for MyStruct<T> where T: Copy // written by the user
//
// We want this code to be rejected - the user is completely bypassing unsafe_Unpin,
// We want this code to be rejected - the user is completely bypassing `UnsafeUnpin`,
// and providing an unsound Unpin impl in safe code!
//
// Unfortunately, the Rust compiler will accept the above code.
// Because MyStruct is declared in the same crate as the user-provided impl,
// the compiler will notice that 'MyStruct<T>: UnsafeUnpinned' never holds.
// the compiler will notice that 'MyStruct<T>: UnsafeUnpin' never holds.
//
// The solution is to introduce the 'Wrapper' struct, which is defined
// in the 'pin-project' crate.
//
// We now have code that looks like this:
//
// impl<T> Unpin for MyStruct<T> where Wrapper<MyStruct<T>>: UnsafeUnpinned {} // generated by pin-project-internal
// impl<T> Unpin for MyStruct<T> where Wrapper<MyStruct<T>>: UnsafeUnpin {} // generated by pin-project-internal
// impl<T> Unpin for MyStruct<T> where T: Copy // written by the user
//
// We also have 'unsafe impl<T> UnsafeUnpin for Wrapper<T> where T: UnsafeUnpin {}' in the
// 'pin-project' crate.
//
// Now, our generated impl has a bound involving a type defined in another crate - Wrapper.
// This will cause rust to conservatively assume that 'Wrapper<MyStruct<T>>: UnsafeUnpinned'
// This will cause rust to conservatively assume that 'Wrapper<MyStruct<T>>: UnsafeUnpin'
// holds, in the interest of preserving forwards compatibility (in case such an impl is added
// for Wrapper<T> in a new version of the crate).
//
// This will cause rust to reject any other Unpin impls for MyStruct<T>, since it will
// assume that our generated impl could potentially apply in any situation.
//
// This acheives the desired effect - when the user writes `#[pin_project(unsafe_Unpin)]`,
// the user must either provide no impl of `UnsafeUnpinned` (which is equivalent
// This acheives the desired effect - when the user writes `#[pin_project(UnsafeUnpin)]`,
// the user must either provide no impl of `UnsafeUnpin` (which is equivalent
// to making the type never implement Unpin), or provide an impl of `UnsafeUnpin`.
// It is impossible for them to provide an impl of `Unpin`
#[doc(hidden)]
Expand Down
2 changes: 1 addition & 1 deletion tests/ui/pin_project/forget-unsafe-unpin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use pin_project::pin_project;
// FIXME
#[test]
fn unsafe_unpin() {
#[pin_project(unsafe_Unpin)]
#[pin_project(UnsafeUnpin)]
pub struct Blah<T> {
field_1: u8,
#[pin]
Expand Down
2 changes: 1 addition & 1 deletion tests/unsafe_unpin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use pin_project::{pin_project, UnsafeUnpin};

#[test]
fn unsafe_unpin() {
#[pin_project(unsafe_Unpin)]
#[pin_project(UnsafeUnpin)]
pub struct Blah<T> {
field_1: u8,
#[pin]
Expand Down