diff --git a/README.md b/README.md index 561f2488..9121e41c 100644 --- a/README.md +++ b/README.md @@ -56,11 +56,9 @@ impl Struct { } ``` -[Code like this will be generated](examples/struct-default.rs) +[Code like this will be generated](examples/struct-default-expanded.rs) -See [`pin_project`] attribute for more details. - -[`pin_project`]: https://docs.rs/pin-project-internal/0.4.0-alpha.10/pin_project_internal/attr.pin_project.html +There are examples and generated code of each feature in [examples](examples/README.md) directory. ## License diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 00000000..62349001 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,9 @@ +## Examples and generated code of each feature of pin-project + +* [Basic usage of `#[pin_project]` on structs.](struct-default.rs) -- [generated code](struct-default-expanded.rs) + +* [Basic usage of `#[pin_project]` on enums.](enum-default.rs) -- [generated code](enum-default-expanded.rs) + +* [Manual implementation of `Unpin` by `UnsafeUnpin`.](unsafe_unpin.rs) -- [generated code](unsafe_unpin-expanded.rs) + +* [Manual implementation of `Drop` by `#[pinned_drop]`.](pinned_drop.rs) -- [generated code](pinned_drop-expanded.rs) diff --git a/examples/enum-default-expanded.rs b/examples/enum-default-expanded.rs new file mode 100644 index 00000000..a8013408 --- /dev/null +++ b/examples/enum-default-expanded.rs @@ -0,0 +1,90 @@ +// Original code (./enum-default.rs): +// +// ```rust +// #![allow(dead_code, unused_imports)] +// +// use pin_project::pin_project; +// +// #[pin_project] +// enum Enum { +// Pinned(#[pin] T), +// Unpinned(U), +// } +// +// fn main() {} +// ``` + +#![allow(dead_code, unused_imports)] + +use pin_project::pin_project; + +enum Enum { + Pinned(T), + Unpinned(U), +} + +#[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. +#[allow(dead_code)] // This lint warns unused fields/variants. +enum __EnumProjection<'_pin, T, U> { + Pinned(::core::pin::Pin<&'_pin mut T>), + Unpinned(&'_pin mut U), +} + +impl<'_outer_pin, T, U> __EnumProjectionTrait<'_outer_pin, T, U> + for ::core::pin::Pin<&'_outer_pin mut Enum> +{ + fn project<'_pin>(&'_pin mut self) -> __EnumProjection<'_pin, T, U> { + unsafe { + match self.as_mut().get_unchecked_mut() { + Enum::Pinned(_x0) => __EnumProjection::Pinned(::core::pin::Pin::new_unchecked(_x0)), + Enum::Unpinned(_x0) => __EnumProjection::Unpinned(_x0), + } + } + } + fn project_into(self) -> __EnumProjection<'_outer_pin, T, U> { + unsafe { + match self.get_unchecked_mut() { + Enum::Pinned(_x0) => __EnumProjection::Pinned(::core::pin::Pin::new_unchecked(_x0)), + Enum::Unpinned(_x0) => __EnumProjection::Unpinned(_x0), + } + } + } +} + +trait __EnumProjectionTrait<'_outer_pin, T, U> { + fn project<'_pin>(&'_pin mut self) -> __EnumProjection<'_pin, T, U>; + fn project_into(self) -> __EnumProjection<'_outer_pin, T, U>; +} + +// Automatically create the appropriate conditional `Unpin` implementation. +// +// See ./struct-default-expanded.rs and https://github.com/taiki-e/pin-project/pull/53. +// for details. +#[allow(non_snake_case)] +fn __unpin_scope_Enum() { + struct AlwaysUnpinEnum { + val: ::core::marker::PhantomData, + } + impl ::core::marker::Unpin for AlwaysUnpinEnum {} + #[allow(dead_code)] + #[doc(hidden)] + struct __UnpinStructEnum { + __pin_project_use_generics: AlwaysUnpinEnum<(T, U)>, + __field0: T, + } + impl ::core::marker::Unpin for Enum where __UnpinStructEnum: ::core::marker::Unpin {} +} + +// Ensure that enum does not implement `Drop`. +// +// See ./struct-default-expanded.rs for details. +trait EnumMustNotImplDrop {} +#[allow(clippy::drop_bounds)] +impl EnumMustNotImplDrop for T {} +#[allow(single_use_lifetimes)] +impl EnumMustNotImplDrop for Enum {} + +// We don't need to check for '#[repr(packed)]', +// since it does not apply to enums. + +fn main() {} diff --git a/examples/enum-default.rs b/examples/enum-default.rs index 6a108352..0afb31b7 100644 --- a/examples/enum-default.rs +++ b/examples/enum-default.rs @@ -1,76 +1,13 @@ -//! -//! Original code: -//! -//! ```rust -//! #![allow(dead_code)] -//! -//! #[pin_project] -//! enum Enum { -//! Pinned(#[pin] T), -//! Unpinned(U), -//! } -//! -//! fn main() {} -//! ``` +// See ./enum-default-expanded.rs for generated code. -#![allow(dead_code)] +#![allow(dead_code, unused_imports)] +use pin_project::pin_project; + +#[pin_project] enum Enum { - Pinned(T), + Pinned(#[pin] T), Unpinned(U), } -#[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. -#[allow(dead_code)] // This lint warns unused fields/variants. -enum __EnumProjection<'_pin, T, U> { - Pinned(::core::pin::Pin<&'_pin mut T>), - Unpinned(&'_pin mut U), -} - -impl<'_outer_pin, T, U> __EnumProjectionTrait<'_outer_pin, T, U> - for ::core::pin::Pin<&'_outer_pin mut Enum> -{ - fn project<'_pin>(&'_pin mut self) -> __EnumProjection<'_pin, T, U> { - unsafe { - match self.as_mut().get_unchecked_mut() { - Enum::Pinned(_x0) => __EnumProjection::Pinned(::core::pin::Pin::new_unchecked(_x0)), - Enum::Unpinned(_x0) => __EnumProjection::Unpinned(_x0), - } - } - } - fn project_into(self) -> __EnumProjection<'_outer_pin, T, U> { - unsafe { - match self.get_unchecked_mut() { - Enum::Pinned(_x0) => __EnumProjection::Pinned(::core::pin::Pin::new_unchecked(_x0)), - Enum::Unpinned(_x0) => __EnumProjection::Unpinned(_x0), - } - } - } -} - -trait __EnumProjectionTrait<'_outer_pin, T, U> { - fn project<'_pin>(&'_pin mut self) -> __EnumProjection<'_pin, T, U>; - fn project_into(self) -> __EnumProjection<'_outer_pin, T, U>; -} - -// Automatically create the appropriate conditional Unpin implementation. -impl Unpin for Enum where T: Unpin {} - -// Ensure that enum does not implement `Drop`. -// There are two possible cases: -// 1. The user type does not implement Drop. In this case, -// the first blanked impl will not apply to it. This code -// will compile, as there is only one impl of MustNotImplDrop for the user type -// 2. The user type does impl Drop. This will make the blanket impl applicable, -// which will then comflict with the explicit MustNotImplDrop impl below. -// This will result in a compilation error, which is exactly what we want. -trait EnumMustNotImplDrop {} -#[allow(clippy::drop_bounds)] -impl EnumMustNotImplDrop for T {} -#[allow(single_use_lifetimes)] -impl EnumMustNotImplDrop for Enum {} - -// We don't need to check for '#[repr(packed)]', -// since it does not apply to enums. - fn main() {} diff --git a/examples/pinned_drop-expanded.rs b/examples/pinned_drop-expanded.rs new file mode 100644 index 00000000..22bc6f1e --- /dev/null +++ b/examples/pinned_drop-expanded.rs @@ -0,0 +1,136 @@ +// Original code (./pinned_drop.rs): +// +// ```rust +// #![allow(dead_code, unused_imports)] +// +// use pin_project::{pin_project, pinned_drop}; +// use std::pin::Pin; +// +// #[pin_project(PinnedDrop)] +// pub struct Foo<'a, T> { +// was_dropped: &'a mut bool, +// #[pin] +// field: T, +// } +// +// #[pinned_drop] +// fn drop_foo(mut this: Pin<&mut Foo<'_, T>>) { +// **this.project().was_dropped = true; +// } +// +// fn main() {} +// ``` + +#![allow(dead_code, unused_imports)] + +use pin_project::{pin_project, pinned_drop}; +use std::pin::Pin; + +pub struct Foo<'a, T> { + was_dropped: &'a mut bool, + field: T, +} + +#[allow(clippy::mut_mut)] +#[allow(dead_code)] +struct __FooProjection<'_pin, 'a, T> { + was_dropped: &'_pin mut &'a mut bool, + field: ::core::pin::Pin<&'_pin mut T>, +} + +impl<'_outer_pin, 'a, T> __FooProjectionTrait<'_outer_pin, 'a, T> + for ::core::pin::Pin<&'_outer_pin mut Foo<'a, T>> +{ + fn project<'_pin>(&'_pin mut self) -> __FooProjection<'_pin, 'a, T> { + unsafe { + let Foo { was_dropped, field } = self.as_mut().get_unchecked_mut(); + __FooProjection { + was_dropped: was_dropped, + field: ::core::pin::Pin::new_unchecked(field), + } + } + } + fn project_into(self) -> __FooProjection<'_outer_pin, 'a, T> { + unsafe { + let Foo { was_dropped, field } = self.get_unchecked_mut(); + __FooProjection { + was_dropped: was_dropped, + field: ::core::pin::Pin::new_unchecked(field), + } + } + } +} + +trait __FooProjectionTrait<'_outer_pin, 'a, T> { + fn project<'_pin>(&'_pin mut self) -> __FooProjection<'_pin, 'a, T>; + fn project_into(self) -> __FooProjection<'_outer_pin, 'a, T>; +} + +#[allow(single_use_lifetimes)] +impl<'a, T> ::core::ops::Drop for Foo<'a, T> { + fn drop(&mut self) { + // Safety - we're in 'drop', so we know that 'self' will + // never move again. + let pinned_self = unsafe { ::core::pin::Pin::new_unchecked(self) }; + // We call `pinned_drop` only once. Since `UnsafePinnedDrop::pinned_drop` + // is an unsafe function and a private API, it is never called again in safe + // code *unless the user uses a maliciously crafted macro*. + unsafe { + ::pin_project::__private::UnsafePinnedDrop::pinned_drop(pinned_self); + } + } +} + +unsafe impl ::pin_project::__private::UnsafePinnedDrop for Foo<'_, T> { + unsafe fn pinned_drop(self: ::core::pin::Pin<&mut Self>) { + // Declare the #[pinned_drop] function *inside* our pinned_drop function + // This guarantees that it's impossible for any other user code + // to call it. + fn drop_foo(mut foo: Pin<&mut Foo<'_, T>>) { + **foo.project().was_dropped = true; + } + + // #[pinned_drop] function is a free function - if it were part of a trait impl, + // it would be possible for user code to call it by directly invoking the trait. + drop_foo(self) + } +} + +// Automatically create the appropriate conditional `Unpin` implementation. +// +// See ./struct-default-expanded.rs and https://github.com/taiki-e/pin-project/pull/53. +// for details. +#[allow(non_snake_case)] +fn __unpin_scope_Foo() { + struct AlwaysUnpinFoo { + val: ::core::marker::PhantomData, + } + impl ::core::marker::Unpin for AlwaysUnpinFoo {} + #[allow(dead_code)] + #[doc(hidden)] + pub struct __UnpinStructFoo<'a, T> { + __pin_project_use_generics: AlwaysUnpinFoo<(T)>, + __field0: T, + __lifetime0: &'a (), + } + impl<'a, T> ::core::marker::Unpin for Foo<'a, T> where __UnpinStructFoo<'a, T>: ::core::marker::Unpin + {} +} + +// Ensure that it's impossible to use pin projections on a #[repr(packed)] struct. +// +// See ./struct-default-expanded.rs and https://github.com/taiki-e/pin-project/pull/34 +// for details. +#[allow(single_use_lifetimes)] +#[allow(non_snake_case)] +#[deny(safe_packed_borrows)] +fn __pin_project_assert_not_repr_packed_Foo<'a, T>(val: Foo<'a, T>) { + { + &val.was_dropped; + } + { + &val.field; + } +} + +fn main() {} diff --git a/examples/pinned_drop.rs b/examples/pinned_drop.rs new file mode 100644 index 00000000..fd57ce42 --- /dev/null +++ b/examples/pinned_drop.rs @@ -0,0 +1,20 @@ +// See ./pinned_drop-expanded.rs for generated code. + +#![allow(dead_code, unused_imports)] + +use pin_project::{pin_project, pinned_drop}; +use std::pin::Pin; + +#[pin_project(PinnedDrop)] +pub struct Foo<'a, T> { + was_dropped: &'a mut bool, + #[pin] + field: T, +} + +#[pinned_drop] +fn drop_foo(mut this: Pin<&mut Foo<'_, T>>) { + **this.project().was_dropped = true; +} + +fn main() {} diff --git a/examples/struct-default-expanded.rs b/examples/struct-default-expanded.rs new file mode 100644 index 00000000..d9cc2281 --- /dev/null +++ b/examples/struct-default-expanded.rs @@ -0,0 +1,145 @@ +// Original code (./struct-default.rs): +// +// ```rust +// #![allow(dead_code, unused_imports)] +// +// use pin_project::pin_project; +// +// #[pin_project] +// struct Struct { +// #[pin] +// pinned: T, +// unpinned: U, +// } +// +// fn main() {} +// ``` + +#![allow(dead_code, unused_imports)] + +use pin_project::pin_project; + +struct Struct { + pinned: T, + unpinned: U, +} + +#[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. +#[allow(dead_code)] // This lint warns unused fields/variants. +struct __StructProjection<'_pin, T, U> { + pinned: ::core::pin::Pin<&'_pin mut T>, + unpinned: &'_pin mut U, +} + +impl<'_outer_pin, T, U> __StructProjectionTrait<'_outer_pin, T, U> + for ::core::pin::Pin<&'_outer_pin mut Struct> +{ + fn project<'_pin>(&'_pin mut self) -> __StructProjection<'_pin, T, U> { + unsafe { + let Struct { pinned, unpinned } = self.as_mut().get_unchecked_mut(); + __StructProjection { + pinned: ::core::pin::Pin::new_unchecked(pinned), + unpinned: unpinned, + } + } + } + fn project_into(self) -> __StructProjection<'_outer_pin, T, U> { + unsafe { + let Struct { pinned, unpinned } = self.get_unchecked_mut(); + __StructProjection { + pinned: ::core::pin::Pin::new_unchecked(pinned), + unpinned: unpinned, + } + } + } +} + +trait __StructProjectionTrait<'_outer_pin, T, U> { + fn project<'_pin>(&'_pin mut self) -> __StructProjection<'_pin, T, U>; + fn project_into(self) -> __StructProjection<'_outer_pin, T, U>; +} + +// Automatically create the appropriate conditional `Unpin` implementation. +// +// Basically this is equivalent to the following code: +// ```rust +// impl Unpin for Struct where T: Unpin {} +// ``` +// +// However, if struct is public and there is a private type field, +// this would cause an E0446 (private type in public interface). +// +// When RFC 2145 is implemented (rust-lang/rust#48054), +// this will become a lint, rather then a hard error. +// +// As a workaround for this, we generate a new struct, containing all of the pinned +// fields from our #[pin_project] type. This struct is delcared within +// a function, which makes it impossible to be named by user code. +// This guarnatees that it will use the default auto-trait impl for Unpin - +// that is, it will implement Unpin iff all of its fields implement Unpin. +// This type can be safely declared as 'public', satisfiying the privacy +// checker without actually allowing user code to access it. +// +// This allows users to apply the #[pin_project] attribute to types +// regardless of the privacy of the types of their fields. +// +// See also https://github.com/taiki-e/pin-project/pull/53. +#[allow(non_snake_case)] +fn __unpin_scope_Struct() { + struct AlwaysUnpinStruct { + val: ::core::marker::PhantomData, + } + impl ::core::marker::Unpin for AlwaysUnpinStruct {} + #[allow(dead_code)] + #[doc(hidden)] + struct __UnpinStructStruct { + __pin_project_use_generics: AlwaysUnpinStruct<(T, U)>, + __field0: T, + } + impl ::core::marker::Unpin for Struct where + __UnpinStructStruct: ::core::marker::Unpin + { + } +} + +// Ensure that struct does not implement `Drop`. +// +// There are two possible cases: +// 1. The user type does not implement Drop. In this case, +// the first blanked impl will not apply to it. This code +// will compile, as there is only one impl of MustNotImplDrop for the user type +// 2. The user type does impl Drop. This will make the blanket impl applicable, +// which will then comflict with the explicit MustNotImplDrop impl below. +// This will result in a compilation error, which is exactly what we want. +trait StructMustNotImplDrop {} +#[allow(clippy::drop_bounds)] +impl StructMustNotImplDrop for T {} +#[allow(single_use_lifetimes)] +impl StructMustNotImplDrop for Struct {} + +// Ensure that it's impossible to use pin projections on a #[repr(packed)] struct. +// +// Taking a reference to a packed field is unsafe, amd appplying +// #[deny(safe_packed_borrows)] makes sure that doing this without +// an 'unsafe' block (which we deliberately do not generate) +// is a hard error. +// +// If the struct ends up having #[repr(packed)] applied somehow, +// this will generate an (unfriendly) error message. Under all reasonable +// circumstances, we'll detect the #[repr(packed)] attribute, and generate +// a much nicer error above. +// +// See https://github.com/taiki-e/pin-project/pull/34 for more details. +#[allow(single_use_lifetimes)] +#[allow(non_snake_case)] +#[deny(safe_packed_borrows)] +fn __pin_project_assert_not_repr_packed_Struct(val: Struct) { + { + &val.pinned; + } + { + &val.unpinned; + } +} + +fn main() {} diff --git a/examples/struct-default.rs b/examples/struct-default.rs index debc8ecb..72c1ad99 100644 --- a/examples/struct-default.rs +++ b/examples/struct-default.rs @@ -1,102 +1,14 @@ -//! -//! Original code: -//! -//! ```rust -//! #![allow(dead_code)] -//! -//! #[pin_project] -//! struct Struct { -//! #[pin] -//! pinned: T, -//! unpinned: U, -//! } -//! -//! fn main() {} -//! ``` +// See ./struct-default-expanded.rs for generated code. -#![allow(dead_code)] +#![allow(dead_code, unused_imports)] +use pin_project::pin_project; + +#[pin_project] struct Struct { + #[pin] pinned: T, unpinned: U, } -#[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. -#[allow(dead_code)] // This lint warns unused fields/variants. -struct __StructProjection<'_pin, T, U> { - pinned: ::core::pin::Pin<&'_pin mut T>, - unpinned: &'_pin mut U, -} - -impl<'_outer_pin, T, U> __StructProjectionTrait<'_outer_pin, T, U> - for ::core::pin::Pin<&'_outer_pin mut Struct> -{ - fn project<'_pin>(&'_pin mut self) -> __StructProjection<'_pin, T, U> { - unsafe { - let Struct { pinned, unpinned } = self.as_mut().get_unchecked_mut(); - __StructProjection { - pinned: ::core::pin::Pin::new_unchecked(pinned), - unpinned: unpinned, - } - } - } - fn project_into(self) -> __StructProjection<'_outer_pin, T, U> { - unsafe { - let Struct { pinned, unpinned } = self.get_unchecked_mut(); - __StructProjection { - pinned: ::core::pin::Pin::new_unchecked(pinned), - unpinned: unpinned, - } - } - } -} - -trait __StructProjectionTrait<'_outer_pin, T, U> { - fn project<'_pin>(&'_pin mut self) -> __StructProjection<'_pin, T, U>; - fn project_into(self) -> __StructProjection<'_outer_pin, T, U>; -} - -// Automatically create the appropriate conditional `Unpin` implementation. -impl Unpin for Struct where T: Unpin {} - -// Ensure that struct does not implement `Drop`. -// -// There are two possible cases: -// 1. The user type does not implement Drop. In this case, -// the first blanked impl will not apply to it. This code -// will compile, as there is only one impl of MustNotImplDrop for the user type -// 2. The user type does impl Drop. This will make the blanket impl applicable, -// which will then comflict with the explicit MustNotImplDrop impl below. -// This will result in a compilation error, which is exactly what we want. -trait StructMustNotImplDrop {} -#[allow(clippy::drop_bounds)] -impl StructMustNotImplDrop for T {} -#[allow(single_use_lifetimes)] -impl StructMustNotImplDrop for Struct {} - -// Ensure that it's impossible to use pin projections on a #[repr(packed)] struct. -// -// Taking a reference to a packed field is unsafe, amd appplying -// #[deny(safe_packed_borrows)] makes sure that doing this without -// an 'unsafe' block (which we deliberately do not generate) -// is a hard error. -// -// If the struct ends up having #[repr(packed)] applied somehow, -// this will generate an (unfriendly) error message. Under all reasonable -// circumstances, we'll detect the #[repr(packed)] attribute, and generate -// a much nicer error above. -// -// See https://github.com/taiki-e/pin-project/pull/34 for for more details. -#[allow(single_use_lifetimes)] -#[allow(non_snake_case)] -#[deny(safe_packed_borrows)] -fn __pin_project_assert_not_repr_packed_Struct(val: Struct) { - { - &val.pinned; - } - { - &val.unpinned; - } -} - fn main() {} diff --git a/examples/unsafe_unpin-expanded.rs b/examples/unsafe_unpin-expanded.rs new file mode 100644 index 00000000..69f8568c --- /dev/null +++ b/examples/unsafe_unpin-expanded.rs @@ -0,0 +1,90 @@ +// Original code (./unsafe_unpin.rs): +// +// ```rust +// #![allow(dead_code, unused_imports)] +// +// use pin_project::{pin_project, UnsafeUnpin}; +// +// #[pin_project(UnsafeUnpin)] +// pub struct Foo { +// #[pin] +// pinned: T, +// unpinned: U, +// } +// +// unsafe impl UnsafeUnpin for Foo {} +// +// fn main() {} +// ``` + +#![allow(dead_code, unused_imports)] + +use pin_project::{pin_project, UnsafeUnpin}; + +pub struct Foo { + pinned: T, + unpinned: U, +} + +#[allow(clippy::mut_mut)] +#[allow(dead_code)] +struct __FooProjection<'_pin, T, U> { + pinned: ::core::pin::Pin<&'_pin mut T>, + unpinned: &'_pin mut U, +} + +impl<'_outer_pin, T, U> __FooProjectionTrait<'_outer_pin, T, U> + for ::core::pin::Pin<&'_outer_pin mut Foo> +{ + fn project<'_pin>(&'_pin mut self) -> __FooProjection<'_pin, T, U> { + unsafe { + let Foo { pinned, unpinned } = self.as_mut().get_unchecked_mut(); + __FooProjection { pinned: ::core::pin::Pin::new_unchecked(pinned), unpinned: unpinned } + } + } + fn project_into(self) -> __FooProjection<'_outer_pin, T, U> { + unsafe { + let Foo { pinned, unpinned } = self.get_unchecked_mut(); + __FooProjection { pinned: ::core::pin::Pin::new_unchecked(pinned), unpinned: unpinned } + } + } +} + +trait __FooProjectionTrait<'_outer_pin, T, U> { + fn project<'_pin>(&'_pin mut self) -> __FooProjection<'_pin, T, U>; + fn project_into(self) -> __FooProjection<'_outer_pin, T, U>; +} + +unsafe impl UnsafeUnpin for Foo {} + +impl ::core::marker::Unpin for Foo where + ::pin_project::__private::Wrapper: ::pin_project::UnsafeUnpin +{ +} + +// Ensure that struct does not implement `Drop`. +// +// See ./struct-default-expanded.rs for details. +trait FooMustNotImplDrop {} +#[allow(clippy::drop_bounds)] +impl FooMustNotImplDrop for T {} +#[allow(single_use_lifetimes)] +impl FooMustNotImplDrop for Foo {} + +// Ensure that it's impossible to use pin projections on a #[repr(packed)] struct. +// +// See ./struct-default-expanded.rs and https://github.com/taiki-e/pin-project/pull/34 +// for details. +#[allow(single_use_lifetimes)] +#[allow(non_snake_case)] +#[deny(safe_packed_borrows)] +fn __pin_project_assert_not_repr_packed_Foo(val: Foo) { + { + &val.pinned; + } + { + &val.unpinned; + } +} + +fn main() {} diff --git a/examples/unsafe_unpin.rs b/examples/unsafe_unpin.rs new file mode 100644 index 00000000..3d5535c6 --- /dev/null +++ b/examples/unsafe_unpin.rs @@ -0,0 +1,16 @@ +// See ./pinned_drop-expanded.rs for generated code. + +#![allow(dead_code, unused_imports)] + +use pin_project::{pin_project, UnsafeUnpin}; + +#[pin_project(UnsafeUnpin)] +pub struct Foo { + #[pin] + pinned: T, + unpinned: U, +} + +unsafe impl UnsafeUnpin for Foo {} + +fn main() {} diff --git a/pin-project-internal/src/pinned_drop.rs b/pin-project-internal/src/pinned_drop.rs index 83affe07..9527df39 100644 --- a/pin-project-internal/src/pinned_drop.rs +++ b/pin-project-internal/src/pinned_drop.rs @@ -62,7 +62,7 @@ fn parse(item: &ItemFn) -> Result { #item // #[pinned_drop] function is a free function - if it were part of a trait impl, // it would be possible for user code to call it by directly invoking the trait. - #fn_name(self); + #fn_name(self) } } }) diff --git a/src/lib.rs b/src/lib.rs index f1faa4db..ce96e52f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,9 +30,9 @@ //! } //! ``` //! -//! [Code like this will be generated](https://github.com/taiki-e/pin-project/blob/master/examples/struct-default.rs) +//! [Code like this will be generated](https://github.com/taiki-e/pin-project/blob/master/examples/struct-default-expanded.rs) //! -//! See [`pin_project`] attribute for more details. +//! There are examples and generated code of each feature in [examples](https://github.com/taiki-e/pin-project/blob/master/examples/README.md) directory. //! //! [`pin_project`]: https://docs.rs/pin-project-internal/0.4.0-alpha.10/pin_project_internal/attr.pin_project.html //! [`pinned_drop`]: https://docs.rs/pin-project-internal/0.4.0-alpha.10/pin_project_internal/attr.pinned_drop.html