//! A lightweight version of [pin-project] written with declarative macros.
//!
//! # Examples
//!
//! [`pin_project!`] macro creates a projection type covering all the fields of struct.
//!
//! ```rust
//! use std::pin::Pin;
//!
//! use pin_project_lite::pin_project;
//!
//! pin_project! {
//!     struct Struct<T, U> {
//!         #[pin]
//!         pinned: T,
//!         unpinned: U,
//!     }
//! }
//!
//! impl<T, U> Struct<T, U> {
//!     fn method(self: Pin<&mut Self>) {
//!         let this = self.project();
//!         let _: Pin<&mut T> = this.pinned; // Pinned reference to the field
//!         let _: &mut U = this.unpinned; // Normal reference to the field
//!     }
//! }
//! ```
//!
//! To use [`pin_project!`] on enums, you need to name the projection type
//! returned from the method.
//!
//! ```rust
//! use std::pin::Pin;
//!
//! use pin_project_lite::pin_project;
//!
//! pin_project! {
//!     #[project = EnumProj]
//!     enum Enum<T, U> {
//!         Variant { #[pin] pinned: T, unpinned: U },
//!     }
//! }
//!
//! impl<T, U> Enum<T, U> {
//!     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].
//!
//! ## Similar: Safety
//!
//! pin-project-lite guarantees safety in much the same way as [pin-project].
//! Both are completely safe unless you write other unsafe code.
//!
//! ## Different: Minimal design
//!
//! This library does not tackle as expansive of a range of use cases as
//! [pin-project] does. If your use case is not already covered, please use
//! [pin-project].
//!
//! ## Different: No proc-macro related dependencies
//!
//! This is the **only** reason to use this crate. However, **if you already
//! have proc-macro related dependencies in your crate's dependency graph, there
//! is no benefit from using this crate.** (Note: There is almost no difference
//! in the amount of code generated between [pin-project] and pin-project-lite.)
//!
//! ## Different: No useful error messages
//!
//! 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: No support for custom Unpin implementation
//!
//! pin-project supports this by [`UnsafeUnpin`][unsafe-unpin] and [`!Unpin`][not-unpin].
//!
//! ## Different: No support for tuple structs and tuple variants
//!
//! pin-project supports this.
//!
//! [not-unpin]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#unpin
//! [pin-project]: https://github.com/taiki-e/pin-project
//! [unsafe-unpin]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#unsafeunpin

#![no_std]
#![doc(test(
    no_crate_inject,
    attr(
        deny(warnings, rust_2018_idioms, single_use_lifetimes),
        allow(dead_code, unused_variables)
    )
))]
#![warn(rust_2018_idioms, single_use_lifetimes, unreachable_pub)]
#![warn(clippy::default_trait_access, clippy::wildcard_imports)]

/// A macro that creates a projection type covering all the fields of struct.
///
/// This macro creates a projection type according to the following rules:
///
/// - For the field that uses `#[pin]` attribute, makes the pinned reference to the field.
/// - For the other fields, makes the unpinned reference to the field.
///
/// And the following methods are implemented on the original type:
///
/// ```rust
/// # use std::pin::Pin;
/// # type Projection<'a> = &'a ();
/// # type ProjectionRef<'a> = &'a ();
/// # trait Dox {
/// fn project(self: Pin<&mut Self>) -> Projection<'_>;
/// fn project_ref(self: Pin<&Self>) -> ProjectionRef<'_>;
/// # }
/// ```
///
/// 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<T> {
///         Variant { #[pin] field: T },
///     }
/// }
///
/// impl<T> Enum<T> {
///     fn method(self: Pin<&mut Self>) {
///         let this: EnumProj<'_, T> = self.project();
///         match this {
///             EnumProj::Variant { field } => {
///                 let _: Pin<&mut T> = field;
///             }
///         }
///     }
/// }
/// ```
///
/// By passing the `#[project_replace = MyProjReplace]` attribute you may create an additional
/// method which allows the contents of `Pin<&mut Self>` to be replaced while simultaneously moving
/// out all unpinned fields in `Self`.
///
/// ```rust
/// # use std::pin::Pin;
/// # type MyProjReplace = ();
/// # trait Dox {
/// fn project_replace(self: Pin<&mut Self>, replacement: Self) -> MyProjReplace;
/// # }
/// ```
///
/// 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
///
/// `pin_project!` macro guarantees safety in much the same way as [pin-project] crate.
/// Both are completely safe unless you write other unsafe code.
///
/// See [pin-project] crate for more details.
///
/// # Examples
///
/// ```rust
/// use std::pin::Pin;
///
/// use pin_project_lite::pin_project;
///
/// pin_project! {
///     struct Struct<T, U> {
///         #[pin]
///         pinned: T,
///         unpinned: U,
///     }
/// }
///
/// impl<T, U> Struct<T, U> {
///     fn method(self: Pin<&mut Self>) {
///         let this = self.project();
///         let _: Pin<&mut T> = this.pinned; // Pinned reference to the field
///         let _: &mut U = this.unpinned; // Normal reference to the field
///     }
/// }
/// ```
///
/// To use `pin_project!` on enums, you need to name the projection type
/// returned from the method.
///
/// ```rust
/// use std::pin::Pin;
///
/// use pin_project_lite::pin_project;
///
/// pin_project! {
///     #[project = EnumProj]
///     enum Enum<T> {
///         Struct {
///             #[pin]
///             field: T,
///         },
///         Unit,
///     }
/// }
///
/// impl<T> Enum<T> {
///     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`].
///
/// ```rust
/// use std::pin::Pin;
///
/// use pin_project_lite::pin_project;
///
/// pin_project! {
///     struct Struct<T> {
///         #[pin]
///         field: T,
///     }
/// }
///
/// impl<T> Struct<T> {
///     fn call_project_twice(mut self: Pin<&mut Self>) {
///         // `project` consumes `self`, so reborrow the `Pin<&mut Self>` via `as_mut`.
///         self.as_mut().project();
///         self.as_mut().project();
///     }
/// }
/// ```
///
/// # `!Unpin`
///
/// If you want to ensure that [`Unpin`] is not implemented, use `#[pin]`
/// attribute for a [`PhantomPinned`] field.
///
/// ```rust
/// use std::marker::PhantomPinned;
///
/// use pin_project_lite::pin_project;
///
/// pin_project! {
///     struct Struct<T> {
///         field: T,
///         #[pin] // <------ This `#[pin]` is required to make `Struct` to `!Unpin`.
///         _pin: PhantomPinned,
///     }
/// }
/// ```
///
/// Note that using [`PhantomPinned`] without `#[pin]` attribute has no effect.
///
/// [`PhantomPinned`]: core::marker::PhantomPinned
/// [`Pin::as_mut`]: core::pin::Pin::as_mut
/// [`Pin`]: core::pin::Pin
/// [pin-project]: https://github.com/taiki-e/pin-project
#[macro_export]
macro_rules! pin_project {
    ($($tt:tt)*) => {
        $crate::__pin_project_internal! {
            [][][][]
            $($tt)*
        }
    };
}

