Skip to content

Commit

Permalink
Change self argument of project method to self: Pin<&mut Self>
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Sep 4, 2019
1 parent 5317091 commit 8735be8
Show file tree
Hide file tree
Showing 10 changed files with 89 additions and 62 deletions.
23 changes: 13 additions & 10 deletions pin-project-internal/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
#![recursion_limit = "256"]
#![doc(html_root_url = "https://docs.rs/pin-project-internal/0.4.0-alpha.8")]
#![doc(test(no_crate_inject, attr(deny(warnings, rust_2018_idioms), allow(dead_code))))]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms, single_use_lifetimes), allow(dead_code))
))]
#![warn(unsafe_code)]
#![warn(rust_2018_idioms, unreachable_pub, single_use_lifetimes)]
#![warn(clippy::all, clippy::pedantic)]
Expand Down Expand Up @@ -104,7 +107,7 @@ use syn::parse::Nothing;
/// }
///
/// impl<T, U> Foo<T, U> {
/// fn baz(mut self: Pin<&mut Self>) {
/// fn baz(self: Pin<&mut Self>) {
/// let this = self.project();
/// let _: Pin<&mut T> = this.future; // Pinned reference to the field
/// let _: &mut U = this.field; // Normal reference to the field
Expand All @@ -127,7 +130,7 @@ use syn::parse::Nothing;
/// }
///
/// impl<T, U> Foo<T, U> {
/// fn baz(mut self: Pin<&mut Self>) {
/// fn baz(self: Pin<&mut Self>) {
/// let this = self.project();
/// let _: Pin<&mut T> = this.future; // Pinned reference to the field
/// let _: &mut U = this.field; // Normal reference to the field
Expand Down Expand Up @@ -174,7 +177,7 @@ use syn::parse::Nothing;
/// }
///
/// #[pinned_drop]
/// fn my_drop_fn<T: Debug, U: Debug>(mut foo: Pin<&mut Foo<T, U>>) {
/// fn my_drop_fn<T: Debug, U: Debug>(foo: Pin<&mut Foo<T, U>>) {
/// let foo = foo.project();
/// println!("Dropping pinned field: {:?}", foo.pinned_field);
/// println!("Dropping unpin field: {:?}", foo.unpin_field);
Expand Down Expand Up @@ -205,7 +208,7 @@ use syn::parse::Nothing;
/// }
///
/// impl<T, U> Foo<T, U> {
/// fn baz(mut self: Pin<&mut Self>) {
/// fn baz(self: Pin<&mut Self>) {
/// let this = self.project();
/// let _: Pin<&mut T> = this.future;
/// let _: &mut U = this.field;
Expand All @@ -223,7 +226,7 @@ use syn::parse::Nothing;
/// struct Foo<T, U>(#[pin] T, U);
///
/// impl<T, U> Foo<T, U> {
/// fn baz(mut self: Pin<&mut Self>) {
/// fn baz(self: Pin<&mut Self>) {
/// let this = self.project();
/// let _: Pin<&mut T> = this.0;
/// let _: &mut U = this.1;
Expand Down Expand Up @@ -262,7 +265,7 @@ use syn::parse::Nothing;
/// # #[cfg(feature = "project_attr")]
/// impl<A, B, C> Foo<A, B, C> {
/// #[project] // Nightly does not need a dummy attribute to the function.
/// fn baz(mut self: Pin<&mut Self>) {
/// fn baz(self: Pin<&mut Self>) {
/// #[project]
/// match self.project() {
/// Foo::Tuple(x, y) => {
Expand Down Expand Up @@ -363,7 +366,7 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
///
/// // impl for the original type
/// impl<T, U> Foo<T, U> {
/// fn bar(mut self: Pin<&mut Self>) {
/// fn bar(self: Pin<&mut Self>) {
/// self.project().baz()
/// }
/// }
Expand Down Expand Up @@ -400,7 +403,7 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
///
/// impl<T, U> Foo<T, U> {
/// #[project] // Nightly does not need a dummy attribute to the function.
/// fn baz(mut self: Pin<&mut Self>) {
/// fn baz(self: Pin<&mut Self>) {
/// #[project]
/// let Foo { future, field } = self.project();
///
Expand Down Expand Up @@ -430,7 +433,7 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream {
///
/// impl<A, B, C> Foo<A, B, C> {
/// #[project] // Nightly does not need a dummy attribute to the function.
/// fn baz(mut self: Pin<&mut Self>) {
/// fn baz(self: Pin<&mut Self>) {
/// #[project]
/// match self.project() {
/// Foo::Tuple(x, y) => {
Expand Down
12 changes: 7 additions & 5 deletions pin-project-internal/src/pin_project/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,21 +31,23 @@ pub(super) fn parse(cx: &mut Context, mut item: ItemEnum) -> Result<TokenStream>

let (proj_variants, proj_arms) = variants(cx, &mut item)?;

let Context { proj_ident, proj_trait, orig_ident, lifetime, .. } = &cx;
let Context { proj_ident, orig_ident, lifetime, .. } = &cx;
let proj_generics = cx.proj_generics();
let proj_ty_generics = proj_generics.split_for_impl().1;
let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
let (orig_impl_generics, orig_ty_generics, where_clause) = item.generics.split_for_impl();

let mut proj_items = quote! {
#[allow(clippy::mut_mut)]
#[allow(dead_code)]
enum #proj_ident #proj_generics #where_clause { #(#proj_variants,)* }
};
proj_items.extend(quote! {
impl #impl_generics #proj_trait #ty_generics for ::core::pin::Pin<&mut #orig_ident #ty_generics> #where_clause {
fn project<#lifetime>(&#lifetime mut self) -> #proj_ident #proj_ty_generics #where_clause {
impl #orig_impl_generics #orig_ident #orig_ty_generics #where_clause {
fn project<#lifetime>(
self: ::core::pin::Pin<&#lifetime mut Self>,
) -> #proj_ident #proj_ty_generics {
unsafe {
match self.as_mut().get_unchecked_mut() {
match self.get_unchecked_mut() {
#(#proj_arms,)*
}
}
Expand Down
25 changes: 1 addition & 24 deletions pin-project-internal/src/pin_project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ use syn::{
*,
};

use crate::utils::{
self, crate_path, proj_ident, proj_lifetime_name, proj_trait_ident, DEFAULT_LIFETIME_NAME,
};
use crate::utils::{self, crate_path, proj_ident, proj_lifetime_name, DEFAULT_LIFETIME_NAME};

mod enums;
mod structs;
Expand Down Expand Up @@ -56,9 +54,6 @@ struct Context {
orig_ident: Ident,
/// Name of the projected type.
proj_ident: Ident,
/// Name of the trait generated
/// to provide a 'project' method
proj_trait: Ident,

/// Visibility of original type.
vis: Visibility,
Expand Down Expand Up @@ -86,7 +81,6 @@ impl Context {
) -> Result<Self> {
let Args { pinned_drop, unsafe_unpin } = syn::parse2(args)?;
let proj_ident = proj_ident(orig_ident);
let proj_trait = proj_trait_ident(orig_ident);

let mut lifetime_name = String::from(DEFAULT_LIFETIME_NAME);
proj_lifetime_name(&mut lifetime_name, &generics.params);
Expand All @@ -107,7 +101,6 @@ impl Context {
Ok(Self {
orig_ident: orig_ident.clone(),
proj_ident,
proj_trait,
vis: vis.clone(),
generics,
lifetime,
Expand Down Expand Up @@ -339,20 +332,6 @@ impl Context {
}
}
}

fn make_proj_trait(&self) -> TokenStream {
let Self { proj_ident, proj_trait, lifetime, .. } = self;
let proj_generics = self.proj_generics();
let proj_ty_generics = proj_generics.split_for_impl().1;

let (orig_generics, _, orig_where_clause) = self.generics.split_for_impl();

quote! {
trait #proj_trait #orig_generics {
fn project<#lifetime>(&#lifetime mut self) -> #proj_ident #proj_ty_generics #orig_where_clause;
}
}
}
}

fn parse(args: TokenStream, input: TokenStream) -> Result<TokenStream> {
Expand All @@ -365,7 +344,6 @@ fn parse(args: TokenStream, input: TokenStream) -> Result<TokenStream> {
res.extend(packed_check);
res.extend(cx.make_drop_impl());
res.extend(cx.make_unpin_impl());
res.extend(cx.make_proj_trait());
Ok(res)
}
Item::Enum(item) => {
Expand All @@ -376,7 +354,6 @@ fn parse(args: TokenStream, input: TokenStream) -> Result<TokenStream> {
let mut res = enums::parse(&mut cx, item)?;
res.extend(cx.make_drop_impl());
res.extend(cx.make_unpin_impl());
res.extend(cx.make_proj_trait());
Ok(res)
}
item => Err(error!(item, "#[pin_project] attribute may only be used on structs or enums")),
Expand Down
12 changes: 7 additions & 5 deletions pin-project-internal/src/pin_project/structs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,21 +28,23 @@ pub(super) fn parse(cx: &mut Context, mut item: ItemStruct) -> Result<TokenStrea
Fields::Unnamed(fields) => unnamed(cx, fields)?,
};

let Context { proj_ident, proj_trait, orig_ident, lifetime, .. } = &cx;
let Context { proj_ident, orig_ident, lifetime, .. } = &cx;
let proj_generics = cx.proj_generics();
let proj_ty_generics = proj_generics.split_for_impl().1;
let (impl_generics, ty_generics, where_clause) = item.generics.split_for_impl();
let (orig_impl_generics, orig_ty_generics, where_clause) = item.generics.split_for_impl();

let mut proj_items = quote! {
#[allow(clippy::mut_mut)]
#[allow(dead_code)]
struct #proj_ident #proj_generics #where_clause #proj_fields
};
proj_items.extend(quote! {
impl #impl_generics #proj_trait #ty_generics for ::core::pin::Pin<&mut #orig_ident #ty_generics> #where_clause {
fn project<#lifetime>(&#lifetime mut self) -> #proj_ident #proj_ty_generics #where_clause {
impl #orig_impl_generics #orig_ident #orig_ty_generics #where_clause {
fn project<#lifetime>(
self: ::core::pin::Pin<&#lifetime mut Self>,
) -> #proj_ident #proj_ty_generics {
unsafe {
let this = self.as_mut().get_unchecked_mut();
let this = self.get_unchecked_mut();
#proj_ident #proj_init
}
}
Expand Down
4 changes: 0 additions & 4 deletions pin-project-internal/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ pub(crate) fn proj_ident(ident: &Ident) -> Ident {
format_ident!("__{}Projection", ident)
}

pub(crate) fn proj_trait_ident(ident: &Ident) -> Ident {
format_ident!("__{}ProjectionTrait", ident)
}

/// Determine the lifetime names. Ensure it doesn't overlap with any existing lifetime names.
pub(crate) fn proj_lifetime_name(
lifetime_name: &mut String,
Expand Down
7 changes: 5 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
//! }
//!
//! impl<T, U> Foo<T, U> {
//! fn baz(mut self: Pin<&mut Self>) {
//! fn baz(self: Pin<&mut Self>) {
//! let this = self.project();
//! let _: Pin<&mut T> = this.future; // Pinned reference to the field
//! let _: &mut U = this.field; // Normal reference to the field
Expand Down Expand Up @@ -86,7 +86,10 @@
#![recursion_limit = "256"]
#![doc(html_root_url = "https://docs.rs/pin-project/0.4.0-alpha.8")]
#![doc(test(no_crate_inject, attr(deny(warnings, rust_2018_idioms), allow(dead_code))))]
#![doc(test(
no_crate_inject,
attr(deny(warnings, rust_2018_idioms, single_use_lifetimes), allow(dead_code))
))]
#![no_std]
#![warn(unsafe_code)]
#![warn(rust_2018_idioms, unreachable_pub, single_use_lifetimes)]
Expand Down
58 changes: 51 additions & 7 deletions tests/pin_project.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ fn test_pin_project() {
let mut foo = Foo { field1: 1, field2: 2 };

let mut foo_orig = Pin::new(&mut foo);
let foo = foo_orig.project();
let foo = foo_orig.as_mut().project();

let x: Pin<&mut i32> = foo.field1;
assert_eq!(*x, 1);
Expand All @@ -33,7 +33,7 @@ fn test_pin_project() {

let mut foo = Foo { field1: 1, field2: 2 };

let mut foo = Pin::new(&mut foo);
let foo = Pin::new(&mut foo);
let foo = foo.project();

let __FooProjection { field1, field2 } = foo;
Expand All @@ -47,7 +47,7 @@ fn test_pin_project() {

let mut bar = Bar(1, 2);

let mut bar = Pin::new(&mut bar);
let bar = Pin::new(&mut bar);
let bar = bar.project();

let x: Pin<&mut i32> = bar.0;
Expand All @@ -73,7 +73,7 @@ fn test_pin_project() {
let mut baz = Baz::Variant1(1, 2);

let mut baz_orig = Pin::new(&mut baz);
let baz = baz_orig.project();
let baz = baz_orig.as_mut().project();

match baz {
__BazProjection::Variant1(x, y) => {
Expand All @@ -94,7 +94,7 @@ fn test_pin_project() {

let mut baz = Baz::Variant2 { field1: 3, field2: 4 };

let mut baz = Pin::new(&mut baz);
let baz = Pin::new(&mut baz);
let mut baz = baz.project();

match &mut baz {
Expand Down Expand Up @@ -132,7 +132,7 @@ fn enum_project_set() {

let mut bar = Bar::Variant1(25);
let mut bar_orig = Pin::new(&mut bar);
let bar_proj = bar_orig.project();
let bar_proj = bar_orig.as_mut().project();

match bar_proj {
__BarProjection::Variant1(val) => {
Expand Down Expand Up @@ -239,11 +239,11 @@ fn combine() {
unsafe impl<T: Unpin> UnsafeUnpin for Foo<T> {}
}

#[test]
// This 'allow' is unrelated to the code
// generated by pin-project - it's just to
// allow us to put a private enum in a public enum
#[allow(private_in_public)]
#[test]
fn test_private_type_in_public_type() {
#[pin_project]
pub struct PublicStruct<T> {
Expand All @@ -262,3 +262,47 @@ fn test_private_type_in_public_type() {
OtherVariant(u8),
}
}

// https://github.com/taiki-e/pin-project/issues/65
#[test]
fn test_lifetime_project() {
#[pin_project]
struct Struct<T, U> {
#[pin]
pinned: T,
unpinned: U,
}

#[pin_project]
enum Enum<T, U> {
Variant {
#[pin]
pinned: T,
unpinned: U,
},
}

impl<T, U> Struct<T, U> {
fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
self.project().pinned
}

fn get_pin_mut_elided(self: Pin<&mut Self>) -> Pin<&mut T> {
self.project().pinned
}
}

impl<T, U> Enum<T, U> {
fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> {
match self.project() {
__EnumProjection::Variant { pinned, .. } => pinned,
}
}

fn get_pin_mut_elided(self: Pin<&mut Self>) -> Pin<&mut T> {
match self.project() {
__EnumProjection::Variant { pinned, .. } => pinned,
}
}
}
}
2 changes: 1 addition & 1 deletion tests/pinned_drop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub struct Foo<'a> {
}

#[pinned_drop]
fn do_drop(mut foo: Pin<&mut Foo<'_>>) {
fn do_drop(foo: Pin<&mut Foo<'_>>) {
**foo.project().was_dropped = true;
}

Expand Down
Loading

0 comments on commit 8735be8

Please sign in to comment.