From ef2b8dbebbaf02d81f930e36d648afe270560e44 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 4 Oct 2020 10:26:02 +0900 Subject: [PATCH 1/5] Enum support for pin_project! macro --- README.md | 35 +- src/lib.rs | 597 +++++++++++++++++- .../tests/expand/default-enum.expanded.rs | 82 +++ tests/expand/tests/expand/default-enum.rs | 16 + .../tests/expand/default-struct.expanded.rs | 3 + .../tests/expand/naming-enum-all.expanded.rs | 82 +++ tests/expand/tests/expand/naming-enum-all.rs | 16 + .../tests/expand/naming-enum-mut.expanded.rs | 54 ++ tests/expand/tests/expand/naming-enum-mut.rs | 15 + .../tests/expand/naming-enum-none.expanded.rs | 25 + tests/expand/tests/expand/naming-enum-none.rs | 14 + .../tests/expand/naming-enum-ref.expanded.rs | 54 ++ tests/expand/tests/expand/naming-enum-ref.rs | 15 + .../expand/tests/expand/pub-enum.expanded.rs | 82 +++ tests/expand/tests/expand/pub-enum.rs | 16 + .../tests/expand/pub-struct.expanded.rs | 3 + tests/include/basic.rs | 14 + tests/lint.rs | 107 ++++ tests/test.rs | 157 +++++ tests/ui/invalid-bounds.stderr | 90 ++- tests/ui/invalid.stderr | 31 +- tests/ui/unsupported.stderr | 64 +- 22 files changed, 1499 insertions(+), 73 deletions(-) create mode 100644 tests/expand/tests/expand/default-enum.expanded.rs create mode 100644 tests/expand/tests/expand/default-enum.rs create mode 100644 tests/expand/tests/expand/naming-enum-all.expanded.rs create mode 100644 tests/expand/tests/expand/naming-enum-all.rs create mode 100644 tests/expand/tests/expand/naming-enum-mut.expanded.rs create mode 100644 tests/expand/tests/expand/naming-enum-mut.rs create mode 100644 tests/expand/tests/expand/naming-enum-none.expanded.rs create mode 100644 tests/expand/tests/expand/naming-enum-none.rs create mode 100644 tests/expand/tests/expand/naming-enum-ref.expanded.rs create mode 100644 tests/expand/tests/expand/naming-enum-ref.rs create mode 100644 tests/expand/tests/expand/pub-enum.expanded.rs create mode 100644 tests/expand/tests/expand/pub-enum.rs diff --git a/README.md b/README.md index b6c5b3a..e42863f 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,32 @@ impl Struct { } ``` +To use [`pin_project!`] on enums, you need to name the projection type +returned from the method. + +```rust +use pin_project_lite::pin_project; +use std::pin::Pin; + +pin_project! { + #[project = EnumProj] + enum Enum { + Variant { #[pin] pinned: T, unpinned: U }, + } +} + +impl Enum { + fn method(self: Pin<&mut Self>) { + match self.project() { + EnumProj::Variant { pinned, unpinned } => { + let _: Pin<&mut T> = pinned; + let _: &mut U = unpinned; + } + } + } +} +``` + ## [pin-project] vs pin-project-lite Here are some similarities and differences compared to [pin-project]. @@ -72,10 +98,6 @@ This is the **only** reason to use this crate. However, **if you already have pr This macro does not handle any invalid input. So error messages are not to be useful in most cases. If you do need useful error messages, then upon error you can pass the same input to [pin-project] to receive a helpful description of the compile error. -### Different: Structs only - -pin-project-lite will refuse anything other than a braced struct with named fields. Enums and tuple structs are not supported. - ### Different: No support for custom Drop implementation pin-project supports this by [`#[pinned_drop]`][pinned-drop]. @@ -84,12 +106,11 @@ pin-project supports this by [`#[pinned_drop]`][pinned-drop]. pin-project supports this by [`UnsafeUnpin`][unsafe-unpin] and [`!Unpin`][not-unpin]. -### Different: No support for pattern matching and destructing +### Different: No support for tuple structs and tuple variants -[pin-project supports this.][naming] +pin-project supports this. [`pin_project!`]: https://docs.rs/pin-project-lite/0.1/pin_project_lite/macro.pin_project.html -[naming]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html [not-unpin]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#unpin [pin-project]: https://github.com/taiki-e/pin-project [pinned-drop]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#pinned_drop diff --git a/src/lib.rs b/src/lib.rs index 0fef95e..d8b3ffa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,6 +25,32 @@ //! } //! ``` //! +//! To use [`pin_project!`] on enums, you need to name the projection type +//! returned from the method. +//! +//! ```rust +//! use pin_project_lite::pin_project; +//! use std::pin::Pin; +//! +//! pin_project! { +//! #[project = EnumProj] +//! enum Enum { +//! Variant { #[pin] pinned: T, unpinned: U }, +//! } +//! } +//! +//! impl Enum { +//! fn method(self: Pin<&mut Self>) { +//! match self.project() { +//! EnumProj::Variant { pinned, unpinned } => { +//! let _: Pin<&mut T> = pinned; +//! let _: &mut U = unpinned; +//! } +//! } +//! } +//! } +//! ``` +//! //! # [pin-project] vs pin-project-lite //! //! Here are some similarities and differences compared to [pin-project]. @@ -45,10 +71,6 @@ //! //! This macro does not handle any invalid input. So error messages are not to be useful in most cases. If you do need useful error messages, then upon error you can pass the same input to [pin-project] to receive a helpful description of the compile error. //! -//! ## Different: Structs only -//! -//! pin-project-lite will refuse anything other than a braced struct with named fields. Enums and tuple structs are not supported. -//! //! ## Different: No support for custom Drop implementation //! //! pin-project supports this by [`#[pinned_drop]`][pinned-drop]. @@ -57,11 +79,10 @@ //! //! pin-project supports this by [`UnsafeUnpin`][unsafe-unpin] and [`!Unpin`][not-unpin]. //! -//! ## Different: No support for pattern matching and destructing +//! ## Different: No support for tuple structs and tuple variants //! -//! [pin-project supports this.][naming] +//! pin-project supports this. //! -//! [naming]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html //! [not-unpin]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#unpin //! [pin-project]: https://github.com/taiki-e/pin-project //! [pinned-drop]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#pinned_drop @@ -102,9 +123,60 @@ /// # } /// ``` /// -/// The visibility of the projected type and projection method is based on the -/// original type. However, if the visibility of the original type is `pub`, -/// the visibility of the projected type and the projection method is `pub(crate)`. +/// By passing an attribute with the same name as the method to the macro, +/// you can name the projection type returned from the method. This allows you +/// to use pattern matching on the projected types. +/// +/// ```rust +/// # use pin_project_lite::pin_project; +/// # use std::pin::Pin; +/// pin_project! { +/// #[project = EnumProj] +/// enum Enum { +/// Variant { #[pin] field: T }, +/// } +/// } +/// +/// impl Enum { +/// fn method(self: Pin<&mut Self>) { +/// let this: EnumProj<'_, T> = self.project(); +/// match this { +/// EnumProj::Variant { field } => { +/// let _: Pin<&mut T> = field; +/// } +/// } +/// } +/// } +/// ``` +/// +/// The `#[project]` (and `#[project_ref]`) attribute must precede the other +/// attributes. For example, the following code will not be compiled: +/// +/// ```rust,compile_fail +/// # use pin_project_lite::pin_project; +/// # use std::pin::Pin; +/// pin_project! { +/// #[derive(Clone)] // <--- ERROR +/// #[project = EnumProj] +/// #[derive(Debug)] // <--- Ok +/// enum Enum { +/// Variant { #[pin] field: T }, +/// } +/// } +/// ``` +/// +/// Also, note that the projection types returned by `project` and `project_ref` have +/// an additional lifetime at the beginning of generics. +/// +/// ```text +/// let this: EnumProj<'_, T> = self.project(); +/// ^^ +/// ``` +/// +/// The visibility of the projected types and projection methods is based on the +/// original type. However, if the visibility of the original type is `pub`, the +/// visibility of the projected types and the projection methods is downgraded +/// to `pub(crate)`. /// /// # Safety /// @@ -136,6 +208,36 @@ /// } /// ``` /// +/// To use `pin_project!` on enums, you need to name the projection type +/// returned from the method. +/// +/// ```rust +/// use pin_project_lite::pin_project; +/// use std::pin::Pin; +/// +/// pin_project! { +/// #[project = EnumProj] +/// enum Enum { +/// Struct { +/// #[pin] +/// field: T, +/// }, +/// Unit, +/// } +/// } +/// +/// impl Enum { +/// fn method(self: Pin<&mut Self>) { +/// match self.project() { +/// EnumProj::Struct { field } => { +/// let _: Pin<&mut T> = field; +/// } +/// EnumProj::Unit => {} +/// } +/// } +/// } +/// ``` +/// /// If you want to call the `project()` method multiple times or later use the /// original [`Pin`] type, it needs to use [`.as_mut()`][`Pin::as_mut`] to avoid /// consuming the [`Pin`]. @@ -186,14 +288,47 @@ /// [pin-project]: https://github.com/taiki-e/pin-project #[macro_export] macro_rules! pin_project { - ($($tt:tt)*) => { - $crate::__pin_project_internal! { $($tt)* } + // Parses options + ( + #[project = $proj_mut_ident:ident] + #[project_ref = $proj_ref_ident:ident] + $($tt:tt)* + ) => { + $crate::__pin_project_internal! { + [$proj_mut_ident][$proj_ref_ident] + $($tt)* + } + }; + ( + #[project = $proj_mut_ident:ident] + $($tt:tt)* + ) => { + $crate::__pin_project_internal! { + [$proj_mut_ident][] + $($tt)* + } + }; + ( + #[project_ref = $proj_ref_ident:ident] + $($tt:tt)* + ) => { + $crate::__pin_project_internal! { + [][$proj_ref_ident] + $($tt)* + } + }; + ( + $($tt:tt)* + ) => { + $crate::__pin_project_internal! { + [][] + $($tt)* + } }; } // limitations: -// * no support for tuple structs and enums. -// * no support for naming the projection types. +// * no support for tuple structs and tuple variant (wontfix). // * no support for multiple trait/lifetime bounds. // * no support for `Self` in where clauses. (wontfix) // * no support for overlapping lifetime names. (wontfix) @@ -320,6 +455,142 @@ macro_rules! __pin_project_internal { }; }; + // ============================================================================================= + // main: enum + (@enum_internal; + [$proj_vis:vis] + [$($proj_mut_ident:ident)?] + [$($proj_ref_ident:ident)?] + [$(#[$attrs:meta])* $vis:vis enum $ident:ident] + [$($def_generics:tt)*] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)*)?] + { + $( + $variant:ident $({ + $( + $(#[$pin:ident])? + $field:ident: $field_ty:ty + ),+ + })? + ),+ + } + ) => { + $(#[$attrs])* + $vis enum $ident $($def_generics)* + $(where + $($where_clause)*)? + { + $( + $variant $({ + $( + $field: $field_ty + ),+ + })? + ),+ + } + + $crate::__pin_project_internal! { @make_proj_ty_enum; + [$proj_vis] + [$($proj_mut_ident)?] + [make_proj_field_mut] + [$vis enum $ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + { + $( + $variant $({ + $( + $(#[$pin])? + $field: $field_ty + ),+ + })? + ),+ + } + } + $crate::__pin_project_internal! { @make_proj_ty_enum; + [$proj_vis] + [$($proj_ref_ident)?] + [make_proj_field_ref] + [$vis enum $ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + { + $( + $variant $({ + $( + $(#[$pin])? + $field: $field_ty + ),+ + })? + ),+ + } + } + + #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + #[allow(clippy::used_underscore_binding)] + const _: () = { + impl <$($impl_generics)*> $ident <$($ty_generics)*> + $(where + $($where_clause)*)? + { + $crate::__pin_project_internal! { @make_proj_method_enum; + [$proj_vis] + [$($proj_mut_ident)?] + [project get_unchecked_mut mut] + [enum $ident] + [$($ty_generics)*] + { + $( + $variant $({ + $( + $(#[$pin])? + $field: $field_ty + ),+ + })? + ),+ + } + } + $crate::__pin_project_internal! { @make_proj_method_enum; + [$proj_vis] + [$($proj_ref_ident)?] + [project_ref get_ref] + [enum $ident] + [$($ty_generics)*] + { + $( + $variant $({ + $( + $(#[$pin])? + $field: $field_ty + ),+ + })? + ),+ + } + } + } + + $crate::__pin_project_internal! { @make_unpin_impl; + [$vis $ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + $( + $variant: ($( + $( + $crate::__pin_project_internal!(@make_unpin_bound; + $(#[$pin])? $field_ty + ) + ),+ + )?) + ),+ + } + + $crate::__pin_project_internal! { @make_drop_impl; + [$ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + } + + // We don't need to check for '#[repr(packed)]', + // since it does not apply to enums. + }; + }; + // ============================================================================================= // make_proj_ty: struct (@make_proj_ty_struct; @@ -335,6 +606,7 @@ macro_rules! __pin_project_internal { ) => { #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. + #[allow(clippy::redundant_pub_crate)] #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 $proj_vis struct Projection <'__pin, $($impl_generics)*> where @@ -348,6 +620,7 @@ macro_rules! __pin_project_internal { ),+ } #[allow(dead_code)] // This lint warns unused fields/variants. + #[allow(clippy::redundant_pub_crate)] #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 $proj_vis struct ProjectionRef <'__pin, $($impl_generics)*> where @@ -361,6 +634,123 @@ macro_rules! __pin_project_internal { ),+ } }; + // ============================================================================================= + // make_proj_ty: enum + (@make_proj_ty_enum; + [$proj_vis:vis] + [$proj_ty_ident:ident] + [$make_proj_field:ident] + [$vis:vis enum $ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + { + $( + $variant:ident $({ + $( + $(#[$pin:ident])? + $field:ident: $field_ty:ty + ),+ + })? + ),+ + } + ) => { + #[allow(dead_code)] // This lint warns unused fields/variants. + #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + #[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. (only needed for project) + #[allow(clippy::redundant_pub_crate)] + #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 + $proj_vis enum $proj_ty_ident <'__pin, $($impl_generics)*> + where + $ident <$($ty_generics)*>: '__pin + $(, $($where_clause)*)? + { + $( + $variant $({ + $( + $field: $crate::__pin_project_internal!(@$make_proj_field; + $(#[$pin])? $field_ty + ) + ),+ + })? + ),+ + } + }; + (@make_proj_ty_enum; + [$proj_vis:vis] + [] + [$make_proj_field:ident] + [$vis:vis enum $ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + { + $( + $variant:ident $({ + $( + $(#[$pin:ident])? + $field:ident: $field_ty:ty + ),+ + })? + ),+ + } + ) => {}; + + // ============================================================================================= + // make_proj_method: enum + (@make_proj_method_enum; + [$proj_vis:vis] + [$proj_ty_ident:ident] + [$method_ident:ident $get_method:ident $($mut:ident)?] + [enum $ident:ident] + [$($ty_generics:tt)*] + { + $( + $variant:ident $({ + $( + $(#[$pin:ident])? + $field:ident: $field_ty:ty + ),+ + })? + ),+ + } + ) => { + $proj_vis fn $method_ident<'__pin>( + self: $crate::__private::Pin<&'__pin $($mut)? Self>, + ) -> $proj_ty_ident <'__pin, $($ty_generics)*> { + unsafe { + match self.$get_method() { + $( + $ident::$variant $({ + $($field),+ + })? => { + $proj_ty_ident::$variant $({ + $( + $field: $crate::__pin_project_internal!( + @make_unsafe_field_proj; + $(#[$pin])? $field + ) + ),+ + })? + } + ),+ + } + } + } + }; + (@make_proj_method_enum; + [$proj_vis:vis] + [] + [$method_ident:ident $get_method:ident $($mut:ident)?] + [enum $ident:ident] + [$($ty_generics:tt)*] + { + $( + $variant:ident $({ + $( + $(#[$pin:ident])? + $field:ident: $field_ty:ty + ),+ + })? + ),+ + } + ) => {}; // ============================================================================================= // make_unpin_impl @@ -394,6 +784,7 @@ macro_rules! __pin_project_internal { // regardless of the privacy of the types of their fields. // // See also https://github.com/taiki-e/pin-project/pull/53. + #[allow(non_snake_case)] $vis struct __Origin <'__pin, $($impl_generics)*> $(where $($where_clause)*)? @@ -477,10 +868,40 @@ macro_rules! __pin_project_internal { ) => { &'__pin $($mut)? ($field_ty) }; + // FIXME: remove + (@make_proj_field_mut; + #[pin] + $field_ty:ty + ) => { + $crate::__private::Pin<&'__pin mut ($field_ty)> + }; + // FIXME: remove + (@make_proj_field_mut; + $field_ty:ty + ) => { + &'__pin mut ($field_ty) + }; + // FIXME: remove + (@make_proj_field_ref; + #[pin] + $field_ty:ty + ) => { + $crate::__private::Pin<&'__pin ($field_ty)> + }; + // FIXME: remove + (@make_proj_field_ref; + $field_ty:ty + ) => { + &'__pin ($field_ty) + }; // ============================================================================================= // Parses input and determines visibility + // struct ( + [$($proj_mut_ident:ident)?] + [$($proj_ref_ident:ident)?] + $(#[$attrs:meta])* pub struct $ident:ident $(< $( $lifetime:lifetime $(: $lifetime_bound:lifetime)? ),* $(,)? @@ -540,6 +961,9 @@ macro_rules! __pin_project_internal { } }; ( + [$($proj_mut_ident:ident)?] + [$($proj_ref_ident:ident)?] + $(#[$attrs:meta])* $vis:vis struct $ident:ident $(< $( $lifetime:lifetime $(: $lifetime_bound:lifetime)? ),* $(,)? @@ -598,6 +1022,151 @@ macro_rules! __pin_project_internal { } } }; + // enum + ( + [$($proj_mut_ident:ident)?] + [$($proj_ref_ident:ident)?] + + $(#[$attrs:meta])* + pub enum $ident:ident $(< + $( $lifetime:lifetime $(: $lifetime_bound:lifetime)? ),* $(,)? + $( $generics:ident + $(: $generics_bound:path)? + $(: ?$generics_unsized_bound:path)? + $(: $generics_lifetime_bound:lifetime)? + $(= $generics_default:ty)? + ),* $(,)? + >)? + $(where + $( $where_clause_ty:ty + $(: $where_clause_bound:path)? + $(: ?$where_clause_unsized_bound:path)? + $(: $where_clause_lifetime_bound:lifetime)? + ),* $(,)? + )? + { + $( + $variant:ident $({ + $( + $(#[$pin:ident])? + $field:ident: $field_ty:ty + ),+ $(,)? + })? + ),+ $(,)? + } + ) => { + $crate::__pin_project_internal! { @enum_internal; + [pub(crate)] + [$($proj_mut_ident)?] + [$($proj_ref_ident)?] + [$(#[$attrs])* pub enum $ident] + [$(< + $( $lifetime $(: $lifetime_bound)? ,)* + $( $generics + $(: $generics_bound)? + $(: ?$generics_unsized_bound)? + $(: $generics_lifetime_bound)? + $(= $generics_default)? + ),* + >)?] + [$( + $( $lifetime $(: $lifetime_bound)? ,)* + $( $generics + $(: $generics_bound)? + $(: ?$generics_unsized_bound)? + $(: $generics_lifetime_bound)? + ),* + )?] + [$( $( $lifetime ,)* $( $generics ),* )?] + [$(where $( $where_clause_ty + $(: $where_clause_bound)? + $(: ?$where_clause_unsized_bound)? + $(: $where_clause_lifetime_bound)? + ),* )?] + { + $( + $variant $({ + $( + $(#[$pin])? + $field: $field_ty + ),+ + })? + ),+ + } + } + }; + ( + [$($proj_mut_ident:ident)?] + [$($proj_ref_ident:ident)?] + + $(#[$attrs:meta])* + $vis:vis enum $ident:ident $(< + $( $lifetime:lifetime $(: $lifetime_bound:lifetime)? ),* $(,)? + $( $generics:ident + $(: $generics_bound:path)? + $(: ?$generics_unsized_bound:path)? + $(: $generics_lifetime_bound:lifetime)? + $(= $generics_default:ty)? + ),* $(,)? + >)? + $(where + $( $where_clause_ty:ty + $(: $where_clause_bound:path)? + $(: ?$where_clause_unsized_bound:path)? + $(: $where_clause_lifetime_bound:lifetime)? + ),* $(,)? + )? + { + $( + $variant:ident $({ + $( + $(#[$pin:ident])? + $field:ident: $field_ty:ty + ),+ $(,)? + })? + ),+ $(,)? + } + ) => { + $crate::__pin_project_internal! { @enum_internal; + [$vis] + [$($proj_mut_ident)?] + [$($proj_ref_ident)?] + [$(#[$attrs])* $vis enum $ident] + [$(< + $( $lifetime $(: $lifetime_bound)? ,)* + $( $generics + $(: $generics_bound)? + $(: ?$generics_unsized_bound)? + $(: $generics_lifetime_bound)? + $(= $generics_default)? + ),* + >)?] + [$( + $( $lifetime $(: $lifetime_bound)? ,)* + $( $generics + $(: $generics_bound)? + $(: ?$generics_unsized_bound)? + $(: $generics_lifetime_bound)? + ),* + )?] + [$( $( $lifetime ,)* $( $generics ),* )?] + [$(where $( $where_clause_ty + $(: $where_clause_bound)? + $(: ?$where_clause_unsized_bound)? + $(: $where_clause_lifetime_bound)? + ),* )?] + { + $( + $variant $({ + $( + $(#[$pin])? + $field: $field_ty + ),+ + })? + ),+ + } + } + }; } // Not public API. diff --git a/tests/expand/tests/expand/default-enum.expanded.rs b/tests/expand/tests/expand/default-enum.expanded.rs new file mode 100644 index 0000000..82f4d72 --- /dev/null +++ b/tests/expand/tests/expand/default-enum.expanded.rs @@ -0,0 +1,82 @@ +use pin_project_lite::pin_project; +enum Enum { + Struct { pinned: T, unpinned: U }, + Unit, +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +#[allow(clippy::mut_mut)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::type_repetition_in_bounds)] +enum EnumProj<'__pin, T, U> +where + Enum: '__pin, +{ + Struct { + pinned: ::pin_project_lite::__private::Pin<&'__pin mut (T)>, + unpinned: &'__pin mut (U), + }, + Unit, +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +#[allow(clippy::mut_mut)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::type_repetition_in_bounds)] +enum EnumProjRef<'__pin, T, U> +where + Enum: '__pin, +{ + Struct { + pinned: ::pin_project_lite::__private::Pin<&'__pin (T)>, + unpinned: &'__pin (U), + }, + Unit, +} +#[allow(single_use_lifetimes)] +#[allow(clippy::used_underscore_binding)] +const _: () = { + impl Enum { + fn project<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin mut Self>, + ) -> EnumProj<'__pin, T, U> { + unsafe { + match self.get_unchecked_mut() { + Enum::Struct { pinned, unpinned } => EnumProj::Struct { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + }, + Enum::Unit => EnumProj::Unit, + } + } + } + fn project_ref<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin Self>, + ) -> EnumProjRef<'__pin, T, U> { + unsafe { + match self.get_ref() { + Enum::Struct { pinned, unpinned } => EnumProjRef::Struct { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + }, + Enum::Unit => EnumProjRef::Unit, + } + } + } + } + #[allow(non_snake_case)] + struct __Origin<'__pin, T, U> { + __dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>, + Struct: (T, ::pin_project_lite::__private::AlwaysUnpin), + Unit: (), + } + impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum where + __Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin + { + } + trait MustNotImplDrop {} + #[allow(clippy::drop_bounds, drop_bounds)] + impl MustNotImplDrop for T {} + impl MustNotImplDrop for Enum {} +}; +fn main() {} diff --git a/tests/expand/tests/expand/default-enum.rs b/tests/expand/tests/expand/default-enum.rs new file mode 100644 index 0000000..0640222 --- /dev/null +++ b/tests/expand/tests/expand/default-enum.rs @@ -0,0 +1,16 @@ +use pin_project_lite::pin_project; + +pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + enum Enum { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Unit, + } +} + +fn main() {} diff --git a/tests/expand/tests/expand/default-struct.expanded.rs b/tests/expand/tests/expand/default-struct.expanded.rs index 88e5a27..3283595 100644 --- a/tests/expand/tests/expand/default-struct.expanded.rs +++ b/tests/expand/tests/expand/default-struct.expanded.rs @@ -10,6 +10,7 @@ struct Struct { const _: () = { #[allow(dead_code)] #[allow(clippy::mut_mut)] + #[allow(clippy::redundant_pub_crate)] #[allow(clippy::type_repetition_in_bounds)] struct Projection<'__pin, T, U> where @@ -19,6 +20,7 @@ const _: () = { unpinned: &'__pin mut (U), } #[allow(dead_code)] + #[allow(clippy::redundant_pub_crate)] #[allow(clippy::type_repetition_in_bounds)] struct ProjectionRef<'__pin, T, U> where @@ -51,6 +53,7 @@ const _: () = { } } } + #[allow(non_snake_case)] struct __Origin<'__pin, T, U> { __dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>, pinned: T, diff --git a/tests/expand/tests/expand/naming-enum-all.expanded.rs b/tests/expand/tests/expand/naming-enum-all.expanded.rs new file mode 100644 index 0000000..82f4d72 --- /dev/null +++ b/tests/expand/tests/expand/naming-enum-all.expanded.rs @@ -0,0 +1,82 @@ +use pin_project_lite::pin_project; +enum Enum { + Struct { pinned: T, unpinned: U }, + Unit, +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +#[allow(clippy::mut_mut)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::type_repetition_in_bounds)] +enum EnumProj<'__pin, T, U> +where + Enum: '__pin, +{ + Struct { + pinned: ::pin_project_lite::__private::Pin<&'__pin mut (T)>, + unpinned: &'__pin mut (U), + }, + Unit, +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +#[allow(clippy::mut_mut)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::type_repetition_in_bounds)] +enum EnumProjRef<'__pin, T, U> +where + Enum: '__pin, +{ + Struct { + pinned: ::pin_project_lite::__private::Pin<&'__pin (T)>, + unpinned: &'__pin (U), + }, + Unit, +} +#[allow(single_use_lifetimes)] +#[allow(clippy::used_underscore_binding)] +const _: () = { + impl Enum { + fn project<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin mut Self>, + ) -> EnumProj<'__pin, T, U> { + unsafe { + match self.get_unchecked_mut() { + Enum::Struct { pinned, unpinned } => EnumProj::Struct { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + }, + Enum::Unit => EnumProj::Unit, + } + } + } + fn project_ref<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin Self>, + ) -> EnumProjRef<'__pin, T, U> { + unsafe { + match self.get_ref() { + Enum::Struct { pinned, unpinned } => EnumProjRef::Struct { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + }, + Enum::Unit => EnumProjRef::Unit, + } + } + } + } + #[allow(non_snake_case)] + struct __Origin<'__pin, T, U> { + __dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>, + Struct: (T, ::pin_project_lite::__private::AlwaysUnpin), + Unit: (), + } + impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum where + __Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin + { + } + trait MustNotImplDrop {} + #[allow(clippy::drop_bounds, drop_bounds)] + impl MustNotImplDrop for T {} + impl MustNotImplDrop for Enum {} +}; +fn main() {} diff --git a/tests/expand/tests/expand/naming-enum-all.rs b/tests/expand/tests/expand/naming-enum-all.rs new file mode 100644 index 0000000..0640222 --- /dev/null +++ b/tests/expand/tests/expand/naming-enum-all.rs @@ -0,0 +1,16 @@ +use pin_project_lite::pin_project; + +pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + enum Enum { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Unit, + } +} + +fn main() {} diff --git a/tests/expand/tests/expand/naming-enum-mut.expanded.rs b/tests/expand/tests/expand/naming-enum-mut.expanded.rs new file mode 100644 index 0000000..931d65b --- /dev/null +++ b/tests/expand/tests/expand/naming-enum-mut.expanded.rs @@ -0,0 +1,54 @@ +use pin_project_lite::pin_project; +enum Enum { + Struct { pinned: T, unpinned: U }, + Unit, +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +#[allow(clippy::mut_mut)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::type_repetition_in_bounds)] +enum EnumProj<'__pin, T, U> +where + Enum: '__pin, +{ + Struct { + pinned: ::pin_project_lite::__private::Pin<&'__pin mut (T)>, + unpinned: &'__pin mut (U), + }, + Unit, +} +#[allow(single_use_lifetimes)] +#[allow(clippy::used_underscore_binding)] +const _: () = { + impl Enum { + fn project<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin mut Self>, + ) -> EnumProj<'__pin, T, U> { + unsafe { + match self.get_unchecked_mut() { + Enum::Struct { pinned, unpinned } => EnumProj::Struct { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + }, + Enum::Unit => EnumProj::Unit, + } + } + } + } + #[allow(non_snake_case)] + struct __Origin<'__pin, T, U> { + __dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>, + Struct: (T, ::pin_project_lite::__private::AlwaysUnpin), + Unit: (), + } + impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum where + __Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin + { + } + trait MustNotImplDrop {} + #[allow(clippy::drop_bounds, drop_bounds)] + impl MustNotImplDrop for T {} + impl MustNotImplDrop for Enum {} +}; +fn main() {} diff --git a/tests/expand/tests/expand/naming-enum-mut.rs b/tests/expand/tests/expand/naming-enum-mut.rs new file mode 100644 index 0000000..69beecd --- /dev/null +++ b/tests/expand/tests/expand/naming-enum-mut.rs @@ -0,0 +1,15 @@ +use pin_project_lite::pin_project; + +pin_project! { + #[project = EnumProj] + enum Enum { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Unit, + } +} + +fn main() {} diff --git a/tests/expand/tests/expand/naming-enum-none.expanded.rs b/tests/expand/tests/expand/naming-enum-none.expanded.rs new file mode 100644 index 0000000..fe1fe9d --- /dev/null +++ b/tests/expand/tests/expand/naming-enum-none.expanded.rs @@ -0,0 +1,25 @@ +use pin_project_lite::pin_project; +enum Enum { + Struct { pinned: T, unpinned: U }, + Unit, +} +#[allow(single_use_lifetimes)] +#[allow(clippy::used_underscore_binding)] +const _: () = { + impl Enum {} + #[allow(non_snake_case)] + struct __Origin<'__pin, T, U> { + __dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>, + Struct: (T, ::pin_project_lite::__private::AlwaysUnpin), + Unit: (), + } + impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum where + __Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin + { + } + trait MustNotImplDrop {} + #[allow(clippy::drop_bounds, drop_bounds)] + impl MustNotImplDrop for T {} + impl MustNotImplDrop for Enum {} +}; +fn main() {} diff --git a/tests/expand/tests/expand/naming-enum-none.rs b/tests/expand/tests/expand/naming-enum-none.rs new file mode 100644 index 0000000..b2e3f9d --- /dev/null +++ b/tests/expand/tests/expand/naming-enum-none.rs @@ -0,0 +1,14 @@ +use pin_project_lite::pin_project; + +pin_project! { + enum Enum { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Unit, + } +} + +fn main() {} diff --git a/tests/expand/tests/expand/naming-enum-ref.expanded.rs b/tests/expand/tests/expand/naming-enum-ref.expanded.rs new file mode 100644 index 0000000..8bd5f40 --- /dev/null +++ b/tests/expand/tests/expand/naming-enum-ref.expanded.rs @@ -0,0 +1,54 @@ +use pin_project_lite::pin_project; +enum Enum { + Struct { pinned: T, unpinned: U }, + Unit, +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +#[allow(clippy::mut_mut)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::type_repetition_in_bounds)] +enum EnumProjRef<'__pin, T, U> +where + Enum: '__pin, +{ + Struct { + pinned: ::pin_project_lite::__private::Pin<&'__pin (T)>, + unpinned: &'__pin (U), + }, + Unit, +} +#[allow(single_use_lifetimes)] +#[allow(clippy::used_underscore_binding)] +const _: () = { + impl Enum { + fn project_ref<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin Self>, + ) -> EnumProjRef<'__pin, T, U> { + unsafe { + match self.get_ref() { + Enum::Struct { pinned, unpinned } => EnumProjRef::Struct { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + }, + Enum::Unit => EnumProjRef::Unit, + } + } + } + } + #[allow(non_snake_case)] + struct __Origin<'__pin, T, U> { + __dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>, + Struct: (T, ::pin_project_lite::__private::AlwaysUnpin), + Unit: (), + } + impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum where + __Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin + { + } + trait MustNotImplDrop {} + #[allow(clippy::drop_bounds, drop_bounds)] + impl MustNotImplDrop for T {} + impl MustNotImplDrop for Enum {} +}; +fn main() {} diff --git a/tests/expand/tests/expand/naming-enum-ref.rs b/tests/expand/tests/expand/naming-enum-ref.rs new file mode 100644 index 0000000..480d592 --- /dev/null +++ b/tests/expand/tests/expand/naming-enum-ref.rs @@ -0,0 +1,15 @@ +use pin_project_lite::pin_project; + +pin_project! { + #[project_ref = EnumProjRef] + enum Enum { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Unit, + } +} + +fn main() {} diff --git a/tests/expand/tests/expand/pub-enum.expanded.rs b/tests/expand/tests/expand/pub-enum.expanded.rs new file mode 100644 index 0000000..511a88b --- /dev/null +++ b/tests/expand/tests/expand/pub-enum.expanded.rs @@ -0,0 +1,82 @@ +use pin_project_lite::pin_project; +pub enum Enum { + Struct { pinned: T, unpinned: U }, + Unit, +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +#[allow(clippy::mut_mut)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::type_repetition_in_bounds)] +pub(crate) enum EnumProj<'__pin, T, U> +where + Enum: '__pin, +{ + Struct { + pinned: ::pin_project_lite::__private::Pin<&'__pin mut (T)>, + unpinned: &'__pin mut (U), + }, + Unit, +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +#[allow(clippy::mut_mut)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::type_repetition_in_bounds)] +pub(crate) enum EnumProjRef<'__pin, T, U> +where + Enum: '__pin, +{ + Struct { + pinned: ::pin_project_lite::__private::Pin<&'__pin (T)>, + unpinned: &'__pin (U), + }, + Unit, +} +#[allow(single_use_lifetimes)] +#[allow(clippy::used_underscore_binding)] +const _: () = { + impl Enum { + pub(crate) fn project<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin mut Self>, + ) -> EnumProj<'__pin, T, U> { + unsafe { + match self.get_unchecked_mut() { + Enum::Struct { pinned, unpinned } => EnumProj::Struct { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + }, + Enum::Unit => EnumProj::Unit, + } + } + } + pub(crate) fn project_ref<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin Self>, + ) -> EnumProjRef<'__pin, T, U> { + unsafe { + match self.get_ref() { + Enum::Struct { pinned, unpinned } => EnumProjRef::Struct { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + }, + Enum::Unit => EnumProjRef::Unit, + } + } + } + } + #[allow(non_snake_case)] + pub struct __Origin<'__pin, T, U> { + __dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>, + Struct: (T, ::pin_project_lite::__private::AlwaysUnpin), + Unit: (), + } + impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum where + __Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin + { + } + trait MustNotImplDrop {} + #[allow(clippy::drop_bounds, drop_bounds)] + impl MustNotImplDrop for T {} + impl MustNotImplDrop for Enum {} +}; +fn main() {} diff --git a/tests/expand/tests/expand/pub-enum.rs b/tests/expand/tests/expand/pub-enum.rs new file mode 100644 index 0000000..d3968af --- /dev/null +++ b/tests/expand/tests/expand/pub-enum.rs @@ -0,0 +1,16 @@ +use pin_project_lite::pin_project; + +pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + pub enum Enum { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Unit, + } +} + +fn main() {} diff --git a/tests/expand/tests/expand/pub-struct.expanded.rs b/tests/expand/tests/expand/pub-struct.expanded.rs index 87ff5c3..09e0989 100644 --- a/tests/expand/tests/expand/pub-struct.expanded.rs +++ b/tests/expand/tests/expand/pub-struct.expanded.rs @@ -10,6 +10,7 @@ pub struct Struct { const _: () = { #[allow(dead_code)] #[allow(clippy::mut_mut)] + #[allow(clippy::redundant_pub_crate)] #[allow(clippy::type_repetition_in_bounds)] pub(crate) struct Projection<'__pin, T, U> where @@ -19,6 +20,7 @@ const _: () = { pub unpinned: &'__pin mut (U), } #[allow(dead_code)] + #[allow(clippy::redundant_pub_crate)] #[allow(clippy::type_repetition_in_bounds)] pub(crate) struct ProjectionRef<'__pin, T, U> where @@ -51,6 +53,7 @@ const _: () = { } } } + #[allow(non_snake_case)] pub struct __Origin<'__pin, T, U> { __dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>, pinned: T, diff --git a/tests/include/basic.rs b/tests/include/basic.rs index 967cf81..64c9013 100644 --- a/tests/include/basic.rs +++ b/tests/include/basic.rs @@ -8,3 +8,17 @@ pub unpinned: U, } } + +::pin_project_lite::pin_project! { + #[project = DefaultEnumProj] + #[project_ref = DefaultEnumProjRef] + #[derive(Debug)] + pub enum DefaultEnum { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Unit, + } +} diff --git a/tests/lint.rs b/tests/lint.rs index e81a13c..626d64b 100644 --- a/tests/lint.rs +++ b/tests/lint.rs @@ -55,6 +55,20 @@ pub mod box_pointers { pub u: Box, } } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[derive(Debug)] + pub enum Enum { + Struct { + #[pin] + p: Box, + u: Box, + }, + Unit, + } + } } pub mod explicit_outlives_requirements { @@ -72,6 +86,40 @@ pub mod explicit_outlives_requirements { pub unpinned: &'a mut U, } } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[derive(Debug)] + pub enum Enum<'a, T, U> + where + T: ?Sized, + U: ?Sized, + { + Struct { + #[pin] + pinned: &'a mut T, + unpinned: &'a mut U, + }, + Unit, + } + } +} + +pub mod variant_size_differences { + use pin_project_lite::pin_project; + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[allow(missing_debug_implementations, missing_copy_implementations)] // https://github.com/rust-lang/rust/pull/74060 + #[allow(variant_size_differences)] // for the type itself + #[allow(clippy::large_enum_variant)] // for the type itself + pub enum Enum { + V1 { f: u8 }, + V2 { f: [u8; 1024] }, + } + } } pub mod clippy_mut_mut { @@ -85,6 +133,20 @@ pub mod clippy_mut_mut { pub unpinned: &'a mut U, } } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[derive(Debug)] + pub enum Enum<'a, T, U> { + Struct { + #[pin] + pinned: &'a mut T, + unpinned: &'a mut U, + }, + Unit, + } + } } #[allow(unreachable_pub)] @@ -99,6 +161,21 @@ mod clippy_redundant_pub_crate { pub unpinned: U, } } + + #[allow(dead_code)] + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[derive(Debug)] + pub enum Enum { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Unit, + } + } } pub mod clippy_type_repetition_in_bounds { @@ -115,6 +192,23 @@ pub mod clippy_type_repetition_in_bounds { pub unpinned: U, } } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[derive(Debug)] + pub enum Enum + where + Enum: Sized, + { + Struct { + #[pin] + pinned: T, + unpinned: U, + }, + Unit, + } + } } pub mod clippy_used_underscore_binding { @@ -128,6 +222,19 @@ pub mod clippy_used_underscore_binding { pub _unpinned: U, } } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[derive(Debug)] + pub enum Enum { + Struct { + #[pin] + _pinned: T, + _unpinned: U, + }, + } + } } #[allow(box_pointers)] diff --git a/tests/test.rs b/tests/test.rs index 1af2b59..f2130eb 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -36,6 +36,83 @@ fn projection() { let _: Pin<&mut i32> = s.f1; let _: &mut i32 = s.f2; + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[derive(Eq, PartialEq, Debug)] + enum Enum { + Struct { + #[pin] + f1: C, + f2: D, + }, + Unit, + } + } + + let mut e = Enum::Struct { f1: 1, f2: 2 }; + let mut e_orig = Pin::new(&mut e); + let e = e_orig.as_mut().project(); + + match e { + EnumProj::Struct { f1, f2 } => { + let x: Pin<&mut i32> = f1; + assert_eq!(*x, 1); + let y: &mut i32 = f2; + assert_eq!(*y, 2); + } + EnumProj::Unit => {} + } + + assert_eq!(Pin::into_ref(e_orig).get_ref(), &Enum::Struct { f1: 1, f2: 2 }); + + let mut e = Enum::Struct { f1: 3, f2: 4 }; + let mut e = Pin::new(&mut e).project(); + + match &mut e { + EnumProj::Struct { f1, f2 } => { + let x: &mut Pin<&mut i32> = f1; + assert_eq!(**x, 3); + let y: &mut &mut i32 = f2; + assert_eq!(**y, 4); + } + EnumProj::Unit => {} + } + + if let EnumProj::Struct { f1, f2 } = e { + let x: Pin<&mut i32> = f1; + assert_eq!(*x, 3); + let y: &mut i32 = f2; + assert_eq!(*y, 4); + } +} + +#[test] +fn enum_project_set() { + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + #[derive(Eq, PartialEq, Debug)] + enum Enum { + V1 { #[pin] f: u8 }, + V2 { f: bool }, + } + } + + let mut e = Enum::V1 { f: 25 }; + let mut e_orig = Pin::new(&mut e); + let e_proj = e_orig.as_mut().project(); + + match e_proj { + EnumProj::V1 { f } => { + let new_e = Enum::V2 { f: f.as_ref().get_ref() == &25 }; + e_orig.set(new_e); + } + _ => unreachable!(), + } + + assert_eq!(e, Enum::V2 { f: true }); } #[test] @@ -48,6 +125,17 @@ fn where_clause() { f: T, } } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + enum Enum + where + T: Copy, + { + V { f: T }, + } + } } #[test] @@ -86,6 +174,18 @@ fn where_clause_and_associated_type_field() { trait Static: 'static {} impl Static for Struct3 {} + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + enum Enum + where + I: Iterator, + { + V1 { #[pin] f: I }, + V2 { f: I::Item }, + } + } } #[test] @@ -114,6 +214,20 @@ fn move_out() { let x = Struct { f: NotCopy }; let _val: NotCopy = x.f; + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + enum Enum { + V { f: NotCopy }, + } + } + + let x = Enum::V { f: NotCopy }; + #[allow(clippy::infallible_destructuring_match)] + let _val: NotCopy = match x { + Enum::V { f } => f, + }; } #[test] @@ -172,6 +286,14 @@ fn trait_bounds_on_type_generics() { f2: &'b u8, } } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + enum Enum<'a, T: ?Sized> { + V { f: &'a mut T }, + } + } } #[test] @@ -205,6 +327,18 @@ fn lifetime_project() { } } + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + enum Enum { + V { + #[pin] + pinned: T, + unpinned: U, + }, + } + } + impl Struct1 { fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> { self.project_ref().pinned @@ -234,6 +368,29 @@ fn lifetime_project() { self.project().pinned } } + + impl Enum { + fn get_pin_ref<'a>(self: Pin<&'a Self>) -> Pin<&'a T> { + match self.project_ref() { + EnumProjRef::V { pinned, .. } => pinned, + } + } + fn get_pin_mut<'a>(self: Pin<&'a mut Self>) -> Pin<&'a mut T> { + match self.project() { + EnumProj::V { pinned, .. } => pinned, + } + } + fn get_pin_ref_elided(self: Pin<&Self>) -> Pin<&T> { + match self.project_ref() { + EnumProjRef::V { pinned, .. } => pinned, + } + } + fn get_pin_mut_elided(self: Pin<&mut Self>) -> Pin<&mut T> { + match self.project() { + EnumProj::V { pinned, .. } => pinned, + } + } + } } mod visibility { diff --git a/tests/ui/invalid-bounds.stderr b/tests/ui/invalid-bounds.stderr index 59e9b13..a565cce 100644 --- a/tests/ui/invalid-bounds.stderr +++ b/tests/ui/invalid-bounds.stderr @@ -1,14 +1,26 @@ -error: no rules expected the token `:` - --> $DIR/invalid-bounds.rs:4:33 +error: no rules expected the token `[` + --> $DIR/invalid-bounds.rs:3:1 | -4 | struct Generics1 { //~ ERROR no rules expected the token `:` - | ^ no rules expected this token in macro call +3 | / pin_project! { +4 | | struct Generics1 { //~ ERROR no rules expected the token `:` +5 | | field: T, +6 | | } +7 | | } + | |_^ no rules expected this token in macro call + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `:` - --> $DIR/invalid-bounds.rs:10:33 +error: no rules expected the token `[` + --> $DIR/invalid-bounds.rs:9:1 + | +9 | / pin_project! { +10 | | struct Generics2 { //~ ERROR no rules expected the token `:` +11 | | field: T, +12 | | } +13 | | } + | |_^ no rules expected this token in macro call | -10 | struct Generics2 { //~ ERROR no rules expected the token `:` - | ^ no rules expected this token in macro call + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: expected one of `+`, `,`, `=`, or `>`, found `:` --> $DIR/invalid-bounds.rs:15:1 @@ -58,23 +70,45 @@ error: expected one of `+`, `,`, `=`, or `>`, found `:` | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `Sized` - --> $DIR/invalid-bounds.rs:34:34 +error: no rules expected the token `[` + --> $DIR/invalid-bounds.rs:33:1 + | +33 | / pin_project! { +34 | | struct Generics6 { //~ ERROR no rules expected the token `Sized` +35 | | field: T, +36 | | } +37 | | } + | |_^ no rules expected this token in macro call | -34 | struct Generics6 { //~ ERROR no rules expected the token `Sized` - | ^^^^^ no rules expected this token in macro call + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `:` - --> $DIR/invalid-bounds.rs:42:20 +error: no rules expected the token `[` + --> $DIR/invalid-bounds.rs:39:1 + | +39 | / pin_project! { +40 | | struct WhereClause1 +41 | | where +42 | | T: 'static : Sized //~ ERROR no rules expected the token `:` +... | +45 | | } +46 | | } + | |_^ no rules expected this token in macro call | -42 | T: 'static : Sized //~ ERROR no rules expected the token `:` - | ^ no rules expected this token in macro call + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `:` - --> $DIR/invalid-bounds.rs:51:20 +error: no rules expected the token `[` + --> $DIR/invalid-bounds.rs:48:1 + | +48 | / pin_project! { +49 | | struct WhereClause2 +50 | | where +51 | | T: 'static : ?Sized //~ ERROR no rules expected the token `:` +... | +54 | | } +55 | | } + | |_^ no rules expected this token in macro call | -51 | T: 'static : ?Sized //~ ERROR no rules expected the token `:` - | ^ no rules expected this token in macro call + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: expected `where`, or `{` after struct name, found `:` --> $DIR/invalid-bounds.rs:57:1 @@ -127,8 +161,16 @@ error: expected `where`, or `{` after struct name, found `:` | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `Sized` - --> $DIR/invalid-bounds.rs:87:21 +error: no rules expected the token `[` + --> $DIR/invalid-bounds.rs:84:1 | -87 | T: ?Sized : Sized //~ ERROR no rules expected the token `Sized` - | ^^^^^ no rules expected this token in macro call +84 | / pin_project! { +85 | | struct WhereClause6 +86 | | where +87 | | T: ?Sized : Sized //~ ERROR no rules expected the token `Sized` +... | +90 | | } +91 | | } + | |_^ no rules expected this token in macro call + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/tests/ui/invalid.stderr b/tests/ui/invalid.stderr index f780e2e..06f2d79 100644 --- a/tests/ui/invalid.stderr +++ b/tests/ui/invalid.stderr @@ -1,14 +1,29 @@ -error: no rules expected the token `(` - --> $DIR/invalid.rs:5:14 +error: no rules expected the token `[` + --> $DIR/invalid.rs:3:1 | -5 | #[pin()] //~ ERROR no rules expected the token `(` - | ^ no rules expected this token in macro call +3 | / pin_project! { +4 | | struct A { +5 | | #[pin()] //~ ERROR no rules expected the token `(` +6 | | pinned: T, +7 | | } +8 | | } + | |_^ no rules expected this token in macro call + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `#` - --> $DIR/invalid.rs:20:9 +error: no rules expected the token `[` + --> $DIR/invalid.rs:17:1 + | +17 | / pin_project! { +18 | | struct C { +19 | | #[pin] +20 | | #[pin] //~ ERROR no rules expected the token `#` +21 | | pinned: T, +22 | | } +23 | | } + | |_^ no rules expected this token in macro call | -20 | #[pin] //~ ERROR no rules expected the token `#` - | ^ no rules expected this token in macro call + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: cannot find attribute `pin` in this scope --> $DIR/invalid.rs:11:7 diff --git a/tests/ui/unsupported.stderr b/tests/ui/unsupported.stderr index 4f7b1ae..2cd17df 100644 --- a/tests/ui/unsupported.stderr +++ b/tests/ui/unsupported.stderr @@ -1,29 +1,53 @@ -error: no rules expected the token `}` - --> $DIR/unsupported.rs:4:21 +error: no rules expected the token `[` + --> $DIR/unsupported.rs:3:1 | -4 | struct Struct1 {} //~ ERROR no rules expected the token `}` - | ^ no rules expected this token in macro call +3 | / pin_project! { +4 | | struct Struct1 {} //~ ERROR no rules expected the token `}` +5 | | } + | |_^ no rules expected this token in macro call + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `(` - --> $DIR/unsupported.rs:8:19 +error: no rules expected the token `[` + --> $DIR/unsupported.rs:7:1 + | +7 | / pin_project! { +8 | | struct Struct2(); //~ ERROR no rules expected the token `(` +9 | | } + | |_^ no rules expected this token in macro call | -8 | struct Struct2(); //~ ERROR no rules expected the token `(` - | ^ no rules expected this token in macro call + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `;` - --> $DIR/unsupported.rs:12:19 +error: no rules expected the token `[` + --> $DIR/unsupported.rs:11:1 + | +11 | / pin_project! { +12 | | struct Struct3; //~ ERROR no rules expected the token `;` +13 | | } + | |_^ no rules expected this token in macro call | -12 | struct Struct3; //~ ERROR no rules expected the token `;` - | ^ no rules expected this token in macro call + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `enum` - --> $DIR/unsupported.rs:16:5 +error: no rules expected the token `[` + --> $DIR/unsupported.rs:15:1 | -16 | enum Enum { //~ ERROR no rules expected the token `enum` - | ^^^^ no rules expected this token in macro call +15 | / pin_project! { +16 | | enum Enum { //~ ERROR no rules expected the token `enum` +17 | | A(u8) +18 | | } +19 | | } + | |_^ no rules expected this token in macro call + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: no rules expected the token `union` - --> $DIR/unsupported.rs:22:5 +error: no rules expected the token `[` + --> $DIR/unsupported.rs:21:1 + | +21 | / pin_project! { +22 | | union Union { //~ ERROR no rules expected the token `union` +23 | | x: u8, +24 | | } +25 | | } + | |_^ no rules expected this token in macro call | -22 | union Union { //~ ERROR no rules expected the token `union` - | ^^^^^ no rules expected this token in macro call + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) From cc3b7103926d93861ff4722f26ce0fd2df665e54 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sun, 4 Oct 2020 10:26:46 +0900 Subject: [PATCH 2/5] Naming support for struct --- src/lib.rs | 301 +++++++++++------- .../tests/expand/default-struct.expanded.rs | 3 + .../expand/naming-struct-all.expanded.rs | 79 +++++ .../expand/tests/expand/naming-struct-all.rs | 13 + .../expand/naming-struct-mut.expanded.rs | 79 +++++ .../expand/tests/expand/naming-struct-mut.rs | 12 + .../expand/naming-struct-none.expanded.rs | 79 +++++ .../expand/tests/expand/naming-struct-none.rs | 11 + .../expand/naming-struct-ref.expanded.rs | 79 +++++ .../expand/tests/expand/naming-struct-ref.rs | 12 + .../tests/expand/pub-struct.expanded.rs | 3 + 11 files changed, 560 insertions(+), 111 deletions(-) create mode 100644 tests/expand/tests/expand/naming-struct-all.expanded.rs create mode 100644 tests/expand/tests/expand/naming-struct-all.rs create mode 100644 tests/expand/tests/expand/naming-struct-mut.expanded.rs create mode 100644 tests/expand/tests/expand/naming-struct-mut.rs create mode 100644 tests/expand/tests/expand/naming-struct-none.expanded.rs create mode 100644 tests/expand/tests/expand/naming-struct-none.rs create mode 100644 tests/expand/tests/expand/naming-struct-ref.expanded.rs create mode 100644 tests/expand/tests/expand/naming-struct-ref.rs diff --git a/src/lib.rs b/src/lib.rs index d8b3ffa..e1248e5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -341,8 +341,10 @@ macro_rules! pin_project { #[macro_export] macro_rules! __pin_project_internal { // ============================================================================================= - // main: struct - (@struct_internal; + // struct:main + (@struct=>internal; + [$($proj_mut_ident:ident)?] + [$($proj_ref_ident:ident)?] [$proj_vis:vis] [$(#[$attrs:meta])* $vis:vis struct $ident:ident] [$($def_generics:tt)*] @@ -364,14 +366,56 @@ macro_rules! __pin_project_internal { ),+ } + $crate::__pin_project_internal! { @struct=>make_proj_ty=>named; + [$proj_vis] + [$($proj_mut_ident)?] + [make_proj_field_mut] + [$vis] [$ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + { + $( + $(#[$pin])? + $field_vis $field: $field_ty + ),+ + } + } + $crate::__pin_project_internal! { @struct=>make_proj_ty=>named; + [$proj_vis] + [$($proj_ref_ident)?] + [make_proj_field_ref] + [$vis] [$ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + { + $( + $(#[$pin])? + $field_vis $field: $field_ty + ),+ + } + } + #[allow(explicit_outlives_requirements)] #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 #[allow(clippy::redundant_pub_crate)] #[allow(clippy::used_underscore_binding)] const _: () = { - $crate::__pin_project_internal! { @make_proj_ty_struct; + $crate::__pin_project_internal! { @struct=>make_proj_ty=>unnamed; [$proj_vis] - [$vis struct $ident] + [$($proj_mut_ident)?][Projection] + [make_proj_field_mut] + [$vis] [$ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + { + $( + $(#[$pin])? + $field_vis $field: $field_ty + ),+ + } + } + $crate::__pin_project_internal! { @struct=>make_proj_ty=>unnamed; + [$proj_vis] + [$($proj_ref_ident)?][ProjectionRef] + [make_proj_field_ref] + [$vis] [$ident] [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] { $( @@ -385,32 +429,30 @@ macro_rules! __pin_project_internal { $(where $($where_clause)*)? { - $proj_vis fn project<'__pin>( - self: $crate::__private::Pin<&'__pin mut Self>, - ) -> Projection <'__pin, $($ty_generics)*> { - unsafe { - let Self { $($field),* } = self.get_unchecked_mut(); - Projection { - $( - $field: $crate::__pin_project_internal!(@make_unsafe_field_proj; - $(#[$pin])? $field - ) - ),+ - } + $crate::__pin_project_internal! { @struct=>make_proj_method; + [$proj_vis] + [$($proj_mut_ident)?][Projection] + [project get_unchecked_mut mut] + [$ident] + [$($ty_generics)*] + { + $( + $(#[$pin])? + $field_vis $field: $field_ty + ),+ } } - $proj_vis fn project_ref<'__pin>( - self: $crate::__private::Pin<&'__pin Self>, - ) -> ProjectionRef <'__pin, $($ty_generics)*> { - unsafe { - let Self { $($field),* } = self.get_ref(); - ProjectionRef { - $( - $field: $crate::__pin_project_internal!(@make_unsafe_field_proj; - $(#[$pin])? $field - ) - ),+ - } + $crate::__pin_project_internal! { @struct=>make_proj_method; + [$proj_vis] + [$($proj_ref_ident)?][ProjectionRef] + [project_ref get_ref] + [$ident] + [$($ty_generics)*] + { + $( + $(#[$pin])? + $field_vis $field: $field_ty + ),+ } } } @@ -454,13 +496,12 @@ macro_rules! __pin_project_internal { } }; }; - // ============================================================================================= - // main: enum - (@enum_internal; - [$proj_vis:vis] + // enum:main + (@enum=>internal; [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] + [$proj_vis:vis] [$(#[$attrs:meta])* $vis:vis enum $ident:ident] [$($def_generics:tt)*] [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)*)?] @@ -489,11 +530,11 @@ macro_rules! __pin_project_internal { ),+ } - $crate::__pin_project_internal! { @make_proj_ty_enum; + $crate::__pin_project_internal! { @enum=>make_proj_ty; [$proj_vis] [$($proj_mut_ident)?] [make_proj_field_mut] - [$vis enum $ident] + [$vis] [$ident] [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] { $( @@ -506,11 +547,11 @@ macro_rules! __pin_project_internal { ),+ } } - $crate::__pin_project_internal! { @make_proj_ty_enum; + $crate::__pin_project_internal! { @enum=>make_proj_ty; [$proj_vis] [$($proj_ref_ident)?] [make_proj_field_ref] - [$vis enum $ident] + [$vis] [$ident] [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] { $( @@ -531,11 +572,11 @@ macro_rules! __pin_project_internal { $(where $($where_clause)*)? { - $crate::__pin_project_internal! { @make_proj_method_enum; + $crate::__pin_project_internal! { @enum=>make_proj_method; [$proj_vis] [$($proj_mut_ident)?] [project get_unchecked_mut mut] - [enum $ident] + [$ident] [$($ty_generics)*] { $( @@ -548,11 +589,11 @@ macro_rules! __pin_project_internal { ),+ } } - $crate::__pin_project_internal! { @make_proj_method_enum; + $crate::__pin_project_internal! { @enum=>make_proj_method; [$proj_vis] [$($proj_ref_ident)?] [project_ref get_ref] - [enum $ident] + [$ident] [$($ty_generics)*] { $( @@ -592,10 +633,37 @@ macro_rules! __pin_project_internal { }; // ============================================================================================= - // make_proj_ty: struct - (@make_proj_ty_struct; + // struct:make_proj_ty + (@struct=>make_proj_ty=>unnamed; [$proj_vis:vis] - [$vis:vis struct $ident:ident] + [$_proj_ty_ident:ident][$proj_ty_ident:ident] + [$make_proj_field:ident] + [$vis:vis] [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + $($field:tt)* + ) => {}; + (@struct=>make_proj_ty=>unnamed; + [$proj_vis:vis] + [][$proj_ty_ident:ident] + [$make_proj_field:ident] + [$vis:vis] [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + $($field:tt)* + ) => { + $crate::__pin_project_internal! { @struct=>make_proj_ty=>named; + [$proj_vis] + [$proj_ty_ident] + [$make_proj_field] + [$vis] [$ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + $($field)* + } + }; + (@struct=>make_proj_ty=>named; + [$proj_vis:vis] + [$proj_ty_ident:ident] + [$make_proj_field:ident] + [$vis:vis] [$ident:ident] [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] { $( @@ -605,42 +673,37 @@ macro_rules! __pin_project_internal { } ) => { #[allow(dead_code)] // This lint warns unused fields/variants. - #[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. - #[allow(clippy::redundant_pub_crate)] - #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 - $proj_vis struct Projection <'__pin, $($impl_generics)*> - where - $ident <$($ty_generics)*>: '__pin - $(, $($where_clause)*)? - { - $( - $field_vis $field: $crate::__pin_project_internal!(@make_proj_field; - $(#[$pin])? $field_ty; mut - ) - ),+ - } - #[allow(dead_code)] // This lint warns unused fields/variants. + #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + #[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. (only needed for project) #[allow(clippy::redundant_pub_crate)] #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 - $proj_vis struct ProjectionRef <'__pin, $($impl_generics)*> + $proj_vis struct $proj_ty_ident <'__pin, $($impl_generics)*> where $ident <$($ty_generics)*>: '__pin $(, $($where_clause)*)? { $( - $field_vis $field: $crate::__pin_project_internal!(@make_proj_field; - $(#[$pin])? $field_ty; + $field_vis $field: $crate::__pin_project_internal!(@$make_proj_field; + $(#[$pin])? $field_ty ) ),+ } }; + (@struct=>make_proj_ty=>named; + [$proj_vis:vis] + [] + [$make_proj_field:ident] + [$vis:vis] [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + $($field:tt)* + ) => {}; // ============================================================================================= - // make_proj_ty: enum - (@make_proj_ty_enum; + // enum:make_proj_ty + (@enum=>make_proj_ty; [$proj_vis:vis] [$proj_ty_ident:ident] [$make_proj_field:ident] - [$vis:vis enum $ident:ident] + [$vis:vis] [$ident:ident] [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] { $( @@ -674,31 +737,69 @@ macro_rules! __pin_project_internal { ),+ } }; - (@make_proj_ty_enum; + (@enum=>make_proj_ty; [$proj_vis:vis] [] [$make_proj_field:ident] - [$vis:vis enum $ident:ident] + [$vis:vis] [$ident:ident] [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + $($variant:tt)* + ) => {}; + + // ============================================================================================= + // struct:make_proj_method + (@struct=>make_proj_method; + [$proj_vis:vis] + [$proj_ty_ident:ident][$_proj_ty_ident:ident] + [$method_ident:ident $get_method:ident $($mut:ident)?] + [$ident:ident] + [$($ty_generics:tt)*] { $( - $variant:ident $({ + $(#[$pin:ident])? + $field_vis:vis $field:ident: $field_ty:ty + ),+ + } + ) => { + $proj_vis fn $method_ident<'__pin>( + self: $crate::__private::Pin<&'__pin $($mut)? Self>, + ) -> $proj_ty_ident <'__pin, $($ty_generics)*> { + unsafe { + let Self { $($field),* } = self.$get_method(); + $proj_ty_ident { $( - $(#[$pin:ident])? - $field:ident: $field_ty:ty + $field: $crate::__pin_project_internal!(@make_unsafe_field_proj; + $(#[$pin])? $field + ) ),+ - })? - ),+ + } + } } - ) => {}; - + }; + (@struct=>make_proj_method; + [$proj_vis:vis] + [][$proj_ty_ident:ident] + [$method_ident:ident $get_method:ident $($mut:ident)?] + [$ident:ident] + [$($ty_generics:tt)*] + $($variant:tt)* + ) => { + $crate::__pin_project_internal! { @struct=>make_proj_method; + [$proj_vis] + [$proj_ty_ident][$proj_ty_ident] + [$method_ident $get_method $($mut)?] + [$ident] + [$($ty_generics)*] + $($variant)* + } + }; // ============================================================================================= - // make_proj_method: enum - (@make_proj_method_enum; + // enum:make_proj_method + (@enum=>make_proj_method; [$proj_vis:vis] [$proj_ty_ident:ident] [$method_ident:ident $get_method:ident $($mut:ident)?] - [enum $ident:ident] + [$ident:ident] [$($ty_generics:tt)*] { $( @@ -734,22 +835,13 @@ macro_rules! __pin_project_internal { } } }; - (@make_proj_method_enum; + (@enum=>make_proj_method; [$proj_vis:vis] [] [$method_ident:ident $get_method:ident $($mut:ident)?] - [enum $ident:ident] + [$ident:ident] [$($ty_generics:tt)*] - { - $( - $variant:ident $({ - $( - $(#[$pin:ident])? - $field:ident: $field_ty:ty - ),+ - })? - ),+ - } + $($variant:tt)* ) => {}; // ============================================================================================= @@ -855,40 +947,23 @@ macro_rules! __pin_project_internal { // ============================================================================================= // make_proj_field - (@make_proj_field; - #[pin] - $field_ty:ty; - $($mut:ident)? - ) => { - $crate::__private::Pin<&'__pin $($mut)? ($field_ty)> - }; - (@make_proj_field; - $field_ty:ty; - $($mut:ident)? - ) => { - &'__pin $($mut)? ($field_ty) - }; - // FIXME: remove (@make_proj_field_mut; #[pin] $field_ty:ty ) => { $crate::__private::Pin<&'__pin mut ($field_ty)> }; - // FIXME: remove (@make_proj_field_mut; $field_ty:ty ) => { &'__pin mut ($field_ty) }; - // FIXME: remove (@make_proj_field_ref; #[pin] $field_ty:ty ) => { $crate::__private::Pin<&'__pin ($field_ty)> }; - // FIXME: remove (@make_proj_field_ref; $field_ty:ty ) => { @@ -926,7 +1001,9 @@ macro_rules! __pin_project_internal { ),+ $(,)? } ) => { - $crate::__pin_project_internal! { @struct_internal; + $crate::__pin_project_internal! { @struct=>internal; + [$($proj_mut_ident)?] + [$($proj_ref_ident)?] [pub(crate)] [$(#[$attrs])* pub struct $ident] [$(< @@ -988,7 +1065,9 @@ macro_rules! __pin_project_internal { ),+ $(,)? } ) => { - $crate::__pin_project_internal! { @struct_internal; + $crate::__pin_project_internal! { @struct=>internal; + [$($proj_mut_ident)?] + [$($proj_ref_ident)?] [$vis] [$(#[$attrs])* $vis struct $ident] [$(< @@ -1055,10 +1134,10 @@ macro_rules! __pin_project_internal { ),+ $(,)? } ) => { - $crate::__pin_project_internal! { @enum_internal; - [pub(crate)] + $crate::__pin_project_internal! { @enum=>internal; [$($proj_mut_ident)?] [$($proj_ref_ident)?] + [pub(crate)] [$(#[$attrs])* pub enum $ident] [$(< $( $lifetime $(: $lifetime_bound)? ,)* @@ -1127,10 +1206,10 @@ macro_rules! __pin_project_internal { ),+ $(,)? } ) => { - $crate::__pin_project_internal! { @enum_internal; - [$vis] + $crate::__pin_project_internal! { @enum=>internal; [$($proj_mut_ident)?] [$($proj_ref_ident)?] + [$vis] [$(#[$attrs])* $vis enum $ident] [$(< $( $lifetime $(: $lifetime_bound)? ,)* diff --git a/tests/expand/tests/expand/default-struct.expanded.rs b/tests/expand/tests/expand/default-struct.expanded.rs index 3283595..17971ae 100644 --- a/tests/expand/tests/expand/default-struct.expanded.rs +++ b/tests/expand/tests/expand/default-struct.expanded.rs @@ -9,6 +9,7 @@ struct Struct { #[allow(clippy::used_underscore_binding)] const _: () = { #[allow(dead_code)] + #[allow(single_use_lifetimes)] #[allow(clippy::mut_mut)] #[allow(clippy::redundant_pub_crate)] #[allow(clippy::type_repetition_in_bounds)] @@ -20,6 +21,8 @@ const _: () = { unpinned: &'__pin mut (U), } #[allow(dead_code)] + #[allow(single_use_lifetimes)] + #[allow(clippy::mut_mut)] #[allow(clippy::redundant_pub_crate)] #[allow(clippy::type_repetition_in_bounds)] struct ProjectionRef<'__pin, T, U> diff --git a/tests/expand/tests/expand/naming-struct-all.expanded.rs b/tests/expand/tests/expand/naming-struct-all.expanded.rs new file mode 100644 index 0000000..3412d52 --- /dev/null +++ b/tests/expand/tests/expand/naming-struct-all.expanded.rs @@ -0,0 +1,79 @@ +use pin_project_lite::pin_project; +struct Struct { + pinned: T, + unpinned: U, +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +#[allow(clippy::mut_mut)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::type_repetition_in_bounds)] +struct StructProj<'__pin, T, U> +where + Struct: '__pin, +{ + pinned: ::pin_project_lite::__private::Pin<&'__pin mut (T)>, + unpinned: &'__pin mut (U), +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +#[allow(clippy::mut_mut)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::type_repetition_in_bounds)] +struct StructProjRef<'__pin, T, U> +where + Struct: '__pin, +{ + pinned: ::pin_project_lite::__private::Pin<&'__pin (T)>, + unpinned: &'__pin (U), +} +#[allow(explicit_outlives_requirements)] +#[allow(single_use_lifetimes)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::used_underscore_binding)] +const _: () = { + impl Struct { + fn project<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin mut Self>, + ) -> StructProj<'__pin, T, U> { + unsafe { + let Self { pinned, unpinned } = self.get_unchecked_mut(); + StructProj { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + } + } + } + fn project_ref<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin Self>, + ) -> StructProjRef<'__pin, T, U> { + unsafe { + let Self { pinned, unpinned } = self.get_ref(); + StructProjRef { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + } + } + } + } + #[allow(non_snake_case)] + struct __Origin<'__pin, T, U> { + __dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>, + pinned: T, + unpinned: ::pin_project_lite::__private::AlwaysUnpin, + } + impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct where + __Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin + { + } + trait MustNotImplDrop {} + #[allow(clippy::drop_bounds, drop_bounds)] + impl MustNotImplDrop for T {} + impl MustNotImplDrop for Struct {} + #[forbid(safe_packed_borrows)] + fn __assert_not_repr_packed(this: &Struct) { + let _ = &this.pinned; + let _ = &this.unpinned; + } +}; +fn main() {} diff --git a/tests/expand/tests/expand/naming-struct-all.rs b/tests/expand/tests/expand/naming-struct-all.rs new file mode 100644 index 0000000..3426c70 --- /dev/null +++ b/tests/expand/tests/expand/naming-struct-all.rs @@ -0,0 +1,13 @@ +use pin_project_lite::pin_project; + +pin_project! { + #[project = StructProj] + #[project_ref = StructProjRef] + struct Struct { + #[pin] + pinned: T, + unpinned: U, + } +} + +fn main() {} diff --git a/tests/expand/tests/expand/naming-struct-mut.expanded.rs b/tests/expand/tests/expand/naming-struct-mut.expanded.rs new file mode 100644 index 0000000..1f7b525 --- /dev/null +++ b/tests/expand/tests/expand/naming-struct-mut.expanded.rs @@ -0,0 +1,79 @@ +use pin_project_lite::pin_project; +struct Struct { + pinned: T, + unpinned: U, +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +#[allow(clippy::mut_mut)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::type_repetition_in_bounds)] +struct StructProj<'__pin, T, U> +where + Struct: '__pin, +{ + pinned: ::pin_project_lite::__private::Pin<&'__pin mut (T)>, + unpinned: &'__pin mut (U), +} +#[allow(explicit_outlives_requirements)] +#[allow(single_use_lifetimes)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::used_underscore_binding)] +const _: () = { + #[allow(dead_code)] + #[allow(single_use_lifetimes)] + #[allow(clippy::mut_mut)] + #[allow(clippy::redundant_pub_crate)] + #[allow(clippy::type_repetition_in_bounds)] + struct ProjectionRef<'__pin, T, U> + where + Struct: '__pin, + { + pinned: ::pin_project_lite::__private::Pin<&'__pin (T)>, + unpinned: &'__pin (U), + } + impl Struct { + fn project<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin mut Self>, + ) -> StructProj<'__pin, T, U> { + unsafe { + let Self { pinned, unpinned } = self.get_unchecked_mut(); + StructProj { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + } + } + } + fn project_ref<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin Self>, + ) -> ProjectionRef<'__pin, T, U> { + unsafe { + let Self { pinned, unpinned } = self.get_ref(); + ProjectionRef { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + } + } + } + } + #[allow(non_snake_case)] + struct __Origin<'__pin, T, U> { + __dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>, + pinned: T, + unpinned: ::pin_project_lite::__private::AlwaysUnpin, + } + impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct where + __Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin + { + } + trait MustNotImplDrop {} + #[allow(clippy::drop_bounds, drop_bounds)] + impl MustNotImplDrop for T {} + impl MustNotImplDrop for Struct {} + #[forbid(safe_packed_borrows)] + fn __assert_not_repr_packed(this: &Struct) { + let _ = &this.pinned; + let _ = &this.unpinned; + } +}; +fn main() {} diff --git a/tests/expand/tests/expand/naming-struct-mut.rs b/tests/expand/tests/expand/naming-struct-mut.rs new file mode 100644 index 0000000..59db445 --- /dev/null +++ b/tests/expand/tests/expand/naming-struct-mut.rs @@ -0,0 +1,12 @@ +use pin_project_lite::pin_project; + +pin_project! { + #[project = StructProj] + struct Struct { + #[pin] + pinned: T, + unpinned: U, + } +} + +fn main() {} diff --git a/tests/expand/tests/expand/naming-struct-none.expanded.rs b/tests/expand/tests/expand/naming-struct-none.expanded.rs new file mode 100644 index 0000000..17971ae --- /dev/null +++ b/tests/expand/tests/expand/naming-struct-none.expanded.rs @@ -0,0 +1,79 @@ +use pin_project_lite::pin_project; +struct Struct { + pinned: T, + unpinned: U, +} +#[allow(explicit_outlives_requirements)] +#[allow(single_use_lifetimes)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::used_underscore_binding)] +const _: () = { + #[allow(dead_code)] + #[allow(single_use_lifetimes)] + #[allow(clippy::mut_mut)] + #[allow(clippy::redundant_pub_crate)] + #[allow(clippy::type_repetition_in_bounds)] + struct Projection<'__pin, T, U> + where + Struct: '__pin, + { + pinned: ::pin_project_lite::__private::Pin<&'__pin mut (T)>, + unpinned: &'__pin mut (U), + } + #[allow(dead_code)] + #[allow(single_use_lifetimes)] + #[allow(clippy::mut_mut)] + #[allow(clippy::redundant_pub_crate)] + #[allow(clippy::type_repetition_in_bounds)] + struct ProjectionRef<'__pin, T, U> + where + Struct: '__pin, + { + pinned: ::pin_project_lite::__private::Pin<&'__pin (T)>, + unpinned: &'__pin (U), + } + impl Struct { + fn project<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin mut Self>, + ) -> Projection<'__pin, T, U> { + unsafe { + let Self { pinned, unpinned } = self.get_unchecked_mut(); + Projection { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + } + } + } + fn project_ref<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin Self>, + ) -> ProjectionRef<'__pin, T, U> { + unsafe { + let Self { pinned, unpinned } = self.get_ref(); + ProjectionRef { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + } + } + } + } + #[allow(non_snake_case)] + struct __Origin<'__pin, T, U> { + __dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>, + pinned: T, + unpinned: ::pin_project_lite::__private::AlwaysUnpin, + } + impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct where + __Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin + { + } + trait MustNotImplDrop {} + #[allow(clippy::drop_bounds, drop_bounds)] + impl MustNotImplDrop for T {} + impl MustNotImplDrop for Struct {} + #[forbid(safe_packed_borrows)] + fn __assert_not_repr_packed(this: &Struct) { + let _ = &this.pinned; + let _ = &this.unpinned; + } +}; +fn main() {} diff --git a/tests/expand/tests/expand/naming-struct-none.rs b/tests/expand/tests/expand/naming-struct-none.rs new file mode 100644 index 0000000..e5447c7 --- /dev/null +++ b/tests/expand/tests/expand/naming-struct-none.rs @@ -0,0 +1,11 @@ +use pin_project_lite::pin_project; + +pin_project! { + struct Struct { + #[pin] + pinned: T, + unpinned: U, + } +} + +fn main() {} diff --git a/tests/expand/tests/expand/naming-struct-ref.expanded.rs b/tests/expand/tests/expand/naming-struct-ref.expanded.rs new file mode 100644 index 0000000..6731ed4 --- /dev/null +++ b/tests/expand/tests/expand/naming-struct-ref.expanded.rs @@ -0,0 +1,79 @@ +use pin_project_lite::pin_project; +struct Struct { + pinned: T, + unpinned: U, +} +#[allow(dead_code)] +#[allow(single_use_lifetimes)] +#[allow(clippy::mut_mut)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::type_repetition_in_bounds)] +struct StructProjRef<'__pin, T, U> +where + Struct: '__pin, +{ + pinned: ::pin_project_lite::__private::Pin<&'__pin (T)>, + unpinned: &'__pin (U), +} +#[allow(explicit_outlives_requirements)] +#[allow(single_use_lifetimes)] +#[allow(clippy::redundant_pub_crate)] +#[allow(clippy::used_underscore_binding)] +const _: () = { + #[allow(dead_code)] + #[allow(single_use_lifetimes)] + #[allow(clippy::mut_mut)] + #[allow(clippy::redundant_pub_crate)] + #[allow(clippy::type_repetition_in_bounds)] + struct Projection<'__pin, T, U> + where + Struct: '__pin, + { + pinned: ::pin_project_lite::__private::Pin<&'__pin mut (T)>, + unpinned: &'__pin mut (U), + } + impl Struct { + fn project<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin mut Self>, + ) -> Projection<'__pin, T, U> { + unsafe { + let Self { pinned, unpinned } = self.get_unchecked_mut(); + Projection { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + } + } + } + fn project_ref<'__pin>( + self: ::pin_project_lite::__private::Pin<&'__pin Self>, + ) -> StructProjRef<'__pin, T, U> { + unsafe { + let Self { pinned, unpinned } = self.get_ref(); + StructProjRef { + pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned), + unpinned: unpinned, + } + } + } + } + #[allow(non_snake_case)] + struct __Origin<'__pin, T, U> { + __dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>, + pinned: T, + unpinned: ::pin_project_lite::__private::AlwaysUnpin, + } + impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Struct where + __Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin + { + } + trait MustNotImplDrop {} + #[allow(clippy::drop_bounds, drop_bounds)] + impl MustNotImplDrop for T {} + impl MustNotImplDrop for Struct {} + #[forbid(safe_packed_borrows)] + fn __assert_not_repr_packed(this: &Struct) { + let _ = &this.pinned; + let _ = &this.unpinned; + } +}; +fn main() {} diff --git a/tests/expand/tests/expand/naming-struct-ref.rs b/tests/expand/tests/expand/naming-struct-ref.rs new file mode 100644 index 0000000..6821af8 --- /dev/null +++ b/tests/expand/tests/expand/naming-struct-ref.rs @@ -0,0 +1,12 @@ +use pin_project_lite::pin_project; + +pin_project! { + #[project_ref = StructProjRef] + struct Struct { + #[pin] + pinned: T, + unpinned: U, + } +} + +fn main() {} diff --git a/tests/expand/tests/expand/pub-struct.expanded.rs b/tests/expand/tests/expand/pub-struct.expanded.rs index 09e0989..a729172 100644 --- a/tests/expand/tests/expand/pub-struct.expanded.rs +++ b/tests/expand/tests/expand/pub-struct.expanded.rs @@ -9,6 +9,7 @@ pub struct Struct { #[allow(clippy::used_underscore_binding)] const _: () = { #[allow(dead_code)] + #[allow(single_use_lifetimes)] #[allow(clippy::mut_mut)] #[allow(clippy::redundant_pub_crate)] #[allow(clippy::type_repetition_in_bounds)] @@ -20,6 +21,8 @@ const _: () = { pub unpinned: &'__pin mut (U), } #[allow(dead_code)] + #[allow(single_use_lifetimes)] + #[allow(clippy::mut_mut)] #[allow(clippy::redundant_pub_crate)] #[allow(clippy::type_repetition_in_bounds)] pub(crate) struct ProjectionRef<'__pin, T, U> From 52b851840725fa36b5d08924418731f33b579ca7 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 20 Oct 2020 23:40:07 +0900 Subject: [PATCH 3/5] Support attrs on variant --- src/lib.rs | 6 ++++++ tests/test.rs | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index e1248e5..7e829df 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -507,6 +507,7 @@ macro_rules! __pin_project_internal { [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)*)?] { $( + $(#[$variant_attrs:meta])* $variant:ident $({ $( $(#[$pin:ident])? @@ -522,6 +523,7 @@ macro_rules! __pin_project_internal { $($where_clause)*)? { $( + $(#[$variant_attrs])* $variant $({ $( $field: $field_ty @@ -1125,6 +1127,7 @@ macro_rules! __pin_project_internal { )? { $( + $(#[$variant_attrs:meta])* $variant:ident $({ $( $(#[$pin:ident])? @@ -1164,6 +1167,7 @@ macro_rules! __pin_project_internal { ),* )?] { $( + $(#[$variant_attrs])* $variant $({ $( $(#[$pin])? @@ -1197,6 +1201,7 @@ macro_rules! __pin_project_internal { )? { $( + $(#[$variant_attrs:meta])* $variant:ident $({ $( $(#[$pin:ident])? @@ -1236,6 +1241,7 @@ macro_rules! __pin_project_internal { ),* )?] { $( + $(#[$variant_attrs])* $variant $({ $( $(#[$pin])? diff --git a/tests/test.rs b/tests/test.rs index f2130eb..c085ed0 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -570,3 +570,15 @@ fn trailing_comma() { // } // } } + +#[test] +fn attrs() { + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + enum Enum { + #[cfg(not(any()))] + V { f: () }, + } + } +} From fc222a44e8ebf9f59398d96dd69a01ef70a47968 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Tue, 20 Oct 2020 23:40:22 +0900 Subject: [PATCH 4/5] Allow #[doc] placed before #[project] --- src/lib.rs | 9 ++++++++- tests/test.rs | 23 +++++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 7e829df..0c60f58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -150,12 +150,13 @@ /// ``` /// /// The `#[project]` (and `#[project_ref]`) attribute must precede the other -/// attributes. For example, the following code will not be compiled: +/// attributes except for `#[doc]`. For example, the following code will not be compiled: /// /// ```rust,compile_fail /// # use pin_project_lite::pin_project; /// # use std::pin::Pin; /// pin_project! { +/// /// documents (`#[doc]`) can be placed before `#[project]`. /// #[derive(Clone)] // <--- ERROR /// #[project = EnumProj] /// #[derive(Debug)] // <--- Ok @@ -290,30 +291,36 @@ macro_rules! pin_project { // Parses options ( + $(#[doc $($doc:tt)*])* #[project = $proj_mut_ident:ident] #[project_ref = $proj_ref_ident:ident] $($tt:tt)* ) => { $crate::__pin_project_internal! { [$proj_mut_ident][$proj_ref_ident] + $(#[doc $($doc)*])* $($tt)* } }; ( + $(#[doc $($doc:tt)*])* #[project = $proj_mut_ident:ident] $($tt:tt)* ) => { $crate::__pin_project_internal! { [$proj_mut_ident][] + $(#[doc $($doc)*])* $($tt)* } }; ( + $(#[doc $($doc:tt)*])* #[project_ref = $proj_ref_ident:ident] $($tt:tt)* ) => { $crate::__pin_project_internal! { [][$proj_ref_ident] + $(#[doc $($doc)*])* $($tt)* } }; diff --git a/tests/test.rs b/tests/test.rs index c085ed0..6f2b511 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -574,11 +574,26 @@ fn trailing_comma() { #[test] fn attrs() { pin_project! { - #[project = EnumProj] - #[project_ref = EnumProjRef] - enum Enum { + #[project = Enum1Proj] + #[project_ref = Enum1ProjRef] + enum Enum1 { #[cfg(not(any()))] - V { f: () }, + V { + f: () + }, + } + } + + pin_project! { + /// dox + #[project = Enum2Proj] + #[project_ref = Enum2ProjRef] + enum Enum2 { + /// dox + V { + // TODO + f: () + }, } } } From 522a9ec7f89c3e692b0044a2ec0c4b7ffb0546c2 Mon Sep 17 00:00:00 2001 From: Taiki Endo Date: Sat, 24 Oct 2020 22:21:10 +0900 Subject: [PATCH 5/5] Update tests --- tests/include/basic.rs | 11 +++++++++++ tests/proper_unpin.rs | 31 ++++++++++++++++++++++++------- tests/test.rs | 4 ++-- 3 files changed, 37 insertions(+), 9 deletions(-) diff --git a/tests/include/basic.rs b/tests/include/basic.rs index 64c9013..25121f2 100644 --- a/tests/include/basic.rs +++ b/tests/include/basic.rs @@ -9,6 +9,17 @@ } } +::pin_project_lite::pin_project! { + #[project = DefaultStructProj] + #[project_ref = DefaultStructProjRef] + #[derive(Debug)] + pub struct DefaultStructNamed { + #[pin] + pub pinned: T, + pub unpinned: U, + } +} + ::pin_project_lite::pin_project! { #[project = DefaultEnumProj] #[project_ref = DefaultEnumProjRef] diff --git a/tests/proper_unpin.rs b/tests/proper_unpin.rs index bbee78c..b1c72c1 100644 --- a/tests/proper_unpin.rs +++ b/tests/proper_unpin.rs @@ -16,17 +16,34 @@ pub mod default { assert_not_unpin!(Inner); pin_project! { - struct Foo { + struct Struct { #[pin] f1: Inner, f2: U, } } - assert_unpin!(Foo<(), ()>); - assert_unpin!(Foo<(), PhantomPinned>); - assert_not_unpin!(Foo); - assert_not_unpin!(Foo); + assert_unpin!(Struct<(), ()>); + assert_unpin!(Struct<(), PhantomPinned>); + assert_not_unpin!(Struct); + assert_not_unpin!(Struct); + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + enum Enum { + V1 { + #[pin] + f1: Inner, + f2: U, + }, + } + } + + assert_unpin!(Enum<(), ()>); + assert_unpin!(Enum<(), PhantomPinned>); + assert_not_unpin!(Enum); + assert_not_unpin!(Enum); pin_project! { struct TrivialBounds { @@ -38,12 +55,12 @@ pub mod default { assert_not_unpin!(TrivialBounds); pin_project! { - struct Bar<'a, T, U> { + struct PinRef<'a, T, U> { #[pin] f1: &'a mut Inner, f2: U, } } - assert_unpin!(Bar<'_, PhantomPinned, PhantomPinned>); + assert_unpin!(PinRef<'_, PhantomPinned, PhantomPinned>); } diff --git a/tests/test.rs b/tests/test.rs index 6f2b511..cc58c40 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -435,7 +435,7 @@ fn dst() { let mut x = Struct1 { f: 0_u8 }; let x: Pin<&mut Struct1> = Pin::new(&mut x as _); - let _y: &mut (dyn core::fmt::Debug) = x.project().f; + let _: &mut (dyn core::fmt::Debug) = x.project().f; pin_project! { pub struct Struct2 { @@ -446,7 +446,7 @@ fn dst() { let mut x = Struct2 { f: 0_u8 }; let x: Pin<&mut Struct2> = Pin::new(&mut x as _); - let _y: Pin<&mut (dyn core::fmt::Debug + Unpin)> = x.project().f; + let _: Pin<&mut (dyn core::fmt::Debug + Unpin)> = x.project().f; pin_project! { struct Struct3