Skip to content

Commit

Permalink
Add project_ref method and #[project_ref] attribute
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Sep 20, 2019
1 parent 166c0f9 commit be9d73e
Show file tree
Hide file tree
Showing 11 changed files with 422 additions and 61 deletions.
16 changes: 16 additions & 0 deletions examples/enum-default-expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ enum __EnumProjection<'_pin, T, U> {
Unpinned(&'_pin mut U),
}

#[allow(dead_code)] // This lint warns unused fields/variants.
enum __EnumProjectionRef<'_pin, T, U> {
Pinned(::core::pin::Pin<&'_pin T>),
Unpinned(&'_pin U),
}

impl<T, U> Enum<T, U> {
fn project<'_pin>(self: ::core::pin::Pin<&'_pin mut Self>) -> __EnumProjection<'_pin, T, U> {
unsafe {
Expand All @@ -39,6 +45,16 @@ impl<T, U> Enum<T, U> {
}
}
}
fn project_ref<'_pin>(self: ::core::pin::Pin<&'_pin Self>) -> __EnumProjectionRef<'_pin, T, U> {
unsafe {
match self.get_ref() {
Enum::Pinned(_x0) => {
__EnumProjectionRef::Pinned(::core::pin::Pin::new_unchecked(_x0))
}
Enum::Unpinned(_x0) => __EnumProjectionRef::Unpinned(_x0),
}
}
}
}

// Automatically create the appropriate conditional `Unpin` implementation.
Expand Down
17 changes: 17 additions & 0 deletions examples/pinned_drop-expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,12 @@ pub(crate) struct __FooProjection<'_pin, 'a, T> {
field: ::core::pin::Pin<&'_pin mut T>,
}

#[allow(dead_code)]
pub(crate) struct __FooProjectionRef<'_pin, 'a, T> {
was_dropped: &'_pin &'a mut bool,
field: ::core::pin::Pin<&'_pin T>,
}

impl<'a, T> Foo<'a, T> {
pub(crate) fn project<'_pin>(
self: ::core::pin::Pin<&'_pin mut Self>,
Expand All @@ -50,6 +56,17 @@ impl<'a, T> Foo<'a, T> {
}
}
}
pub(crate) fn project_ref<'_pin>(
self: ::core::pin::Pin<&'_pin Self>,
) -> __FooProjectionRef<'_pin, 'a, T> {
unsafe {
let Foo { was_dropped, field } = self.get_ref();
__FooProjectionRef {
was_dropped: was_dropped,
field: ::core::pin::Pin::new_unchecked(field),
}
}
}
}

#[allow(single_use_lifetimes)]
Expand Down
16 changes: 16 additions & 0 deletions examples/struct-default-expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ struct __StructProjection<'_pin, T, U> {
pinned: ::core::pin::Pin<&'_pin mut T>,
unpinned: &'_pin mut U,
}
#[allow(dead_code)] // This lint warns unused fields/variants.
struct __StructProjectionRef<'_pin, T, U> {
pinned: ::core::pin::Pin<&'_pin T>,
unpinned: &'_pin U,
}

impl<T, U> Struct<T, U> {
fn project<'_pin>(self: ::core::pin::Pin<&'_pin mut Self>) -> __StructProjection<'_pin, T, U> {
Expand All @@ -41,6 +46,17 @@ impl<T, U> Struct<T, U> {
}
}
}
fn project_ref<'_pin>(
self: ::core::pin::Pin<&'_pin Self>,
) -> __StructProjectionRef<'_pin, T, U> {
unsafe {
let Struct { pinned, unpinned } = self.get_ref();
__StructProjectionRef {
pinned: ::core::pin::Pin::new_unchecked(pinned),
unpinned: unpinned,
}
}
}
}

// Automatically create the appropriate conditional `Unpin` implementation.
Expand Down
16 changes: 16 additions & 0 deletions examples/unsafe_unpin-expanded.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ pub(crate) struct __FooProjection<'_pin, T, U> {
pinned: ::core::pin::Pin<&'_pin mut T>,
unpinned: &'_pin mut U,
}
#[allow(dead_code)]
pub(crate) struct __FooProjectionRef<'_pin, T, U> {
pinned: ::core::pin::Pin<&'_pin T>,
unpinned: &'_pin U,
}

