-
-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
79: Add more examples and generated code r=taiki-e a=taiki-e Co-authored-by: Taiki Endo <te316e89@gmail.com>
- Loading branch information
Showing
12 changed files
with
523 additions
and
170 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// Original code (./enum-default.rs): | ||
// | ||
// ```rust | ||
// #![allow(dead_code, unused_imports)] | ||
// | ||
// use pin_project::pin_project; | ||
// | ||
// #[pin_project] | ||
// enum Enum<T, U> { | ||
// Pinned(#[pin] T), | ||
// Unpinned(U), | ||
// } | ||
// | ||
// fn main() {} | ||
// ``` | ||
|
||
#![allow(dead_code, unused_imports)] | ||
|
||
use pin_project::pin_project; | ||
|
||
enum Enum<T, U> { | ||
Pinned(T), | ||
Unpinned(U), | ||
} | ||
|
||
#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. | ||
#[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<T, U>> | ||
{ | ||
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<T: ?Sized> { | ||
val: ::core::marker::PhantomData<T>, | ||
} | ||
impl<T: ?Sized> ::core::marker::Unpin for AlwaysUnpinEnum<T> {} | ||
#[allow(dead_code)] | ||
#[doc(hidden)] | ||
struct __UnpinStructEnum<T, U> { | ||
__pin_project_use_generics: AlwaysUnpinEnum<(T, U)>, | ||
__field0: T, | ||
} | ||
impl<T, U> ::core::marker::Unpin for Enum<T, U> where __UnpinStructEnum<T, U>: ::core::marker::Unpin {} | ||
} | ||
|
||
// Ensure that enum does not implement `Drop`. | ||
// | ||
// See ./struct-default-expanded.rs for details. | ||
trait EnumMustNotImplDrop {} | ||
#[allow(clippy::drop_bounds)] | ||
impl<T: Drop> EnumMustNotImplDrop for T {} | ||
#[allow(single_use_lifetimes)] | ||
impl<T, U> EnumMustNotImplDrop for Enum<T, U> {} | ||
|
||
// We don't need to check for '#[repr(packed)]', | ||
// since it does not apply to enums. | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,76 +1,13 @@ | ||
//! | ||
//! Original code: | ||
//! | ||
//! ```rust | ||
//! #![allow(dead_code)] | ||
//! | ||
//! #[pin_project] | ||
//! enum Enum<T, U> { | ||
//! 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<T, U> { | ||
Pinned(T), | ||
Pinned(#[pin] T), | ||
Unpinned(U), | ||
} | ||
|
||
#[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. | ||
#[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<T, U>> | ||
{ | ||
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<T, U> Unpin for Enum<T, U> 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<T: Drop> EnumMustNotImplDrop for T {} | ||
#[allow(single_use_lifetimes)] | ||
impl<T, U> EnumMustNotImplDrop for Enum<T, U> {} | ||
|
||
// We don't need to check for '#[repr(packed)]', | ||
// since it does not apply to enums. | ||
|
||
fn main() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<T>(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<T> ::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<T>(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<T: ?Sized> { | ||
val: ::core::marker::PhantomData<T>, | ||
} | ||
impl<T: ?Sized> ::core::marker::Unpin for AlwaysUnpinFoo<T> {} | ||
#[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() {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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<T>(mut this: Pin<&mut Foo<'_, T>>) { | ||
**this.project().was_dropped = true; | ||
} | ||
|
||
fn main() {} |
Oops, something went wrong.