From e875c5a1979e006571d00971736ce1ae2163d47a Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Thu, 7 May 2020 11:32:28 +0900 Subject: [PATCH] Allow naming the projected types --- .github/workflows/ci.yml | 4 +- .../src/pin_project/derive.rs | 27 +++++++-- tests/pin_project.rs | 60 ++++++++++++------- 3 files changed, 65 insertions(+), 26 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 02469bd6..2666d398 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -27,8 +27,8 @@ jobs: # This is the minimum supported Rust version of this crate. # When updating this, the reminder to update the minimum supported # Rust version in README.md. - - build: 1.33.0 - rust: 1.33.0 + - build: 1.34.0 + rust: 1.34.0 - build: 1.36.0 rust: 1.36.0 - build: 1.37.0 diff --git a/pin-project-internal/src/pin_project/derive.rs b/pin-project-internal/src/pin_project/derive.rs index b2f4972f..9e34aff5 100644 --- a/pin-project-internal/src/pin_project/derive.rs +++ b/pin-project-internal/src/pin_project/derive.rs @@ -136,6 +136,12 @@ struct Args { unsafe_unpin: Option, /// `Replace`. replace: Option, + /// `project = `. + project: Option, + /// `project_ref = `. + project_ref: Option, + /// `project_replace = `. + project_replace: Option, } const DUPLICATE_PIN: &str = "duplicate #[pin] attribute"; @@ -232,6 +238,18 @@ impl Parse for Args { "UnsafeUnpin" => { replace(&mut args.unsafe_unpin, token.span(), &token)?; } + "project" => { + let _: token::Eq = input.parse()?; + replace(&mut args.project, input.parse()?, &token)?; + } + "project_ref" => { + let _: token::Eq = input.parse()?; + replace(&mut args.project_ref, input.parse()?, &token)?; + } + "project_replace" => { + let _: token::Eq = input.parse()?; + replace(&mut args.project_replace, input.parse()?, &token)?; + } _ => return Err(error!(token, "unexpected argument: {}", token)), } @@ -313,7 +331,8 @@ impl<'a> Context<'a> { ident: &'a Ident, generics: &'a mut Generics, ) -> Result { - let Args { pinned_drop, unsafe_unpin, replace } = Args::get(attrs)?; + let Args { pinned_drop, unsafe_unpin, replace, project, project_ref, project_replace } = + Args::get(attrs)?; { let ty_generics = generics.split_for_impl().1; @@ -341,9 +360,9 @@ impl<'a> Context<'a> { Ok(Self { proj: ProjectedType { vis: determine_visibility(vis), - mut_ident: proj_ident(ident, Mutable), - ref_ident: proj_ident(ident, Immutable), - own_ident: proj_ident(ident, Owned), + mut_ident: project.unwrap_or_else(|| proj_ident(ident, Mutable)), + ref_ident: project_ref.unwrap_or_else(|| proj_ident(ident, Immutable)), + own_ident: project_replace.unwrap_or_else(|| proj_ident(ident, Owned)), lifetime, generics: proj_generics, where_clause, diff --git a/tests/pin_project.rs b/tests/pin_project.rs index 970016f8..61f03837 100644 --- a/tests/pin_project.rs +++ b/tests/pin_project.rs @@ -1,12 +1,20 @@ #![warn(rust_2018_idioms, single_use_lifetimes)] #![allow(dead_code)] -use core::{marker::PhantomPinned, pin::Pin}; +use core::{ + marker::{PhantomData, PhantomPinned}, + pin::Pin, +}; use pin_project::{pin_project, pinned_drop, UnsafeUnpin}; #[test] fn projection() { - #[pin_project(Replace)] + #[pin_project( + Replace, + project = StructProj, + project_ref = StructProjRef, + project_replace = StructProjOwn, + )] struct Struct { #[pin] field1: T, @@ -27,12 +35,24 @@ fn projection() { assert_eq!(s_orig.as_ref().field2, 2); let mut s = Struct { field1: 1, field2: 2 }; - let s = Pin::new(&mut s).project(); - let __StructProjection { field1, field2 } = s; + let StructProj { field1, field2 } = Pin::new(&mut s).project(); let _: Pin<&mut i32> = field1; let _: &mut i32 = field2; + let StructProjRef { field1, field2 } = Pin::new(&s).project_ref(); + let _: Pin<&i32> = field1; + let _: &i32 = field2; + + let mut s = Pin::new(&mut s); + let StructProjOwn { field1, field2 } = + s.as_mut().project_replace(Struct { field1: 3, field2: 4 }); + let _: PhantomData = field1; + let _: i32 = field2; + assert_eq!(field2, 2); + assert_eq!(s.field1, 3); + assert_eq!(s.field2, 4); + #[pin_project(Replace)] struct TupleStruct(#[pin] T, U); @@ -45,7 +65,7 @@ fn projection() { let y: &mut i32 = s.1; assert_eq!(*y, 2); - #[pin_project(Replace)] + #[pin_project(Replace, project = EnumProj)] #[derive(Eq, PartialEq, Debug)] enum Enum { Variant1(#[pin] A, B), @@ -62,18 +82,18 @@ fn projection() { let e = e_orig.as_mut().project(); match e { - __EnumProjection::Variant1(x, y) => { + EnumProj::Variant1(x, y) => { let x: Pin<&mut i32> = x; assert_eq!(*x, 1); let y: &mut i32 = y; assert_eq!(*y, 2); } - __EnumProjection::Variant2 { field1, field2 } => { + EnumProj::Variant2 { field1, field2 } => { let _x: Pin<&mut i32> = field1; let _y: &mut i32 = field2; } - __EnumProjection::None => {} + EnumProj::None => {} } assert_eq!(Pin::into_ref(e_orig).get_ref(), &Enum::Variant1(1, 2)); @@ -82,21 +102,21 @@ fn projection() { let mut e = Pin::new(&mut e).project(); match &mut e { - __EnumProjection::Variant1(x, y) => { + EnumProj::Variant1(x, y) => { let _x: &mut Pin<&mut i32> = x; let _y: &mut &mut i32 = y; } - __EnumProjection::Variant2 { field1, field2 } => { + EnumProj::Variant2 { field1, field2 } => { let x: &mut Pin<&mut i32> = field1; assert_eq!(**x, 3); let y: &mut &mut i32 = field2; assert_eq!(**y, 4); } - __EnumProjection::None => {} + EnumProj::None => {} } - if let __EnumProjection::Variant2 { field1, field2 } = e { + if let EnumProj::Variant2 { field1, field2 } = e { let x: Pin<&mut i32> = field1; assert_eq!(*x, 3); @@ -107,7 +127,7 @@ fn projection() { #[test] fn enum_project_set() { - #[pin_project(Replace)] + #[pin_project(Replace, project = EnumProj)] #[derive(Eq, PartialEq, Debug)] enum Enum { Variant1(#[pin] u8), @@ -119,7 +139,7 @@ fn enum_project_set() { let e_proj = e_orig.as_mut().project(); match e_proj { - __EnumProjection::Variant1(val) => { + EnumProj::Variant1(val) => { let new_e = Enum::Variant2(val.as_ref().get_ref() == &25); e_orig.set(new_e); } @@ -362,7 +382,7 @@ fn lifetime_project() { unpinned: U, } - #[pin_project(Replace)] + #[pin_project(Replace, project = EnumProj, project_ref = EnumProjRef)] enum Enum { Variant { #[pin] @@ -392,12 +412,12 @@ fn lifetime_project() { impl Enum { fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> { match self.project_ref() { - __EnumProjectionRef::Variant { pinned, .. } => pinned, + EnumProjRef::Variant { pinned, .. } => pinned, } } fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> { match self.project() { - __EnumProjection::Variant { pinned, .. } => pinned, + EnumProj::Variant { pinned, .. } => pinned, } } } @@ -420,7 +440,7 @@ fn lifetime_project_elided() { unpinned: U, } - #[pin_project(Replace)] + #[pin_project(Replace, project = EnumProj, project_ref = EnumProjRef)] enum Enum { Variant { #[pin] @@ -450,12 +470,12 @@ fn lifetime_project_elided() { impl Enum { fn get_pin_ref(self: Pin<&Self>) -> Pin<&T> { match self.project_ref() { - __EnumProjectionRef::Variant { pinned, .. } => pinned, + EnumProjRef::Variant { pinned, .. } => pinned, } } fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut T> { match self.project() { - __EnumProjection::Variant { pinned, .. } => pinned, + EnumProj::Variant { pinned, .. } => pinned, } } }