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

Add project_ref method and #[project_ref] attribute #93

Merged
merged 1 commit into from
Sep 20, 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
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