Skip to content

Commit

Permalink
Merge #79
Browse files Browse the repository at this point in the history
79: Add more examples and generated code r=taiki-e a=taiki-e



Co-authored-by: Taiki Endo <te316e89@gmail.com>
  • Loading branch information
bors[bot] and taiki-e authored Sep 9, 2019
2 parents 33968d8 + ecf2cf6 commit 6eac367
Show file tree
Hide file tree
Showing 12 changed files with 523 additions and 170 deletions.
6 changes: 2 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,9 @@ impl<T, U> Struct<T, U> {
}
```

[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

Expand Down
9 changes: 9 additions & 0 deletions examples/README.md
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)
90 changes: 90 additions & 0 deletions examples/enum-default-expanded.rs
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() {}
75 changes: 6 additions & 69 deletions examples/enum-default.rs
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() {}
136 changes: 136 additions & 0 deletions examples/pinned_drop-expanded.rs
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() {}
20 changes: 20 additions & 0 deletions examples/pinned_drop.rs
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() {}
Loading

0 comments on commit 6eac367

Please sign in to comment.