Skip to content

Commit

Permalink
Allow naming the projected types
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed May 7, 2020
1 parent dec0b16 commit 2eecdb0
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 26 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 23 additions & 4 deletions pin-project-internal/src/pin_project/derive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,12 @@ struct Args {
unsafe_unpin: Option<Span>,
/// `Replace`.
replace: Option<Span>,
/// `project = <ident>`.
project: Option<Ident>,
/// `project_ref = <ident>`.
project_ref: Option<Ident>,
/// `project_replace = <ident>`.
project_replace: Option<Ident>,
}

const DUPLICATE_PIN: &str = "duplicate #[pin] attribute";
Expand Down Expand Up @@ -216,6 +222,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)),
}

Expand Down Expand Up @@ -297,7 +315,8 @@ impl<'a> Context<'a> {
ident: &'a Ident,
generics: &'a mut Generics,
) -> Result<Self> {
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;
let self_ty = syn::parse_quote!(#ident #ty_generics);
Expand All @@ -323,9 +342,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,
Expand Down
60 changes: 40 additions & 20 deletions tests/pin_project.rs
Original file line number Diff line number Diff line change
@@ -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<T, U> {
#[pin]
field1: T,
Expand All @@ -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<i32> = field1;
let _: i32 = field2;
assert_eq!(field2, 2);
assert_eq!(s.field1, 3);
assert_eq!(s.field2, 4);

#[pin_project(Replace)]
struct TupleStruct<T, U>(#[pin] T, U);

Expand All @@ -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<A, B, C, D> {
Variant1(#[pin] A, B),
Expand All @@ -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));
Expand All @@ -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);

Expand All @@ -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),
Expand All @@ -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);
}
Expand Down Expand Up @@ -362,7 +382,7 @@ fn lifetime_project() {
unpinned: U,
}

#[pin_project(Replace)]
#[pin_project(Replace, project = EnumProj, project_ref = EnumProjRef)]
enum Enum<T, U> {
Variant {
#[pin]
Expand Down Expand Up @@ -392,12 +412,12 @@ fn lifetime_project() {
impl<T, U> Enum<T, U> {
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,
}
}
}
Expand All @@ -420,7 +440,7 @@ fn lifetime_project_elided() {
unpinned: U,
}

#[pin_project(Replace)]
#[pin_project(Replace, project = EnumProj, project_ref = EnumProjRef)]
enum Enum<T, U> {
Variant {
#[pin]
Expand Down Expand Up @@ -450,12 +470,12 @@ fn lifetime_project_elided() {
impl<T, U> Enum<T, U> {
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,
}
}
}
Expand Down

0 comments on commit 2eecdb0

Please sign in to comment.