// limitations:
// - 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)
// - no interoperability with other field attributes.
// - no useful error messages. (wontfix)
// etc...

// Not public API.
#[doc(hidden)]
#[macro_export]
macro_rules! __pin_project_internal {
    // macro helpers
    // ignores any projection without a projection identity
    (@make_proj_ty;
        [] // no identity given, so we ignore the projection
        $($field:tt)*
    ) => {};
    // ignores make_proj_replace_ty without a projection identity
    (@make_proj_replace_ty;
        [] // no identity given, so we ignore the projection
        $($field:tt)*
    ) => {};
    (@$struct_ty_ident:ident=>make_proj_method;
        []
        $($variant:tt)*
    ) => {};
    (@$struct_ty_ident:ident=>make_proj_replace_method;
        []
        $($field:tt)*
    ) => {};
    // =============================================================================================
    // struct:main
    (@expand;
        [$($proj_mut_ident:ident)?]
        [$($proj_ref_ident:ident)?]
        [$($proj_replace_ident:ident)?]
        [$proj_vis:vis]
        [$(#[$attrs:meta])* $vis:vis $struct_ty_ident:ident $ident:ident]
        [$($def_generics:tt)*]
        [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)*)?]
        {
            $($body_data:tt)*
        }
        $(impl $($pinned_drop:tt)*)?
    ) => {
        $crate::__pin_project_internal! { @reconstruct;
            [$(#[$attrs])* $vis $struct_ty_ident $ident]
            [$($def_generics)*] [$($impl_generics)*]
            [$($ty_generics)*] [$(where $($where_clause)*)?]
            {
                $($body_data)*
            }
        }

        $crate::__pin_project_internal! { @make_proj_ty;
            [$($proj_mut_ident)?]
            [$proj_vis $struct_ty_ident $ident]
            [make_proj_field_mut]
            [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
            {
                $($body_data)*
            }
        }
        $crate::__pin_project_internal! { @make_proj_ty;
            [$($proj_ref_ident)?]
            [$proj_vis $struct_ty_ident $ident]
            [make_proj_field_ref]
            [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
            {
                $($body_data)*
            }
        }
        $crate::__pin_project_internal! { @make_proj_replace_ty;
            [$($proj_replace_ident)?]
            [$proj_vis $struct_ty_ident]
            [make_proj_field_replace]
            [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
            {
                $($body_data)*
            }
        }

        $crate::__pin_project_internal! { @constant;
            [$(#[$attrs])* $vis $struct_ty_ident $ident]
            [$($proj_mut_ident)?] [$($proj_ref_ident)?] [$($proj_replace_ident)?]
            [$proj_vis]
            [$($def_generics)*] [$($impl_generics)*]
            [$($ty_generics)*] [$(where $($where_clause)*)?]
            {
                $($body_data)*
            }
            $(impl $($pinned_drop)*)?
        }
    };
    (@constant;
        [$(#[$attrs:meta])* $vis:vis struct $ident:ident]
        [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] [$($proj_replace_ident:ident)?]
        [$proj_vis:vis]
        [$($def_generics:tt)*]
        [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)*)?]
        {
            $(
                $(#[$pin:ident])?
                $field_vis:vis $field:ident: $field_ty:ty
            ),+ $(,)?
        }
        $(impl $($pinned_drop:tt)*)?
    ) => {

        #[allow(explicit_outlives_requirements)] // https://github.com/rust-lang/rust/issues/60993
        #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058
        // This lint warns of `clippy::*` generated by external macros.
        // We allow this lint for compatibility with older compilers.
        #[allow(clippy::unknown_clippy_lints)]
        #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct.
        #[allow(clippy::used_underscore_binding)]
        const _: () = {
            $crate::__pin_project_internal! { @make_proj_ty;
                [$($proj_mut_ident)? Projection]
                [$proj_vis struct $ident]
                [make_proj_field_mut]
                [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
                {
                    $(
                        $(#[$pin])?
                        $field_vis $field: $field_ty
                    ),+
                }
            }
            $crate::__pin_project_internal! { @make_proj_ty;
                [$($proj_ref_ident)? ProjectionRef]
                [$proj_vis struct $ident]
                [make_proj_field_ref]
                [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
                {
                    $(
                        $(#[$pin])?
                        $field_vis $field: $field_ty
                    ),+
                }
            }

            impl <$($impl_generics)*> $ident <$($ty_generics)*>
            $(where
                $($where_clause)*)?
            {
                $crate::__pin_project_internal! { @struct=>make_proj_method;
                    [$($proj_mut_ident)? Projection]
                    [$proj_vis]
                    [project get_unchecked_mut mut]
                    [$($ty_generics)*]
                    {
                        $(
                            $(#[$pin])?
                            $field_vis $field
                        ),+
                    }
                }
                $crate::__pin_project_internal! { @struct=>make_proj_method;
                    [$($proj_ref_ident)? ProjectionRef]
                    [$proj_vis]
                    [project_ref get_ref]
                    [$($ty_generics)*]
                    {
                        $(
                            $(#[$pin])?
                            $field_vis $field
                        ),+
                    }
                }
                $crate::__pin_project_internal! { @struct=>make_proj_replace_method;
                    [$($proj_replace_ident)?]
                    [$proj_vis]
                    [ProjectionReplace]
                    [$($ty_generics)*]
                    {
                        $(
                            $(#[$pin])?
                            $field_vis $field
                        ),+
                    }
                }
            }

            $crate::__pin_project_internal! { @make_unpin_impl;
                [$vis $ident]
                [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
                $(
                    $field: $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)*)?]
                $(impl $($pinned_drop)*)?
            }

            // Ensure that it's impossible to use pin projections on a #[repr(packed)] struct.
            //
            // Taking a reference to a packed field is UB, and applying
            // `#[forbid(unaligned_references)]` makes sure that doing this is a hard error.
            //
            // If the struct ends up having #[repr(packed)] applied somehow,
            // this will generate an (unfriendly) error message. Under all reasonable
            // circumstances, we'll detect the #[repr(packed)] attribute, and generate
            // a much nicer error above.
            //
            // See https://github.com/taiki-e/pin-project/pull/34 for more details.
            //
            // Note:
            // - Lint-based tricks aren't perfect, but they're much better than nothing:
            //   https://github.com/taiki-e/pin-project-lite/issues/26
            //
            // - Enable both unaligned_references and safe_packed_borrows lints
            //   because unaligned_references lint does not exist in older compilers:
            //   https://github.com/taiki-e/pin-project-lite/pull/55
            //   https://github.com/rust-lang/rust/pull/82525
            #[forbid(unaligned_references, safe_packed_borrows)]
            fn __assert_not_repr_packed <$($impl_generics)*> (this: &$ident <$($ty_generics)*>)
            $(where
                $($where_clause)*)?
            {
                $(
                    let _ = &this.$field;
                )+
            }
        };
    };
    // =============================================================================================
    // enum:main
    (@constant;
        [$(#[$attrs:meta])* $vis:vis enum $ident:ident]
        [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] [$($proj_replace_ident:ident)?]
        [$proj_vis:vis]
        [$($def_generics:tt)*]
        [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)*)?]
        {
            $(
                $(#[$variant_attrs:meta])*
                $variant:ident $({
                    $(
                        $(#[$pin:ident])?
                        $field:ident: $field_ty:ty
                    ),+ $(,)?
                })?
            ),+ $(,)?
        }
        $(impl $($pinned_drop:tt)*)?
    ) => {

        #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058
        // This lint warns of `clippy::*` generated by external macros.
        // We allow this lint for compatibility with older compilers.
        #[allow(clippy::unknown_clippy_lints)]
        #[allow(clippy::used_underscore_binding)]
        const _: () = {
            impl <$($impl_generics)*> $ident <$($ty_generics)*>
            $(where
                $($where_clause)*)?
            {
                $crate::__pin_project_internal! { @enum=>make_proj_method;
                    [$($proj_mut_ident)?]
                    [$proj_vis]
                    [project get_unchecked_mut mut]
                    [$($ty_generics)*]
                    {
                        $(
                            $variant $({
                                $(
                                    $(#[$pin])?
                                    $field
                                ),+
                            })?
                        ),+
                    }
                }
                $crate::__pin_project_internal! { @enum=>make_proj_method;
                    [$($proj_ref_ident)?]
                    [$proj_vis]
                    [project_ref get_ref]
                    [$($ty_generics)*]
                    {
                        $(
                            $variant $({
                                $(
                                    $(#[$pin])?
                                    $field
                                ),+
                            })?
                        ),+
                    }
                }
                $crate::__pin_project_internal! { @enum=>make_proj_replace_method;
                    [$($proj_replace_ident)?]
                    [$proj_vis]
                    [$($ty_generics)*]
                    {
                        $(
                            $variant $({
                                $(
                                    $(#[$pin])?
                                    $field
                                ),+
                            })?
                        ),+
                    }
                }
            }

            $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)*)?]
                $(impl $($pinned_drop)*)?
            }

            // We don't need to check for '#[repr(packed)]',
            // since it does not apply to enums.
        };
    };

    (@reconstruct;
        [$(#[$attrs:meta])* $vis:vis struct $ident:ident]
        [$($def_generics:tt)*] [$($impl_generics:tt)*]
        [$($ty_generics:tt)*] [$(where $($where_clause:tt)*)?]
        {
            $(
                $(#[$pin:ident])?
                $field_vis:vis $field:ident: $field_ty:ty
            ),+ $(,)?
        }
    ) => {
        $(#[$attrs])*
        $vis struct $ident $($def_generics)*
        $(where
            $($where_clause)*)?
        {
            $(
                $field_vis $field: $field_ty
            ),+
        }
    };

    // reconstruct original enum type
    (@reconstruct;
        [$(#[$attrs:meta])* $vis:vis enum $ident:ident]
        [$($def_generics:tt)*] [$($impl_generics:tt)*]
        [$($ty_generics:tt)*] [$(where $($where_clause:tt)*)?]
        {
            $(
                $(#[$variant_attrs:meta])*
                $variant:ident $({
                    $(
                        $(#[$pin:ident])?
                        $field:ident: $field_ty:ty
                    ),+ $(,)?
                })?
            ),+ $(,)?
        }
    ) => {
        $(#[$attrs])*
        $vis enum $ident $($def_generics)*
        $(where
            $($where_clause)*)?
        {
            $(
                $(#[$variant_attrs])*
                $variant $({
                    $(
                        $field: $field_ty
                    ),+
                })?
            ),+
        }
    };
    // construct a projected type
    (@make_proj_ty;
        [$proj_ty_ident:ident]
        [$proj_vis:vis $struct_ty_ident:ident $ident:ident]
        [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
        [$($body_data:tt)+]
    ) => {
        #[allow(dead_code)] // This lint warns unused fields/variants.
        #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058
        // This lint warns of `clippy::*` generated by external macros.
        // We allow this lint for compatibility with older compilers.
        #[allow(clippy::unknown_clippy_lints)]
        #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. (only needed for project)
        #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct.
        #[allow(clippy::ref_option_ref)] // This lint warns `&Option<&<ty>>`. (only needed for project_ref)
        #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326
        $proj_vis $struct_ty_ident $proj_ty_ident <'__pin, $($impl_generics)*>
        where
            $ident <$($ty_generics)*>: '__pin
            $(, $($where_clause)*)?
        {
            $($body_data)+
        }
    };
    // construct a project_replace type
    (@make_proj_replace_ty;
        [$proj_ty_ident:ident]
        [$proj_vis:vis $struct_ty_ident:ident]
        [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
        [$($body_data:tt)+]
    ) => {
        #[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 <ty>`. (only needed for project)
        #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct.
        #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326
        $proj_vis $struct_ty_ident $proj_ty_ident <$($impl_generics)*>
        where
            $($($where_clause)*)?
        {
            $($body_data)+
        }
    };
    // =============================================================================================
    // struct:make_proj_ty
    // if a proj_ty_ident was given, we do *not* create one with the default
    (@make_proj_ty;
        [$proj_ty_ident:ident $default_ident:ident]
        [$proj_vis:vis struct $ident:ident]
        $($field:tt)*
    ) => {};
    (@make_proj_ty;
        [$proj_ty_ident:ident]
        [$proj_vis:vis struct $ident:ident]
        [$make_proj_field:ident]
        [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
        {
            $(
                $(#[$pin:ident])?
                $field_vis:vis $field:ident: $field_ty:ty
            ),+ $(,)?
        }
    ) => {
        $crate::__pin_project_internal!{@make_proj_ty;
            [$proj_ty_ident]
            [$proj_vis struct $ident]
            [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)* )?]
            [
                $(
                    $field_vis $field: $crate::__pin_project_internal!(@$make_proj_field;
                        $(#[$pin])? $field_ty
                    )
                ),+
            ]
        }
    };
    (@make_proj_replace_ty;
        [$proj_ty_ident:ident]
        [$proj_vis:vis struct]
        [$make_proj_field:ident]
        [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
        {
            $(
                $(#[$pin:ident])?
                $field_vis:vis $field:ident: $field_ty:ty
            ),+ $(,)?
        }
    ) => {
        $crate::__pin_project_internal!{@make_proj_replace_ty;
            [$proj_ty_ident]
            [$proj_vis struct]
            [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)* )?]
            [
                $(
                    $field_vis $field: $crate::__pin_project_internal!(@$make_proj_field;
                        $(#[$pin])? $field_ty
                    )
                ),+
            ]
        }
    };
    // =============================================================================================
    // enum:make_proj_ty
    (@make_proj_ty;
        [$proj_ty_ident:ident]
        [$proj_vis:vis enum $ident:ident]
        [$make_proj_field:ident]
        [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
        {
            $(
                $(#[$variant_attrs:meta])*
                $variant:ident $({
                    $(
                        $(#[$pin:ident])?
                        $field:ident: $field_ty:ty
                    ),+ $(,)?
                })?
            ),+ $(,)?
        }
    ) => {
        $crate::__pin_project_internal!{@make_proj_ty;
            [$proj_ty_ident]
            [$proj_vis enum $ident]
            [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)* )?]
            [
                $(
                    $variant $({
                        $(
                            $field: $crate::__pin_project_internal!(@$make_proj_field;
                                $(#[$pin])? $field_ty
                            )
                        ),+
                    })?
                ),+
            ]
        }
    };
    (@make_proj_replace_ty;
        [$proj_ty_ident:ident]
        [$proj_vis:vis enum]
        [$make_proj_field:ident]
        [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
        {
            $(
                $(#[$variant_attrs:meta])*
                $variant:ident $({
                    $(
                        $(#[$pin:ident])?
                        $field:ident: $field_ty:ty
                    ),+ $(,)?
                })?
            ),+ $(,)?
        }
    ) => {
        $crate::__pin_project_internal!{@make_proj_replace_ty;
            [$proj_ty_ident]
            [$proj_vis enum]
            [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)* )?]
            [
                $(
                    $variant $({
                        $(
                            $field: $crate::__pin_project_internal!(@$make_proj_field;
                                $(#[$pin])? $field_ty
                            )
                        ),+
                    })?
                ),+
            ]
        }
    };
    // =============================================================================================
    (@make_proj_replace_block;
        [$($proj_path: tt)+]
        {
            $(
                $(#[$pin:ident])?
                $field_vis:vis $field:ident
            ),+
        }
    ) => {
        let result = $($proj_path)* {
            $(
                $field: $crate::__pin_project_internal!(@make_replace_field_proj;
                    $(#[$pin])? $field
                )
            ),+
        };

        {
            ( $(
                $crate::__pin_project_internal!(@make_unsafe_drop_in_place_guard;
                    $(#[$pin])? $field
                ),
            )* );
        }

        result
    };
    (@make_proj_replace_block;
        [$($proj_path: tt)+]
    ) => {
        $($proj_path)*
    };

    // =============================================================================================
    // struct:make_proj_method
    // this employs an ignored default strategy that ensures the identity used matches the one used in `struct=>make_proj_ty`
    (@struct=>make_proj_method;
        [$proj_ty_ident:ident $_ignored_default_arg:ident]
        [$proj_vis:vis]
        [$method_ident:ident $get_method:ident $($mut:ident)?]
        [$($ty_generics:tt)*]
        $($variant:tt)*
    ) => {
        $crate::__pin_project_internal! { @struct=>make_proj_method;
            [$proj_ty_ident]
            [$proj_vis]
            [$method_ident $get_method $($mut)?]
            [$($ty_generics)*]
            $($variant)*
        }
    };
    (@struct=>make_proj_method;
        [$proj_ty_ident:ident]
        [$proj_vis:vis]
        [$method_ident:ident $get_method:ident $($mut:ident)?]
        [$($ty_generics:tt)*]
        {
            $(
                $(#[$pin:ident])?
                $field_vis:vis $field:ident
            ),+
        }
    ) => {
        $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 {
                    $(
                        $field: $crate::__pin_project_internal!(@make_unsafe_field_proj;
                            $(#[$pin])? $field
                        )
                    ),+
                }
            }
        }
    };

    (@struct=>make_proj_replace_method;
        [$proj_ty_ident:ident]
        [$proj_vis:vis]
        [$_proj_ty_ident:ident]
        [$($ty_generics:tt)*]
        {
            $(
                $(#[$pin:ident])?
                $field_vis:vis $field:ident
            ),+
        }
    ) => {
        $proj_vis fn project_replace(
            self: $crate::__private::Pin<&mut Self>,
            replacement: Self,
        ) -> $proj_ty_ident <$($ty_generics)*> {
            unsafe {
                let __self_ptr: *mut Self = self.get_unchecked_mut();

                // Destructors will run in reverse order, so next create a guard to overwrite
                // `self` with the replacement value without calling destructors.
                let __guard = $crate::__private::UnsafeOverwriteGuard::new(__self_ptr, replacement);

                let Self { $($field),* } = &mut *__self_ptr;

                $crate::__pin_project_internal!{@make_proj_replace_block;
                    [$proj_ty_ident]
                    {
                        $(
                            $(#[$pin])?
                            $field
                        ),+
                    }
                }
            }
        }
    };
    // =============================================================================================
    // enum:make_proj_method
    (@enum=>make_proj_method;
        [$proj_ty_ident:ident]
        [$proj_vis:vis]
        [$method_ident:ident $get_method:ident $($mut:ident)?]
        [$($ty_generics:tt)*]
        {
            $(
                $variant:ident $({
                    $(
                        $(#[$pin:ident])?
                        $field:ident
                    ),+
                })?
            ),+
        }
    ) => {
        $proj_vis fn $method_ident<'__pin>(
            self: $crate::__private::Pin<&'__pin $($mut)? Self>,
        ) -> $proj_ty_ident <'__pin, $($ty_generics)*> {
            unsafe {
                match self.$get_method() {
                    $(
                        Self::$variant $({
                            $($field),+
                        })? => {
                            $proj_ty_ident::$variant $({
                                $(
                                    $field: $crate::__pin_project_internal!(
                                        @make_unsafe_field_proj;
                                        $(#[$pin])? $field
                                    )
                                ),+
                            })?
                        }
                    ),+
                }
            }
        }
    };
    (@enum=>make_proj_replace_method;
        [$proj_ty_ident:ident]
        [$proj_vis:vis]
        [$($ty_generics:tt)*]
        {
            $(
                $variant:ident $({
                    $(
                        $(#[$pin:ident])?
                        $field:ident
                    ),+
                })?
            ),+
        }
    ) => {
        $proj_vis fn project_replace(
            self: $crate::__private::Pin<&mut Self>,
            replacement: Self,
        ) -> $proj_ty_ident <$($ty_generics)*> {
            unsafe {
                let __self_ptr: *mut Self = self.get_unchecked_mut();

                // Destructors will run in reverse order, so next create a guard to overwrite
                // `self` with the replacement value without calling destructors.
                let __guard = $crate::__private::UnsafeOverwriteGuard::new(__self_ptr, replacement);

                match &mut *__self_ptr {
                    $(
                        Self::$variant $({
                            $($field),+
                        })? => {
                            $crate::__pin_project_internal!{@make_proj_replace_block;
                                [$proj_ty_ident :: $variant]
                                $({
                                    $(
                                        $(#[$pin])?
                                        $field
                                    ),+
                                })?
                            }
                        }
                    ),+
                }
            }
        }
    };
    // =============================================================================================
    // make_unpin_impl
    (@make_unpin_impl;
        [$vis:vis $ident:ident]
        [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
        $($field:tt)*
    ) => {
        // Automatically create the appropriate conditional `Unpin` implementation.
        //
        // Basically this is equivalent to the following code:
        // ```rust
        // impl<T, U> Unpin for Struct<T, U> where T: Unpin {}
        // ```
        //
        // However, if struct is public and there is a private type field,
        // this would cause an E0446 (private type in public interface).
        //
        // When RFC 2145 is implemented (rust-lang/rust#48054),
        // this will become a lint, rather then a hard error.
        //
        // As a workaround for this, we generate a new struct, containing all of the pinned
        // fields from our #[pin_project] type. This struct is declared within
        // a function, which makes it impossible to be named by user code.
        // This guarantees that it will use the default auto-trait impl for Unpin -
        // that is, it will implement Unpin iff all of its fields implement Unpin.
        // This type can be safely declared as 'public', satisfying the privacy
        // checker without actually allowing user code to access it.
        //
        // This allows users to apply the #[pin_project] attribute to types
        // 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)*)?
        {
            __dummy_lifetime: $crate::__private::PhantomData<&'__pin ()>,
            $($field)*
        }
        impl <'__pin, $($impl_generics)*> $crate::__private::Unpin for $ident <$($ty_generics)*>
        where
            __Origin <'__pin, $($ty_generics)*>: $crate::__private::Unpin
            $(, $($where_clause)*)?
        {
        }
    };

    // =============================================================================================
    // make_drop_impl
    (@make_drop_impl;
        [$_ident:ident]
        [$($_impl_generics:tt)*] [$($_ty_generics:tt)*] [$(where $($_where_clause:tt)* )?]
        impl $(<
            $( $lifetime:lifetime $(: $lifetime_bound:lifetime)? ),* $(,)?
            $( $generics:ident
                $(: $generics_bound:path)?
                $(: ?$generics_unsized_bound:path)?
                $(: $generics_lifetime_bound:lifetime)?
            ),*
        >)? PinnedDrop for $self_ty:ty
        $(where
            $( $where_clause_ty:ty
                $(: $where_clause_bound:path)?
                $(: ?$where_clause_unsized_bound:path)?
                $(: $where_clause_lifetime_bound:lifetime)?
            ),* $(,)?
        )?
        {
            fn drop($($arg:ident)+: Pin<&mut Self>) {
                $($tt:tt)*
            }
        }
    ) => {
        impl $(<
            $( $lifetime $(: $lifetime_bound)? ,)*
            $( $generics
                $(: $generics_bound)?
                $(: ?$generics_unsized_bound)?
                $(: $generics_lifetime_bound)?
            ),*
        >)? $crate::__private::Drop for $self_ty
        $(where
            $( $where_clause_ty
                $(: $where_clause_bound)?
                $(: ?$where_clause_unsized_bound)?
                $(: $where_clause_lifetime_bound)?
            ),*
        )?
        {
            fn drop(&mut self) {
                // Implementing `__DropInner::__drop_inner` is safe, but calling it is not safe.
                // This is because destructors can be called multiple times in safe code and
                // [double dropping is unsound](https://github.com/rust-lang/rust/pull/62360).
                //
                // `__drop_inner` is defined as a safe method, but this is fine since
                // `__drop_inner` is not accessible by the users and we call `__drop_inner` only
                // once.
                //
                // Users can implement [`Drop`] safely using `pin_project!` and can drop a
                // type that implements `PinnedDrop` using the [`drop`] function safely.
                fn __drop_inner $(<
                    $( $lifetime $(: $lifetime_bound)? ,)*
                    $( $generics
                        $(: $generics_bound)?
                        $(: ?$generics_unsized_bound)?
                        $(: $generics_lifetime_bound)?
                    ),*
                >)? (
                    $($arg)+: $crate::__private::Pin<&mut $self_ty>,
                )
                $(where
                    $( $where_clause_ty
                        $(: $where_clause_bound)?
                        $(: ?$where_clause_unsized_bound)?
                        $(: $where_clause_lifetime_bound)?
                    ),*
                )?
                {
                    // A dummy `__drop_inner` function to prevent users call outer `__drop_inner`.
                    fn __drop_inner() {}
                    $($tt)*
                }

                // Safety - we're in 'drop', so we know that 'self' will
                // never move again.
                let pinned_self: $crate::__private::Pin<&mut Self>
                    = unsafe { $crate::__private::Pin::new_unchecked(self) };
                // We call `__drop_inner` only once. Since `__DropInner::__drop_inner`
                // is not accessible by the users, it is never called again.
                __drop_inner(pinned_self);
            }
        }
    };
    (@make_drop_impl;
        [$ident:ident]
        [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
    ) => {
        // Ensure that struct does not implement `Drop`.
        //
        // There are two possible cases:
        // 1. The user type does not implement Drop. In this case,
        // the first blanked impl will not apply to it. This code
        // will compile, as there is only one impl of MustNotImplDrop for the user type
        // 2. The user type does impl Drop. This will make the blanket impl applicable,
        // which will then conflict with the explicit MustNotImplDrop impl below.
        // This will result in a compilation error, which is exactly what we want.
        trait MustNotImplDrop {}
        #[allow(clippy::drop_bounds, drop_bounds)]
        impl<T: $crate::__private::Drop> MustNotImplDrop for T {}
        impl <$($impl_generics)*> MustNotImplDrop for $ident <$($ty_generics)*>
        $(where
            $($where_clause)*)?
        {
        }
    };

    // =============================================================================================
    // make_unpin_bound
    (@make_unpin_bound;
        #[pin]
        $field_ty:ty
    ) => {
        $field_ty
    };
    (@make_unpin_bound;
        $field_ty:ty
    ) => {
        $crate::__private::AlwaysUnpin<$field_ty>
    };

    // =============================================================================================
    // make_unsafe_field_proj
    (@make_unsafe_field_proj;
        #[pin]
        $field:ident
    ) => {
        $crate::__private::Pin::new_unchecked($field)
    };
    (@make_unsafe_field_proj;
        $field:ident
    ) => {
        $field
    };

    // =============================================================================================
    // make_replace_field_proj
    (@make_replace_field_proj;
        #[pin]
        $field:ident
    ) => {
        $crate::__private::PhantomData
    };
    (@make_replace_field_proj;
        $field:ident
    ) => {
        $crate::__private::ptr::read($field)
    };


    // =============================================================================================
    // make_unsafe_drop_in_place_guard
    (@make_unsafe_drop_in_place_guard;
        #[pin]
        $field:ident
    ) => {
        $crate::__private::UnsafeDropInPlaceGuard::new($field)
    };
    (@make_unsafe_drop_in_place_guard;
        $field:ident
    ) => {
        ()
    };

    // =============================================================================================
    // make_proj_field
    (@make_proj_field_mut;
        #[pin]
        $field_ty:ty
    ) => {
        $crate::__private::Pin<&'__pin mut ($field_ty)>
    };
    (@make_proj_field_mut;
        $field_ty:ty
    ) => {
        &'__pin mut ($field_ty)
    };
    (@make_proj_field_ref;
        #[pin]
        $field_ty:ty
    ) => {
        $crate::__private::Pin<&'__pin ($field_ty)>
    };
    (@make_proj_field_ref;
        $field_ty:ty
    ) => {
        &'__pin ($field_ty)
    };

    (@make_proj_field_replace;
        #[pin]
        $field_ty:ty
    ) => {
        $crate::__private::PhantomData<$field_ty>
    };
    (@make_proj_field_replace;
        $field_ty:ty
    ) => {
        $field_ty
    };

    // =============================================================================================
    // Parses attributes and determines visibility
    // parsing proj_mut_ident
    (
        []
        [$($proj_ref_ident:ident)?]
        [$($proj_replace_ident:ident)?]
        [$($attrs:tt)*]

        #[project = $proj_mut_ident:ident]
        $($tt:tt)*
    ) => {
        $crate::__pin_project_internal! {
            [$proj_mut_ident]
            [$($proj_ref_ident)?]
            [$($proj_replace_ident)?]
            [$($attrs)*]
            $($tt)*
        }
    };

    // parsing proj_ref_ident
    {
        [$($proj_mut_ident:ident)?]
        []
        [$($proj_replace_ident:ident)?]
        [$($attrs:tt)*]

        #[project_ref = $proj_ref_ident:ident]
        $($tt:tt)*
    } => {
        $crate::__pin_project_internal! {
            [$($proj_mut_ident)?]
            [$proj_ref_ident]
            [$($proj_replace_ident)?]
            [$($attrs)*]
            $($tt)*
        }
    };

    // parsing proj_replace_ident
    {
        [$($proj_mut_ident:ident)?]
        [$($proj_ref_ident:ident)?]
        []
        [$($attrs:tt)*]

        #[project_replace = $proj_replace_ident:ident]
        $($tt:tt)*
    } => {
        $crate::__pin_project_internal! {
            [$($proj_mut_ident)?]
            [$($proj_ref_ident)?]
            [$proj_replace_ident]
            [$($attrs)*]
            $($tt)*
        }
    };

    // this is actually part of a recursive step that picks off a single non-`pin_project_lite` attribute
    // there could be more to parse
    {
        [$($proj_mut_ident:ident)?]
        [$($proj_ref_ident:ident)?]
        [$($proj_replace_ident:ident)?]
        [$($attrs:tt)*]

        #[$($attr:tt)*]
        $($tt:tt)*
    } => {
        $crate::__pin_project_internal! {
            [$($proj_mut_ident)?]
            [$($proj_ref_ident)?]
            [$($proj_replace_ident)?]
            [$($attrs)* #[$($attr)*]]
            $($tt)*
        }
    };

    // now determine visibility
    // if public, downgrade
    {
        [$($proj_mut_ident:ident)?]
        [$($proj_ref_ident:ident)?]
        [$($proj_replace_ident:ident)?]
        [$($attrs:tt)*]
        pub $struct_ty_ident:ident $ident:ident
        $($tt:tt)*
    } => {
        $crate::__pin_project_internal! {
            [$($proj_mut_ident)?]
            [$($proj_ref_ident)?]
            [$($proj_replace_ident)?]
            [$($attrs)*]
            [pub $struct_ty_ident $ident pub(crate)]
            $($tt)*
        }
    };
    {
        [$($proj_mut_ident:ident)?]
        [$($proj_ref_ident:ident)?]
        [$($proj_replace_ident:ident)?]
        [$($attrs:tt)*]
        $vis:vis $struct_ty_ident:ident $ident:ident
        $($tt:tt)*
    } => {
        $crate::__pin_project_internal! {
            [$($proj_mut_ident)?]
            [$($proj_ref_ident)?]
            [$($proj_replace_ident)?]
            [$($attrs)*]
            [$vis $struct_ty_ident $ident $vis]
            $($tt)*
        }
    };
    // parse generics
    (
        [$($proj_mut_ident:ident)?]
        [$($proj_ref_ident:ident)?]
        [$($proj_replace_ident:ident)?]
        [$($attrs:tt)*]
        [$vis:vis $struct_ty_ident:ident $ident:ident $proj_ty_vis:vis]
        $(<
            $( $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)?
            ),* $(,)?
        )?
        {
            $($body_data:tt)*
        }
        $(impl $($pinned_drop:tt)*)?
    ) => {
        $crate::__pin_project_internal! { @expand;
            [$($proj_mut_ident)?]
            [$($proj_ref_ident)?]
            [$($proj_replace_ident)?]
            [$proj_ty_vis]
            [$($attrs)* $vis $struct_ty_ident $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)?
            ),* )?]
            {
                $($body_data)*
            }
            $(impl $($pinned_drop)*)?
        }
    };
}

// Not public API.
#[doc(hidden)]
pub mod __private {
    use core::mem::ManuallyDrop;
    #[doc(hidden)]
    pub use core::{
        marker::{PhantomData, Unpin},
        ops::Drop,
        pin::Pin,
        ptr,
    };

    // This is an internal helper struct used by `pin_project!`.
    #[doc(hidden)]
    pub struct AlwaysUnpin<T: ?Sized>(PhantomData<T>);

    impl<T: ?Sized> Unpin for AlwaysUnpin<T> {}

    // This is an internal helper used to ensure a value is dropped.
    #[doc(hidden)]
    pub struct UnsafeDropInPlaceGuard<T: ?Sized>(*mut T);

    impl<T: ?Sized> UnsafeDropInPlaceGuard<T> {
        #[doc(hidden)]
        pub unsafe fn new(ptr: *mut T) -> Self {
            Self(ptr)
        }
    }

    impl<T: ?Sized> Drop for UnsafeDropInPlaceGuard<T> {
        fn drop(&mut self) {
            unsafe {
                ptr::drop_in_place(self.0);
            }
        }
    }

    // This is an internal helper used to ensure a value is overwritten without
    // its destructor being called.
    #[doc(hidden)]
    pub struct UnsafeOverwriteGuard<T> {
        target: *mut T,
        value: ManuallyDrop<T>,
    }

    impl<T> UnsafeOverwriteGuard<T> {
        #[doc(hidden)]
        pub unsafe fn new(target: *mut T, value: T) -> Self {
            Self { target, value: ManuallyDrop::new(value) }
        }
    }

    impl<T> Drop for UnsafeOverwriteGuard<T> {
        fn drop(&mut self) {
            unsafe {
                ptr::write(self.target, ptr::read(&*self.value));
            }
        }
    }
}