impl<T, U> Foo<T, U> {
pub(crate) fn project<'_pin>(
Expand All @@ -42,6 +47,17 @@ impl<T, U> Foo<T, U> {
__FooProjection { pinned: ::core::pin::Pin::new_unchecked(pinned), unpinned: unpinned }
}
}
pub(crate) fn project_ref<'_pin>(
self: ::core::pin::Pin<&'_pin Self>,
) -> __FooProjectionRef<'_pin, T, U> {
unsafe {
let Foo { pinned, unpinned } = self.get_ref();
__FooProjectionRef {
pinned: ::core::pin::Pin::new_unchecked(pinned),
unpinned: unpinned,
}
}
}
}

unsafe impl<T: Unpin, U> UnsafeUnpin for Foo<T, U> {}
Expand Down
36 changes: 29 additions & 7 deletions pin-project-internal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ mod project;
use proc_macro::TokenStream;
use syn::parse::Nothing;

use utils::{Immutable, Mutable};

// TODO: Move this doc into pin-project crate when https://github.com/rust-lang/rust/pull/62855 merged.
/// An attribute that creates a projection struct covering all the fields.
///
Expand All @@ -33,13 +35,15 @@ use syn::parse::Nothing;
/// the field.
/// - For the other fields, makes the unpinned reference to the field.
///
/// The following method is implemented on the original `#[pin_project]` type:
/// The following methods are implemented on the original `#[pin_project]` type:
///
/// ```
/// # use std::pin::Pin;
/// # type ProjectedType = ();
/// # trait Projection {
/// fn project(self: Pin<&mut Self>) -> ProjectedType;
/// # type Projection = ();
/// # type ProjectionRef = ();
/// # trait Dox {
/// fn project(self: Pin<&mut Self>) -> Projection;
/// fn project_ref(self: Pin<&Self>) -> ProjectionRef;
/// # }
/// ```
///
Expand Down Expand Up @@ -304,13 +308,14 @@ use syn::parse::Nothing;
///
/// Enums without variants (zero-variant enums) are not supported.
///
/// See also [`project`] attribute.
/// See also [`project`] and [`project_ref`] attributes.
///
/// [`Pin::as_mut`]: core::pin::Pin::as_mut
/// [`Pin::set`]: core::pin::Pin::set
/// [`drop`]: Drop::drop
/// [`UnsafeUnpin`]: https://docs.rs/pin-project/0.4.0-alpha.11/pin_project/trait.UnsafeUnpin.html
/// [`project`]: ./attr.project.html
/// [`project_ref`]: ./attr.project_ref.html
/// [`pinned_drop`]: ./attr.pinned_drop.html
#[proc_macro_attribute]
pub fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream {
Expand Down Expand Up @@ -361,7 +366,8 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
}

// TODO: Move this doc into pin-project crate when https://github.com/rust-lang/rust/pull/62855 merged.
/// An attribute to provide way to refer to the projected type.
/// An attribute to provide way to refer to the projected type returned by
/// `project` method.
///
/// The following syntaxes are supported.
///
Expand Down Expand Up @@ -507,7 +513,23 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
pub fn project(args: TokenStream, input: TokenStream) -> TokenStream {
let _: Nothing = syn::parse_macro_input!(args);
let input = syn::parse_macro_input!(input);
project::attribute(input).into()
project::attribute(input, Mutable).into()
}

/// An attribute to provide way to refer to the projected type returned by
/// `project_ref` method.
///
/// This is the same as [`project`] attribute except it refers to the projected
/// type returned by `project_ref` method.
///
/// See [`project`] attribute for more details.
///
/// [`project`]: ./attr.project.html
#[proc_macro_attribute]
pub fn project_ref(args: TokenStream, input: TokenStream) -> TokenStream {
let _: Nothing = syn::parse_macro_input!(args);
let input = syn::parse_macro_input!(input);
project::attribute(input, Immutable).into()
}

#[doc(hidden)]
Expand Down
Loading

0 comments on commit be9d73e

Please sign in to comment.