diff --git a/pin-project-internal/src/lib.rs b/pin-project-internal/src/lib.rs index f7a73865..a21a3b08 100644 --- a/pin-project-internal/src/lib.rs +++ b/pin-project-internal/src/lib.rs @@ -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)] @@ -104,7 +107,7 @@ use syn::parse::Nothing; /// } /// /// impl Foo { -/// 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 @@ -127,7 +130,7 @@ use syn::parse::Nothing; /// } /// /// impl Foo { -/// 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 @@ -174,7 +177,7 @@ use syn::parse::Nothing; /// } /// /// #[pinned_drop] -/// fn my_drop_fn(mut foo: Pin<&mut Foo>) { +/// fn my_drop_fn(foo: Pin<&mut Foo>) { /// let foo = foo.project(); /// println!("Dropping pinned field: {:?}", foo.pinned_field); /// println!("Dropping unpin field: {:?}", foo.unpin_field); @@ -205,7 +208,7 @@ use syn::parse::Nothing; /// } /// /// impl Foo { -/// 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; @@ -223,7 +226,7 @@ use syn::parse::Nothing; /// struct Foo(#[pin] T, U); /// /// impl Foo { -/// 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; @@ -262,7 +265,7 @@ use syn::parse::Nothing; /// # #[cfg(feature = "project_attr")] /// impl Foo { /// #[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) => { @@ -363,7 +366,7 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { /// /// // impl for the original type /// impl Foo { -/// fn bar(mut self: Pin<&mut Self>) { +/// fn bar(self: Pin<&mut Self>) { /// self.project().baz() /// } /// } @@ -400,7 +403,7 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { /// /// impl Foo { /// #[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(); /// @@ -430,7 +433,7 @@ pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { /// /// impl Foo { /// #[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) => { diff --git a/pin-project-internal/src/pin_project/enums.rs b/pin-project-internal/src/pin_project/enums.rs index 9c3cbaaa..5eb4d82e 100644 --- a/pin-project-internal/src/pin_project/enums.rs +++ b/pin-project-internal/src/pin_project/enums.rs @@ -31,10 +31,10 @@ pub(super) fn parse(cx: &mut Context, mut item: ItemEnum) -> Result 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)] @@ -42,10 +42,12 @@ pub(super) fn parse(cx: &mut Context, mut item: ItemEnum) -> Result 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,)* } } diff --git a/pin-project-internal/src/pin_project/mod.rs b/pin-project-internal/src/pin_project/mod.rs index aec9a484..be4a3932 100644 --- a/pin-project-internal/src/pin_project/mod.rs +++ b/pin-project-internal/src/pin_project/mod.rs @@ -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; @@ -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, @@ -86,7 +81,6 @@ impl Context { ) -> Result { 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); @@ -107,7 +101,6 @@ impl Context { Ok(Self { orig_ident: orig_ident.clone(), proj_ident, - proj_trait, vis: vis.clone(), generics, lifetime, @@ -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 { @@ -365,7 +344,6 @@ fn parse(args: TokenStream, input: TokenStream) -> Result { 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) => { @@ -376,7 +354,6 @@ fn parse(args: TokenStream, input: TokenStream) -> Result { 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")), diff --git a/pin-project-internal/src/pin_project/structs.rs b/pin-project-internal/src/pin_project/structs.rs index ee7dc855..3a8add2b 100644 --- a/pin-project-internal/src/pin_project/structs.rs +++ b/pin-project-internal/src/pin_project/structs.rs @@ -28,10 +28,10 @@ pub(super) fn parse(cx: &mut Context, mut item: ItemStruct) -> Result 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)] @@ -39,10 +39,12 @@ pub(super) fn parse(cx: &mut Context, mut item: ItemStruct) -> Result #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 } } diff --git a/pin-project-internal/src/utils.rs b/pin-project-internal/src/utils.rs index befe4d61..9e111664 100644 --- a/pin-project-internal/src/utils.rs +++ b/pin-project-internal/src/utils.rs @@ -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, diff --git a/src/lib.rs b/src/lib.rs index 62547892..0cde0de3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,7 @@ //! } //! //! impl Foo { -//! 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 @@ -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)] diff --git a/tests/pin_project.rs b/tests/pin_project.rs index df595bcb..dac05e94 100644 --- a/tests/pin_project.rs +++ b/tests/pin_project.rs @@ -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); @@ -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; @@ -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; @@ -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) => { @@ -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 { @@ -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) => { @@ -239,11 +239,11 @@ fn combine() { unsafe impl UnsafeUnpin for Foo {} } -#[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 { @@ -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 { + #[pin] + pinned: T, + unpinned: U, + } + + #[pin_project] + enum Enum { + Variant { + #[pin] + pinned: T, + unpinned: U, + }, + } + + impl Struct { + 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 Enum { + 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, + } + } + } +} diff --git a/tests/pinned_drop.rs b/tests/pinned_drop.rs index f0f6c3d2..66a7a3b4 100644 --- a/tests/pinned_drop.rs +++ b/tests/pinned_drop.rs @@ -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; } diff --git a/tests/project.rs b/tests/project.rs index 85dbda63..ae208f97 100644 --- a/tests/project.rs +++ b/tests/project.rs @@ -20,7 +20,7 @@ fn project_stmt_expr() { } let mut foo = Foo { field1: 1, field2: 2 }; - let mut foo = Pin::new(&mut foo); + let foo = Pin::new(&mut foo); #[project] let Foo { field1, field2 } = foo.project(); @@ -37,7 +37,7 @@ fn project_stmt_expr() { struct Bar(#[pin] T, U); let mut bar = Bar(1, 2); - let mut bar = Pin::new(&mut bar); + let bar = Pin::new(&mut bar); #[project] let Bar(x, y) = bar.project(); @@ -63,7 +63,7 @@ fn project_stmt_expr() { let mut baz = Baz::Variant1(1, 2); - let mut baz = Pin::new(&mut baz); + let baz = Pin::new(&mut baz); let mut baz = baz.project(); #[project] diff --git a/tests/project_nightly.rs b/tests/project_nightly.rs index d88d34a8..7090297b 100644 --- a/tests/project_nightly.rs +++ b/tests/project_nightly.rs @@ -25,7 +25,7 @@ fn project_stmt_expr_nightly() { let mut baz = Baz::Variant1(1, 2); - let mut baz = Pin::new(&mut baz); + let baz = Pin::new(&mut baz); let mut baz = baz.project(); #[project]