pin-project-internal-1.1.3/.cargo_vcs_info.json0000644000000001620000000000100151010ustar { "git": { "sha1": "55829b9ac3a24d25a2b188544943ce880cbfbe4e" }, "path_in_vcs": "pin-project-internal" }pin-project-internal-1.1.3/Cargo.toml0000644000000021520000000000100131000ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2021" rust-version = "1.56" name = "pin-project-internal" version = "1.1.3" description = """ Implementation detail of the `pin-project` crate. """ keywords = [ "pin", "macros", "attribute", ] categories = [ "no-std", "no-std::no-alloc", "rust-patterns", ] license = "Apache-2.0 OR MIT" repository = "https://github.com/taiki-e/pin-project" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] [lib] proc-macro = true [dependencies.proc-macro2] version = "1.0.60" [dependencies.quote] version = "1" [dependencies.syn] version = "2.0.1" features = [ "full", "visit-mut", ] [dev-dependencies] pin-project-internal-1.1.3/Cargo.toml.orig000064400000000000000000000011431046102023000165600ustar 00000000000000[package] name = "pin-project-internal" version = "1.1.3" edition = "2021" rust-version = "1.56" license = "Apache-2.0 OR MIT" repository = "https://github.com/taiki-e/pin-project" keywords = ["pin", "macros", "attribute"] categories = ["no-std", "no-std::no-alloc", "rust-patterns"] description = """ Implementation detail of the `pin-project` crate. """ [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] [lib] proc-macro = true [dependencies] proc-macro2 = "1.0.60" quote = "1" syn = { version = "2.0.1", features = ["full", "visit-mut"] } [dev-dependencies] pin-project = { path = ".." } pin-project-internal-1.1.3/LICENSE-APACHE000064400000000000000000000236761046102023000156340ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS pin-project-internal-1.1.3/LICENSE-MIT000064400000000000000000000017771046102023000153420ustar 00000000000000Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. pin-project-internal-1.1.3/src/lib.rs000064400000000000000000000442151046102023000156030ustar 00000000000000//! Implementation detail of the `pin-project` crate. - **do not use directly** #![doc(test( no_crate_inject, attr( deny(warnings, rust_2018_idioms, single_use_lifetimes), allow(dead_code, unused_variables) ) ))] #![forbid(unsafe_code)] #![warn(rust_2018_idioms, single_use_lifetimes, unreachable_pub)] #![warn(clippy::pedantic)] #![allow( clippy::needless_doctest_main, clippy::similar_names, clippy::single_match_else, clippy::too_many_lines )] // older compilers require explicit `extern crate`. #[allow(unused_extern_crates)] extern crate proc_macro; #[macro_use] mod utils; mod pin_project; mod pinned_drop; use proc_macro::TokenStream; /// An attribute that creates projection types covering all the fields of /// struct or enum. /// /// This attribute creates projection types according to the following rules: /// /// - For the fields that use `#[pin]` attribute, create the pinned reference to /// the field. /// - For the other fields, create a normal 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 argument with the same name as the method to the attribute, /// 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::pin_project; /// # use std::pin::Pin; /// #[pin_project(project = EnumProj)] /// enum Enum { /// Variant(#[pin] T), /// } /// /// impl Enum { /// fn method(self: Pin<&mut Self>) { /// let this: EnumProj<'_, T> = self.project(); /// match this { /// EnumProj::Variant(x) => { /// let _: Pin<&mut T> = x; /// } /// } /// } /// } /// ``` /// /// 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 /// /// This attribute is completely safe. In the absence of other `unsafe` code /// *that you write*, it is impossible to cause [undefined /// behavior][undefined-behavior] with this attribute. /// /// This is accomplished by enforcing the four requirements for pin projection /// stated in [the Rust documentation][pin-projection]: /// /// 1. The struct must only be [`Unpin`] if all the structural fields are /// [`Unpin`]. /// /// To enforce this, this attribute will automatically generate an [`Unpin`] /// implementation for you, which will require that all structurally pinned /// fields be [`Unpin`]. /// /// If you attempt to provide an [`Unpin`] impl, the blanket impl will then /// apply to your type, causing a compile-time error due to the conflict with /// the second impl. /// /// If you wish to provide a manual [`Unpin`] impl, you can do so via the /// [`UnsafeUnpin`][unsafe-unpin] argument. /// /// 2. The destructor of the struct must not move structural fields out of its /// argument. /// /// To enforce this, this attribute will generate code like this: /// /// ```rust /// struct MyStruct {} /// trait MyStructMustNotImplDrop {} /// # #[allow(unknown_lints, drop_bounds)] /// impl MyStructMustNotImplDrop for T {} /// impl MyStructMustNotImplDrop for MyStruct {} /// ``` /// /// If you attempt to provide an [`Drop`] impl, the blanket impl will then /// apply to your type, causing a compile-time error due to the conflict with /// the second impl. /// /// If you wish to provide a custom [`Drop`] impl, you can annotate an impl /// with [`#[pinned_drop]`][pinned-drop]. This impl takes a pinned version of /// your struct - that is, [`Pin`]`<&mut MyStruct>` where `MyStruct` is the /// type of your struct. /// /// You can call `.project()` on this type as usual, along with any other /// methods you have defined. Because your code is never provided with /// a `&mut MyStruct`, it is impossible to move out of pin-projectable /// fields in safe code in your destructor. /// /// 3. You must make sure that you uphold the [`Drop` /// guarantee][drop-guarantee]: once your struct is pinned, the memory that /// contains the content is not overwritten or deallocated without calling /// the content's destructors. /// /// Safe code doesn't need to worry about this - the only way to violate /// this requirement is to manually deallocate memory (which is `unsafe`), /// or to overwrite a field with something else. /// Because your custom destructor takes [`Pin`]`<&mut MyStruct>`, it's /// impossible to obtain a mutable reference to a pin-projected field in safe /// code. /// /// 4. You must not offer any other operations that could lead to data being /// moved out of the structural fields when your type is pinned. /// /// As with requirement 3, it is impossible for safe code to violate this. /// This crate ensures that safe code can never obtain a mutable reference to /// `#[pin]` fields, which prevents you from ever moving out of them in safe /// code. /// /// Pin projections are also incompatible with [`#[repr(packed)]`][repr-packed] /// types. Attempting to use this attribute on a `#[repr(packed)]` type results /// in a compile-time error. /// /// # Examples /// /// `#[pin_project]` can be used on structs and enums. /// /// ```rust /// use std::pin::Pin; /// /// use pin_project::pin_project; /// /// #[pin_project] /// struct Struct { /// #[pin] /// pinned: T, /// unpinned: U, /// } /// /// impl Struct { /// fn method(self: Pin<&mut Self>) { /// let this = self.project(); /// let _: Pin<&mut T> = this.pinned; /// let _: &mut U = this.unpinned; /// } /// } /// ``` /// /// ```rust /// use std::pin::Pin; /// /// use pin_project::pin_project; /// /// #[pin_project] /// struct TupleStruct(#[pin] T, U); /// /// impl TupleStruct { /// fn method(self: Pin<&mut Self>) { /// let this = self.project(); /// let _: Pin<&mut T> = this.0; /// let _: &mut U = this.1; /// } /// } /// ``` /// /// 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::pin_project; /// /// #[pin_project(project = EnumProj)] /// enum Enum { /// Tuple(#[pin] T), /// Struct { field: U }, /// Unit, /// } /// /// impl Enum { /// fn method(self: Pin<&mut Self>) { /// match self.project() { /// EnumProj::Tuple(x) => { /// let _: Pin<&mut T> = x; /// } /// EnumProj::Struct { field } => { /// let _: &mut U = field; /// } /// EnumProj::Unit => {} /// } /// } /// } /// ``` /// /// When `#[pin_project]` is used on enums, only named projection types and /// methods are generated because there is no way to access variants of /// projected types without naming it. /// For example, in the above example, only the `project` method is generated, /// and the `project_ref` method is not generated. /// (When `#[pin_project]` is used on structs, both methods are always generated.) /// /// ```rust,compile_fail,E0599 /// # use pin_project::pin_project; /// # use std::pin::Pin; /// # /// # #[pin_project(project = EnumProj)] /// # enum Enum { /// # Tuple(#[pin] T), /// # Struct { field: U }, /// # Unit, /// # } /// # /// impl Enum { /// fn call_project_ref(self: Pin<&Self>) { /// let _this = self.project_ref(); /// //~^ ERROR no method named `project_ref` found for struct `Pin<&Enum>` in the current scope /// } /// } /// ``` /// /// If you want to call `.project()` 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::pin_project; /// /// #[pin_project] /// struct Struct { /// #[pin] /// field: T, /// } /// /// impl Struct { /// 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 the `!Unpin` /// argument to `#[pin_project]`. /// /// ```rust /// use pin_project::pin_project; /// /// #[pin_project(!Unpin)] /// struct Struct { /// field: T, /// } /// ``` /// /// This is equivalent to using `#[pin]` attribute for the [`PhantomPinned`] /// field. /// /// ```rust /// use std::marker::PhantomPinned; /// /// use pin_project::pin_project; /// /// #[pin_project] /// struct Struct { /// field: T, /// #[pin] // <------ This `#[pin]` is required to make `Struct` to `!Unpin`. /// _pin: PhantomPinned, /// } /// ``` /// /// Note that using [`PhantomPinned`] without `#[pin]` attribute has no effect. /// /// # `UnsafeUnpin` /// /// If you want to implement [`Unpin`] manually, you must use the `UnsafeUnpin` /// argument to `#[pin_project]`. /// /// ```rust /// use pin_project::{pin_project, UnsafeUnpin}; /// /// #[pin_project(UnsafeUnpin)] /// struct Struct { /// #[pin] /// pinned: T, /// unpinned: U, /// } /// /// unsafe impl UnsafeUnpin for Struct {} /// ``` /// /// Note the usage of the unsafe [`UnsafeUnpin`] trait, instead of the usual /// [`Unpin`] trait. [`UnsafeUnpin`] behaves exactly like [`Unpin`], except that /// is unsafe to implement. This unsafety comes from the fact that pin /// projections are being used. If you implement [`UnsafeUnpin`], you must /// ensure that it is only implemented when all pin-projected fields implement /// [`Unpin`]. /// /// See [`UnsafeUnpin`] trait for more details. /// /// # `#[pinned_drop]` /// /// In order to correctly implement pin projections, a type's [`Drop`] impl must /// not move out of any structurally pinned fields. Unfortunately, /// [`Drop::drop`] takes `&mut Self`, not [`Pin`]`<&mut Self>`. /// /// To ensure that this requirement is upheld, the `#[pin_project]` attribute /// will provide a [`Drop`] impl for you. This [`Drop`] impl will delegate to /// an impl block annotated with `#[pinned_drop]` if you use the `PinnedDrop` /// argument to `#[pin_project]`. /// /// This impl block acts just like a normal [`Drop`] impl, /// except for the following two: /// /// - `drop` method takes [`Pin`]`<&mut Self>` /// - Name of the trait is `PinnedDrop`. /// /// ```rust /// # use std::pin::Pin; /// pub trait PinnedDrop { /// fn drop(self: Pin<&mut Self>); /// } /// ``` /// /// `#[pin_project]` implements the actual [`Drop`] trait via `PinnedDrop` you /// implemented. To drop a type that implements `PinnedDrop`, use the [`drop`] /// function just like dropping a type that directly implements [`Drop`]. /// /// In particular, it will never be called more than once, just like /// [`Drop::drop`]. /// /// For example: /// /// ```rust /// use std::{fmt::Debug, pin::Pin}; /// /// use pin_project::{pin_project, pinned_drop}; /// /// #[pin_project(PinnedDrop)] /// struct PrintOnDrop { /// #[pin] /// pinned_field: T, /// unpin_field: U, /// } /// /// #[pinned_drop] /// impl PinnedDrop for PrintOnDrop { /// fn drop(self: Pin<&mut Self>) { /// println!("Dropping pinned field: {:?}", self.pinned_field); /// println!("Dropping unpin field: {:?}", self.unpin_field); /// } /// } /// /// fn main() { /// let _x = PrintOnDrop { pinned_field: true, unpin_field: 40 }; /// } /// ``` /// /// See also [`#[pinned_drop]`][macro@pinned_drop] attribute. /// /// # `project_replace` method /// /// In addition to the `project` and `project_ref` methods which are always /// provided when you use the `#[pin_project]` attribute, there is a third /// method, `project_replace` which can be useful in some situations. It is /// equivalent to [`Pin::set`], except that the unpinned fields are moved and /// returned, instead of being dropped in-place. /// /// ```rust /// # use std::pin::Pin; /// # type ProjectionOwned = (); /// # trait Dox { /// fn project_replace(self: Pin<&mut Self>, other: Self) -> ProjectionOwned; /// # } /// ``` /// /// The `ProjectionOwned` type is identical to the `Self` type, except that /// all pinned fields have been replaced by equivalent [`PhantomData`] types. /// /// This method is opt-in, because it is only supported for [`Sized`] types, and /// because it is incompatible with the [`#[pinned_drop]`][pinned-drop] /// attribute described above. It can be enabled by using /// `#[pin_project(project_replace)]`. /// /// For example: /// /// ```rust /// use std::{marker::PhantomData, pin::Pin}; /// /// use pin_project::pin_project; /// /// #[pin_project(project_replace)] /// struct Struct { /// #[pin] /// pinned_field: T, /// unpinned_field: U, /// } /// /// impl Struct { /// fn method(self: Pin<&mut Self>, other: Self) { /// let this = self.project_replace(other); /// let _: U = this.unpinned_field; /// let _: PhantomData = this.pinned_field; /// } /// } /// ``` /// /// By passing the value to the `project_replace` argument, you can name the /// returned type of the `project_replace` method. This is necessary whenever /// destructuring the return type of the `project_replace` method, and work in exactly /// the same way as the `project` and `project_ref` arguments. /// /// ```rust /// use pin_project::pin_project; /// /// #[pin_project(project_replace = EnumProjOwn)] /// enum Enum { /// A { /// #[pin] /// pinned_field: T, /// unpinned_field: U, /// }, /// B, /// } /// /// let mut x = Box::pin(Enum::A { pinned_field: 42, unpinned_field: "hello" }); /// /// match x.as_mut().project_replace(Enum::B) { /// EnumProjOwn::A { unpinned_field, .. } => assert_eq!(unpinned_field, "hello"), /// EnumProjOwn::B => unreachable!(), /// } /// ``` /// /// [`PhantomData`]: core::marker::PhantomData /// [`PhantomPinned`]: core::marker::PhantomPinned /// [`Pin::as_mut`]: core::pin::Pin::as_mut /// [`Pin::set`]: core::pin::Pin::set /// [`Pin`]: core::pin::Pin /// [`UnsafeUnpin`]: https://docs.rs/pin-project/1/pin_project/trait.UnsafeUnpin.html /// [drop-guarantee]: core::pin#drop-guarantee /// [pin-projection]: core::pin#projections-and-structural-pinning /// [pinned-drop]: macro@pin_project#pinned_drop /// [repr-packed]: https://doc.rust-lang.org/nomicon/other-reprs.html#reprpacked /// [undefined-behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html /// [unsafe-unpin]: macro@pin_project#unsafeunpin #[proc_macro_attribute] pub fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream { pin_project::attribute(&args.into(), input.into()).into() } /// An attribute used for custom implementations of [`Drop`]. /// /// This attribute is used in conjunction with the `PinnedDrop` argument to /// the [`#[pin_project]`][macro@pin_project] attribute. /// /// The impl block annotated with this attribute acts just like a normal /// [`Drop`] impl, except for the following two: /// /// - `drop` method takes [`Pin`]`<&mut Self>` /// - Name of the trait is `PinnedDrop`. /// /// ```rust /// # use std::pin::Pin; /// pub trait PinnedDrop { /// fn drop(self: Pin<&mut Self>); /// } /// ``` /// /// `#[pin_project]` implements the actual [`Drop`] trait via `PinnedDrop` you /// implemented. To drop a type that implements `PinnedDrop`, use the [`drop`] /// function just like dropping a type that directly implements [`Drop`]. /// /// In particular, it will never be called more than once, just like /// [`Drop::drop`]. /// /// # Examples /// /// ```rust /// use std::pin::Pin; /// /// use pin_project::{pin_project, pinned_drop}; /// /// #[pin_project(PinnedDrop)] /// struct PrintOnDrop { /// #[pin] /// field: u8, /// } /// /// #[pinned_drop] /// impl PinnedDrop for PrintOnDrop { /// fn drop(self: Pin<&mut Self>) { /// println!("Dropping: {}", self.field); /// } /// } /// /// fn main() { /// let _x = PrintOnDrop { field: 50 }; /// } /// ``` /// /// See also ["pinned-drop" section of `#[pin_project]` attribute][pinned-drop]. /// /// # Why `#[pinned_drop]` attribute is needed? /// /// Implementing `PinnedDrop::drop` 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][rust-lang/rust#62360]. /// /// Ideally, it would be desirable to be able to forbid manual calls in /// the same way as [`Drop::drop`], but the library cannot do it. So, by using /// macros and replacing them with private traits like the following, /// this crate prevent users from calling `PinnedDrop::drop` in safe code. /// /// ```rust /// # use std::pin::Pin; /// pub trait PinnedDrop { /// unsafe fn drop(self: Pin<&mut Self>); /// } /// ``` /// /// This allows implementing [`Drop`] safely using `#[pinned_drop]`. /// Also by using the [`drop`] function just like dropping a type that directly /// implements [`Drop`], can drop safely a type that implements `PinnedDrop`. /// /// [rust-lang/rust#62360]: https://github.com/rust-lang/rust/pull/62360 /// [`Pin`]: core::pin::Pin /// [pinned-drop]: macro@pin_project#pinned_drop #[proc_macro_attribute] pub fn pinned_drop(args: TokenStream, input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input); pinned_drop::attribute(&args.into(), input).into() } // Not public API. #[doc(hidden)] #[proc_macro_derive(__PinProjectInternalDerive, attributes(pin))] pub fn __pin_project_internal_derive(input: TokenStream) -> TokenStream { pin_project::derive(input.into()).into() } pin-project-internal-1.1.3/src/pin_project/args.rs000064400000000000000000000214451046102023000203050ustar 00000000000000use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{ parse::{Parse, ParseStream}, spanned::Spanned, Attribute, Error, Ident, Result, Token, }; use super::PIN; use crate::utils::{ParseBufferExt, SliceExt}; pub(super) fn parse_args(attrs: &[Attribute]) -> Result { // `(__private())` -> `` struct Input(Option); impl Parse for Input { fn parse(input: ParseStream<'_>) -> Result { Ok(Self((|| { let private = input.parse::().ok()?; if private == "__private" { input.parenthesized().ok()?.parse::().ok() } else { None } })())) } } if let Some(attr) = attrs.find("pin_project") { bail!(attr, "duplicate #[pin_project] attribute"); } let mut attrs = attrs.iter().filter(|attr| attr.path().is_ident(PIN)); let prev = if let Some(attr) = attrs.next() { (attr, syn::parse2::(attr.meta.require_list()?.tokens.clone())?.0) } else { // This only fails if another macro removes `#[pin]`. bail!(TokenStream::new(), "#[pin_project] attribute has been removed"); }; if let Some(attr) = attrs.next() { let (prev_attr, prev_res) = &prev; // As the `#[pin]` attribute generated by `#[pin_project]` // has the same span as `#[pin_project]`, it is possible // that a useless error message will be generated. // So, use the span of `prev_attr` if it is not a valid attribute. let res = syn::parse2::(attr.meta.require_list()?.tokens.clone())?.0; let span = match (prev_res, res) { (Some(_), _) => attr, (None, _) => prev_attr, }; bail!(span, "duplicate #[pin] attribute"); } // This `unwrap` only fails if another macro removes `#[pin]` and inserts own `#[pin]`. syn::parse2(prev.1.unwrap()) } pub(super) struct Args { /// `PinnedDrop` argument. pub(super) pinned_drop: Option, /// `UnsafeUnpin` or `!Unpin` argument. pub(super) unpin_impl: UnpinImpl, /// `project = ` argument. pub(super) project: Option, /// `project_ref = ` argument. pub(super) project_ref: Option, /// `project_replace [= ]` argument. pub(super) project_replace: ProjReplace, } impl Parse for Args { fn parse(input: ParseStream<'_>) -> Result { mod kw { syn::custom_keyword!(Unpin); } /// Parses `= ` in ` = ` and returns value and span of name-value pair. fn parse_value( input: ParseStream<'_>, name: &Ident, has_prev: bool, ) -> Result<(Ident, TokenStream)> { if input.is_empty() { bail!(name, "expected `{0} = `, found `{0}`", name); } let eq_token: Token![=] = input.parse()?; if input.is_empty() { let span = quote!(#name #eq_token); bail!(span, "expected `{0} = `, found `{0} =`", name); } let value: Ident = input.parse()?; let span = quote!(#name #value); if has_prev { bail!(span, "duplicate `{}` argument", name); } Ok((value, span)) } let mut pinned_drop = None; let mut unsafe_unpin = None; let mut not_unpin = None; let mut project = None; let mut project_ref = None; let mut project_replace_value = None; let mut project_replace_span = None; while !input.is_empty() { if input.peek(Token![!]) { let bang: Token![!] = input.parse()?; if input.is_empty() { bail!(bang, "expected `!Unpin`, found `!`"); } let unpin: kw::Unpin = input.parse()?; let span = quote!(#bang #unpin); if not_unpin.replace(span.span()).is_some() { bail!(span, "duplicate `!Unpin` argument"); } } else { let token = input.parse::()?; match &*token.to_string() { "PinnedDrop" => { if pinned_drop.replace(token.span()).is_some() { bail!(token, "duplicate `PinnedDrop` argument"); } } "UnsafeUnpin" => { if unsafe_unpin.replace(token.span()).is_some() { bail!(token, "duplicate `UnsafeUnpin` argument"); } } "project" => { project = Some(parse_value(input, &token, project.is_some())?.0); } "project_ref" => { project_ref = Some(parse_value(input, &token, project_ref.is_some())?.0); } "project_replace" => { if input.peek(Token![=]) { let (value, span) = parse_value(input, &token, project_replace_span.is_some())?; project_replace_value = Some(value); project_replace_span = Some(span.span()); } else if project_replace_span.is_some() { bail!(token, "duplicate `project_replace` argument"); } else { project_replace_span = Some(token.span()); } } "Replace" => { bail!( token, "`Replace` argument was removed, use `project_replace` argument instead" ); } _ => bail!(token, "unexpected argument: {}", token), } } if input.is_empty() { break; } let _: Token![,] = input.parse()?; } if project.is_some() || project_ref.is_some() { if project == project_ref { bail!( project_ref, "name `{}` is already specified by `project` argument", project_ref.as_ref().unwrap() ); } if let Some(ident) = &project_replace_value { if project == project_replace_value { bail!(ident, "name `{}` is already specified by `project` argument", ident); } else if project_ref == project_replace_value { bail!(ident, "name `{}` is already specified by `project_ref` argument", ident); } } } if let Some(span) = pinned_drop { if project_replace_span.is_some() { return Err(Error::new( span, "arguments `PinnedDrop` and `project_replace` are mutually exclusive", )); } } let project_replace = match (project_replace_span, project_replace_value) { (None, _) => ProjReplace::None, (Some(span), Some(ident)) => ProjReplace::Named { ident, span }, (Some(span), None) => ProjReplace::Unnamed { span }, }; let unpin_impl = match (unsafe_unpin, not_unpin) { (None, None) => UnpinImpl::Default, (Some(span), None) => UnpinImpl::Unsafe(span), (None, Some(span)) => UnpinImpl::Negative(span), (Some(span), Some(_)) => { return Err(Error::new( span, "arguments `UnsafeUnpin` and `!Unpin` are mutually exclusive", )); } }; Ok(Self { pinned_drop, unpin_impl, project, project_ref, project_replace }) } } /// `UnsafeUnpin` or `!Unpin` argument. #[derive(Clone, Copy)] pub(super) enum UnpinImpl { Default, /// `UnsafeUnpin`. Unsafe(Span), /// `!Unpin`. Negative(Span), } /// `project_replace [= ]` argument. pub(super) enum ProjReplace { None, /// `project_replace`. Unnamed { span: Span, }, /// `project_replace = `. Named { span: Span, ident: Ident, }, } impl ProjReplace { /// Return the span of this argument. pub(super) fn span(&self) -> Option { match self { Self::None => None, Self::Named { span, .. } | Self::Unnamed { span, .. } => Some(*span), } } pub(super) fn ident(&self) -> Option<&Ident> { if let Self::Named { ident, .. } = self { Some(ident) } else { None } } } pin-project-internal-1.1.3/src/pin_project/attribute.rs000064400000000000000000000047341046102023000213560ustar 00000000000000use proc_macro2::TokenStream; use quote::quote; use syn::{ parse::{Parse, ParseStream}, Attribute, Result, Token, Visibility, }; use super::PIN; use crate::utils::SliceExt; // To generate the correct `Unpin` implementation and the projection methods, // we need to collect the types of the pinned fields. // However, since proc-macro-attribute is applied before `cfg` and `cfg_attr` // on fields, we cannot be collecting field types properly at this timing. // So instead of generating the `Unpin` implementation and the projection // methods here, delegate their processing to proc-macro-derive. // // At this stage, only attributes are parsed and the following attributes are // added to the attributes of the item. // - `#[derive(InternalDerive)]` - An internal helper macro that does the above // processing. // - `#[pin(__private(#args))]` - Pass the argument of `#[pin_project]` to // proc-macro-derive (`InternalDerive`). pub(super) fn parse_attribute(args: &TokenStream, input: TokenStream) -> Result { let Input { attrs, body } = syn::parse2(input)?; Ok(quote! { #(#attrs)* #[derive(::pin_project::__private::__PinProjectInternalDerive)] // Use `__private` to prevent users from trying to control `InternalDerive` // manually. `__private` does not guarantee compatibility between patch // versions, so it should be sufficient for this purpose in most cases. #[pin(__private(#args))] #body }) } struct Input { attrs: Vec, body: TokenStream, } impl Parse for Input { fn parse(input: ParseStream<'_>) -> Result { let attrs = input.call(Attribute::parse_outer)?; let ahead = input.fork(); let _vis: Visibility = ahead.parse()?; if !ahead.peek(Token![struct]) && !ahead.peek(Token![enum]) { // If we check this only on proc-macro-derive, it may generate unhelpful error // messages. So it is preferable to be able to detect it here. bail!( input.parse::()?, "#[pin_project] attribute may only be used on structs or enums" ); } else if let Some(attr) = attrs.find(PIN) { bail!(attr, "#[pin] attribute may only be used on fields of structs or variants"); } else if let Some(attr) = attrs.find("pin_project") { bail!(attr, "duplicate #[pin_project] attribute"); } Ok(Self { attrs, body: input.parse()? }) } } pin-project-internal-1.1.3/src/pin_project/derive.rs000064400000000000000000001247261046102023000206350ustar 00000000000000use proc_macro2::{Delimiter, Group, Span, TokenStream}; use quote::{format_ident, quote, quote_spanned, ToTokens}; use syn::{ parse_quote, punctuated::Punctuated, token, visit_mut::VisitMut, Attribute, Data, DataEnum, DeriveInput, Error, Field, Fields, FieldsNamed, FieldsUnnamed, Generics, Ident, Index, Lifetime, LifetimeParam, Meta, Result, Token, Type, Variant, Visibility, WhereClause, }; use super::{ args::{parse_args, Args, ProjReplace, UnpinImpl}, PIN, }; use crate::utils::{ determine_lifetime_name, determine_visibility, insert_lifetime_and_bound, ReplaceReceiver, SliceExt, Variants, }; pub(super) fn parse_derive(input: TokenStream) -> Result { let mut input: DeriveInput = syn::parse2(input)?; let mut cx; let mut generate = GenerateTokens::default(); let ident = &input.ident; let ty_generics = input.generics.split_for_impl().1; let self_ty = parse_quote!(#ident #ty_generics); let mut visitor = ReplaceReceiver(&self_ty); visitor.visit_generics_mut(&mut input.generics); visitor.visit_data_mut(&mut input.data); match &input.data { Data::Struct(data) => { cx = Context::new(&input.attrs, &input.vis, ident, &mut input.generics, Struct)?; parse_struct(&mut cx, &data.fields, &mut generate)?; } Data::Enum(data) => { cx = Context::new(&input.attrs, &input.vis, ident, &mut input.generics, Enum)?; parse_enum(&mut cx, data, &mut generate)?; } Data::Union(_) => { bail!(input, "#[pin_project] attribute may only be used on structs or enums"); } } Ok(generate.into_tokens(&cx)) } #[derive(Default)] struct GenerateTokens { exposed: TokenStream, scoped: TokenStream, } impl GenerateTokens { fn extend(&mut self, expose: bool, tokens: TokenStream) { if expose { self.exposed.extend(tokens); } else { self.scoped.extend(tokens); } } fn into_tokens(self, cx: &Context<'_>) -> TokenStream { let mut tokens = self.exposed; let scoped = self.scoped; let unpin_impl = make_unpin_impl(cx); let drop_impl = make_drop_impl(cx); let allowed_lints = global_allowed_lints(); tokens.extend(quote! { // All items except projected types are generated inside a `const` scope. // This makes it impossible for user code to refer to these types. // However, this prevents Rustdoc from displaying docs for any // of our types. In particular, users cannot see the // automatically generated `Unpin` impl for the '__UnpinStruct' types // // Previously, we provided a flag to correctly document the // automatically generated `Unpin` impl by using def-site hygiene, // but it is now removed. // // Refs: // - https://github.com/rust-lang/rust/issues/63281 // - https://github.com/taiki-e/pin-project/pull/53#issuecomment-525906867 // - https://github.com/taiki-e/pin-project/pull/70 #allowed_lints #[allow(unused_qualifications)] #[allow(clippy::semicolon_if_nothing_returned)] #[allow(clippy::use_self)] #[allow(clippy::used_underscore_binding)] const _: () = { #[allow(unused_extern_crates)] extern crate pin_project as _pin_project; #scoped #unpin_impl #drop_impl }; }); tokens } } /// Returns attributes that should be applied to all generated code. fn global_allowed_lints() -> TokenStream { quote! { #[allow(box_pointers)] // This lint warns use of the `Box` type. #[allow(deprecated)] #[allow(explicit_outlives_requirements)] // https://github.com/rust-lang/rust/issues/60993 #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 #[allow(unreachable_pub)] // This lint warns `pub` field in private struct. #[allow(unused_tuple_struct_fields)] // 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::pattern_type_mismatch)] #[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 } } /// Returns attributes used on projected types. fn proj_allowed_lints(cx: &Context<'_>) -> (TokenStream, TokenStream, TokenStream) { let large_enum_variant = if cx.kind == Enum { Some(quote! { #[allow(variant_size_differences)] #[allow(clippy::large_enum_variant)] }) } else { None }; let global_allowed_lints = global_allowed_lints(); let proj_mut_allowed_lints = if cx.project { Some(&global_allowed_lints) } else { None }; let proj_mut = quote! { #proj_mut_allowed_lints #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. }; let proj_ref_allowed_lints = if cx.project_ref { Some(&global_allowed_lints) } else { None }; let proj_ref = quote! { #proj_ref_allowed_lints #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(clippy::ref_option_ref)] // This lint warns `&Option<&>`. }; let proj_own_allowed_lints = if cx.project_replace.ident().is_some() { Some(&global_allowed_lints) } else { None }; let proj_own = quote! { #proj_own_allowed_lints #[allow(dead_code)] // This lint warns unused fields/variants. #large_enum_variant }; (proj_mut, proj_ref, proj_own) } struct Context<'a> { /// The original type. orig: OriginalType<'a>, /// The projected types. proj: ProjectedType, /// Types of the pinned fields. pinned_fields: Vec<&'a Type>, /// Kind of the original type: struct or enum kind: TypeKind, /// `PinnedDrop` argument. pinned_drop: Option, /// `UnsafeUnpin` or `!Unpin` argument. unpin_impl: UnpinImpl, /// `project` argument. project: bool, /// `project_ref` argument. project_ref: bool, /// `project_replace [= ]` argument. project_replace: ProjReplace, } impl<'a> Context<'a> { fn new( attrs: &'a [Attribute], vis: &'a Visibility, ident: &'a Ident, generics: &'a mut Generics, kind: TypeKind, ) -> Result { let Args { pinned_drop, unpin_impl, project, project_ref, project_replace } = parse_args(attrs)?; if let Some(name) = [project.as_ref(), project_ref.as_ref(), project_replace.ident()] .iter() .filter_map(Option::as_ref) .find(|name| **name == ident) { bail!(name, "name `{}` is the same as the original type name", name); } let mut lifetime_name = String::from("'pin"); determine_lifetime_name(&mut lifetime_name, generics); let lifetime = Lifetime::new(&lifetime_name, Span::call_site()); let ty_generics = generics.split_for_impl().1; let ty_generics_as_generics = parse_quote!(#ty_generics); let mut proj_generics = generics.clone(); let pred = insert_lifetime_and_bound( &mut proj_generics, lifetime.clone(), &ty_generics_as_generics, ident, ); let mut where_clause = generics.make_where_clause().clone(); where_clause.predicates.push(pred); let own_ident = project_replace .ident() .cloned() .unwrap_or_else(|| format_ident!("__{}ProjectionOwned", ident)); Ok(Self { kind, pinned_drop, unpin_impl, project: project.is_some(), project_ref: project_ref.is_some(), project_replace, proj: ProjectedType { vis: determine_visibility(vis), mut_ident: project.unwrap_or_else(|| format_ident!("__{}Projection", ident)), ref_ident: project_ref.unwrap_or_else(|| format_ident!("__{}ProjectionRef", ident)), own_ident, lifetime, generics: proj_generics, where_clause, }, orig: OriginalType { attrs, vis, ident, generics }, pinned_fields: Vec::new(), }) } } #[derive(Copy, Clone, PartialEq)] enum TypeKind { Enum, Struct, } use TypeKind::{Enum, Struct}; struct OriginalType<'a> { /// Attributes of the original type. attrs: &'a [Attribute], /// Visibility of the original type. vis: &'a Visibility, /// Name of the original type. ident: &'a Ident, /// Generics of the original type. generics: &'a Generics, } struct ProjectedType { /// Visibility of the projected types. vis: Visibility, /// Name of the projected type returned by `project` method. mut_ident: Ident, /// Name of the projected type returned by `project_ref` method. ref_ident: Ident, /// Name of the projected type returned by `project_replace` method. own_ident: Ident, /// Lifetime on the generated projected types. lifetime: Lifetime, /// Generics of the projected types. generics: Generics, /// `where` clause of the projected types. This has an additional /// bound generated by `insert_lifetime_and_bound` where_clause: WhereClause, } struct ProjectedVariants { proj_variants: TokenStream, proj_ref_variants: TokenStream, proj_own_variants: TokenStream, proj_arms: TokenStream, proj_ref_arms: TokenStream, proj_own_arms: TokenStream, } #[derive(Default)] struct ProjectedFields { proj_pat: TokenStream, proj_body: TokenStream, proj_own_body: TokenStream, proj_fields: TokenStream, proj_ref_fields: TokenStream, proj_own_fields: TokenStream, } fn validate_struct(ident: &Ident, fields: &Fields) -> Result<()> { if fields.is_empty() { let msg = "#[pin_project] attribute may not be used on structs with zero fields"; if let Fields::Unit = fields { bail!(ident, msg) } bail!(fields, msg) } Ok(()) } fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> { if variants.is_empty() { return Err(Error::new( brace_token.span.join(), "#[pin_project] attribute may not be used on enums without variants", )); } let has_field = variants.iter().try_fold(false, |has_field, v| { if let Some((_, e)) = &v.discriminant { bail!(e, "#[pin_project] attribute may not be used on enums with discriminants"); } else if let Some(attr) = v.attrs.find(PIN) { bail!(attr, "#[pin] attribute may only be used on fields of structs or variants"); } else if v.fields.is_empty() { Ok(has_field) } else { Ok(true) } })?; if has_field { Ok(()) } else { bail!(variants, "#[pin_project] attribute may not be used on enums with zero fields"); } } fn parse_struct<'a>( cx: &mut Context<'a>, fields: &'a Fields, generate: &mut GenerateTokens, ) -> Result<()> { // Do this first for a better error message. let packed_check = ensure_not_packed(&cx.orig, Some(fields))?; validate_struct(cx.orig.ident, fields)?; let ProjectedFields { proj_pat, proj_body, proj_fields, proj_ref_fields, proj_own_fields, proj_own_body, } = match fields { Fields::Named(_) => visit_fields(cx, None, fields, Delimiter::Brace)?, Fields::Unnamed(_) => visit_fields(cx, None, fields, Delimiter::Parenthesis)?, Fields::Unit => unreachable!(), }; let proj_ident = &cx.proj.mut_ident; let proj_ref_ident = &cx.proj.ref_ident; let proj_own_ident = &cx.proj.own_ident; let vis = &cx.proj.vis; let mut orig_generics = cx.orig.generics.clone(); let orig_where_clause = orig_generics.where_clause.take(); let proj_generics = &cx.proj.generics; let proj_where_clause = &cx.proj.where_clause; // For tuple structs, we need to generate `(T1, T2) where Foo: Bar` // For non-tuple structs, we need to generate `where Foo: Bar { field1: T }` let (where_clause_fields, where_clause_ref_fields, where_clause_own_fields) = match fields { Fields::Named(_) => ( quote!(#proj_where_clause #proj_fields), quote!(#proj_where_clause #proj_ref_fields), quote!(#orig_where_clause #proj_own_fields), ), Fields::Unnamed(_) => ( quote!(#proj_fields #proj_where_clause;), quote!(#proj_ref_fields #proj_where_clause;), quote!(#proj_own_fields #orig_where_clause;), ), Fields::Unit => unreachable!(), }; let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx); generate.extend(cx.project, quote! { #proj_attrs #vis struct #proj_ident #proj_generics #where_clause_fields }); generate.extend(cx.project_ref, quote! { #proj_ref_attrs #vis struct #proj_ref_ident #proj_generics #where_clause_ref_fields }); if cx.project_replace.span().is_some() { generate.extend(cx.project_replace.ident().is_some(), quote! { #proj_own_attrs #vis struct #proj_own_ident #orig_generics #where_clause_own_fields }); } let proj_mut_body = quote! { let Self #proj_pat = self.get_unchecked_mut(); #proj_ident #proj_body }; let proj_ref_body = quote! { let Self #proj_pat = self.get_ref(); #proj_ref_ident #proj_body }; let proj_own_body = quote! { let Self #proj_pat = &mut *__self_ptr; #proj_own_body }; generate.extend(false, make_proj_impl(cx, &proj_mut_body, &proj_ref_body, &proj_own_body)); generate.extend(false, packed_check); Ok(()) } fn parse_enum<'a>( cx: &mut Context<'a>, DataEnum { brace_token, variants, .. }: &'a DataEnum, generate: &mut GenerateTokens, ) -> Result<()> { if let ProjReplace::Unnamed { span } = &cx.project_replace { return Err(Error::new( *span, "`project_replace` argument requires a value when used on enums", )); } // #[repr(packed)] cannot be apply on enums and will be rejected by rustc. // However, we should not rely on the behavior of rustc that rejects this. // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001 // // Do this first for a better error message. ensure_not_packed(&cx.orig, None)?; validate_enum(*brace_token, variants)?; let ProjectedVariants { proj_variants, proj_ref_variants, proj_own_variants, proj_arms, proj_ref_arms, proj_own_arms, } = visit_variants(cx, variants)?; let proj_ident = &cx.proj.mut_ident; let proj_ref_ident = &cx.proj.ref_ident; let proj_own_ident = &cx.proj.own_ident; let vis = &cx.proj.vis; let mut orig_generics = cx.orig.generics.clone(); let orig_where_clause = orig_generics.where_clause.take(); let proj_generics = &cx.proj.generics; let proj_where_clause = &cx.proj.where_clause; let (proj_attrs, proj_ref_attrs, proj_own_attrs) = proj_allowed_lints(cx); if cx.project { generate.extend(true, quote! { #proj_attrs #vis enum #proj_ident #proj_generics #proj_where_clause { #proj_variants } }); } if cx.project_ref { generate.extend(true, quote! { #proj_ref_attrs #vis enum #proj_ref_ident #proj_generics #proj_where_clause { #proj_ref_variants } }); } if cx.project_replace.ident().is_some() { generate.extend(true, quote! { #proj_own_attrs #vis enum #proj_own_ident #orig_generics #orig_where_clause { #proj_own_variants } }); } let proj_mut_body = quote! { match self.get_unchecked_mut() { #proj_arms } }; let proj_ref_body = quote! { match self.get_ref() { #proj_ref_arms } }; let proj_own_body = quote! { match &mut *__self_ptr { #proj_own_arms } }; generate.extend(false, make_proj_impl(cx, &proj_mut_body, &proj_ref_body, &proj_own_body)); Ok(()) } fn visit_variants<'a>(cx: &mut Context<'a>, variants: &'a Variants) -> Result { let mut proj_variants = TokenStream::new(); let mut proj_ref_variants = TokenStream::new(); let mut proj_own_variants = TokenStream::new(); let mut proj_arms = TokenStream::new(); let mut proj_ref_arms = TokenStream::new(); let mut proj_own_arms = TokenStream::new(); for Variant { ident, fields, .. } in variants { let ProjectedFields { proj_pat, proj_body, proj_fields, proj_ref_fields, proj_own_fields, proj_own_body, } = match fields { Fields::Named(_) => visit_fields(cx, Some(ident), fields, Delimiter::Brace)?, Fields::Unnamed(_) => visit_fields(cx, Some(ident), fields, Delimiter::Parenthesis)?, Fields::Unit => ProjectedFields { proj_own_body: proj_own_body(cx, Some(ident), None, &[]), ..Default::default() }, }; let proj_ident = &cx.proj.mut_ident; let proj_ref_ident = &cx.proj.ref_ident; proj_variants.extend(quote! { #ident #proj_fields, }); proj_ref_variants.extend(quote! { #ident #proj_ref_fields, }); proj_own_variants.extend(quote! { #ident #proj_own_fields, }); proj_arms.extend(quote! { Self::#ident #proj_pat => #proj_ident::#ident #proj_body, }); proj_ref_arms.extend(quote! { Self::#ident #proj_pat => #proj_ref_ident::#ident #proj_body, }); proj_own_arms.extend(quote! { Self::#ident #proj_pat => { #proj_own_body } }); } Ok(ProjectedVariants { proj_variants, proj_ref_variants, proj_own_variants, proj_arms, proj_ref_arms, proj_own_arms, }) } fn visit_fields<'a>( cx: &mut Context<'a>, variant_ident: Option<&Ident>, fields: &'a Fields, delim: Delimiter, ) -> Result { fn surround(delim: Delimiter, tokens: TokenStream) -> TokenStream { Group::new(delim, tokens).into_token_stream() } let mut proj_pat = TokenStream::new(); let mut proj_body = TokenStream::new(); let mut proj_fields = TokenStream::new(); let mut proj_ref_fields = TokenStream::new(); let mut proj_own_fields = TokenStream::new(); let mut proj_move = TokenStream::new(); let mut pinned_bindings = Vec::with_capacity(fields.len()); for (i, Field { attrs, vis, ident, colon_token, ty, mutability: _ }) in fields.iter().enumerate() { let binding = ident.clone().unwrap_or_else(|| format_ident!("_{}", i)); proj_pat.extend(quote!(#binding,)); let lifetime = &cx.proj.lifetime; if attrs.position_exact(PIN)?.is_some() { proj_fields.extend(quote! { #vis #ident #colon_token ::pin_project::__private::Pin<&#lifetime mut (#ty)>, }); proj_ref_fields.extend(quote! { #vis #ident #colon_token ::pin_project::__private::Pin<&#lifetime (#ty)>, }); proj_own_fields.extend(quote! { #vis #ident #colon_token ::pin_project::__private::PhantomData<#ty>, }); proj_body.extend(quote! { #ident #colon_token _pin_project::__private::Pin::new_unchecked(#binding), }); proj_move.extend(quote! { #ident #colon_token _pin_project::__private::PhantomData, }); cx.pinned_fields.push(ty); pinned_bindings.push(binding); } else { proj_fields.extend(quote! { #vis #ident #colon_token &#lifetime mut (#ty), }); proj_ref_fields.extend(quote! { #vis #ident #colon_token &#lifetime (#ty), }); proj_own_fields.extend(quote! { #vis #ident #colon_token #ty, }); proj_body.extend(quote! { #binding, }); proj_move.extend(quote! { #ident #colon_token _pin_project::__private::ptr::read(#binding), }); } } let proj_pat = surround(delim, proj_pat); let proj_body = surround(delim, proj_body); let proj_fields = surround(delim, proj_fields); let proj_ref_fields = surround(delim, proj_ref_fields); let proj_own_fields = surround(delim, proj_own_fields); let proj_move = Group::new(delim, proj_move); let proj_own_body = proj_own_body(cx, variant_ident, Some(&proj_move), &pinned_bindings); Ok(ProjectedFields { proj_pat, proj_body, proj_own_body, proj_fields, proj_ref_fields, proj_own_fields, }) } /// Generates the processing that `project_replace` does for the struct or each variant. /// /// Note: `pinned_fields` must be in declaration order. fn proj_own_body( cx: &Context<'_>, variant_ident: Option<&Ident>, proj_move: Option<&Group>, pinned_fields: &[Ident], ) -> TokenStream { let ident = &cx.proj.own_ident; let proj_own = match variant_ident { Some(variant_ident) => quote!(#ident::#variant_ident), None => quote!(#ident), }; // The fields of the struct and the active enum variant are dropped // in declaration order. // Refs: https://doc.rust-lang.org/reference/destructors.html let pinned_fields = pinned_fields.iter().rev(); quote! { // First, extract all the unpinned fields. let __result = #proj_own #proj_move; // Now create guards to drop all the pinned fields. // // Due to a compiler bug (https://github.com/rust-lang/rust/issues/47949) // this must be in its own scope, or else `__result` will not be dropped // if any of the destructors panic. { #( let __guard = _pin_project::__private::UnsafeDropInPlaceGuard::new(#pinned_fields); )* } // Finally, return the result. __result } } /// Creates `Unpin` implementation for the original type. /// /// The kind of `Unpin` impl generated depends on `unpin_impl` field: /// - `UnpinImpl::Unsafe` - Implements `Unpin` via `UnsafeUnpin` impl. /// - `UnpinImpl::Negative` - Generates `Unpin` impl with bounds that will never be true. /// - `UnpinImpl::Default` - Generates `Unpin` impl that requires `Unpin` for all pinned fields. fn make_unpin_impl(cx: &Context<'_>) -> TokenStream { match cx.unpin_impl { UnpinImpl::Unsafe(span) => { let mut proj_generics = cx.proj.generics.clone(); let orig_ident = cx.orig.ident; let lifetime = &cx.proj.lifetime; // Make the error message highlight `UnsafeUnpin` argument. proj_generics.make_where_clause().predicates.push(parse_quote_spanned! { span => _pin_project::__private::Wrapper<#lifetime, Self>: _pin_project::UnsafeUnpin }); let (impl_generics, _, where_clause) = proj_generics.split_for_impl(); let ty_generics = cx.orig.generics.split_for_impl().1; quote_spanned! { span => impl #impl_generics _pin_project::__private::Unpin for #orig_ident #ty_generics #where_clause { } } } UnpinImpl::Negative(span) => { let mut proj_generics = cx.proj.generics.clone(); let orig_ident = cx.orig.ident; let lifetime = &cx.proj.lifetime; proj_generics.make_where_clause().predicates.push(parse_quote! { _pin_project::__private::Wrapper< #lifetime, _pin_project::__private::PhantomPinned >: _pin_project::__private::Unpin }); let (proj_impl_generics, _, proj_where_clause) = proj_generics.split_for_impl(); let ty_generics = cx.orig.generics.split_for_impl().1; // For interoperability with `forbid(unsafe_code)`, `unsafe` token should be // call-site span. let unsafety = ::default(); quote_spanned! { span => #[doc(hidden)] impl #proj_impl_generics _pin_project::__private::Unpin for #orig_ident #ty_generics #proj_where_clause { } // Generate a dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it. // // To ensure that users don't accidentally write a non-functional `UnsafeUnpin` // impls, we emit one ourselves. If the user ends up writing an `UnsafeUnpin` // impl, they'll get a "conflicting implementations of trait" error when // coherence checks are run. #[doc(hidden)] #unsafety impl #proj_impl_generics _pin_project::UnsafeUnpin for #orig_ident #ty_generics #proj_where_clause { } } } UnpinImpl::Default => { let mut full_where_clause = cx.orig.generics.where_clause.clone().unwrap(); // Generate a field in our new struct for every // pinned field in the original type. let fields = cx.pinned_fields.iter().enumerate().map(|(i, ty)| { let field_ident = format_ident!("__field{}", i); quote!(#field_ident: #ty) }); // We could try to determine the subset of type parameters // and lifetimes that are actually used by the pinned fields // (as opposed to those only used by unpinned fields). // However, this would be tricky and error-prone, since // it's possible for users to create types that would alias // with generic parameters (e.g. 'struct T'). // // Instead, we generate a use of every single type parameter // and lifetime used in the original struct. For type parameters, // we generate code like this: // // ```rust // struct AlwaysUnpin(PhantomData) {} // impl Unpin for AlwaysUnpin {} // // ... // _field: AlwaysUnpin<(A, B, C)> // ``` // // This ensures that any unused type parameters // don't end up with `Unpin` bounds. let lifetime_fields = cx.orig.generics.lifetimes().enumerate().map( |(i, LifetimeParam { lifetime, .. })| { let field_ident = format_ident!("__lifetime{}", i); quote!(#field_ident: &#lifetime ()) }, ); let orig_ident = cx.orig.ident; let struct_ident = format_ident!("__{}", orig_ident); let vis = cx.orig.vis; let lifetime = &cx.proj.lifetime; let type_params = cx.orig.generics.type_params().map(|t| &t.ident); let proj_generics = &cx.proj.generics; let (proj_impl_generics, proj_ty_generics, _) = proj_generics.split_for_impl(); let (_, ty_generics, where_clause) = cx.orig.generics.split_for_impl(); full_where_clause.predicates.push(parse_quote! { #struct_ident #proj_ty_generics: _pin_project::__private::Unpin }); quote! { // This needs to have the same visibility as the original type, // due to the limitations of the 'public in private' error. // // Our goal is to implement the public trait `Unpin` for // a potentially public user type. Because of this, rust // requires that any types mentioned in the where clause of // our `Unpin` impl also be public. This means that our generated // `__UnpinStruct` type must also be public. // However, we ensure that the user can never actually reference // this 'public' type by creating this type in the inside of `const`. #[allow(missing_debug_implementations)] #vis struct #struct_ident #proj_generics #where_clause { __pin_project_use_generics: _pin_project::__private::AlwaysUnpin< #lifetime, (#(_pin_project::__private::PhantomData<#type_params>),*) >, #(#fields,)* #(#lifetime_fields,)* } impl #proj_impl_generics _pin_project::__private::Unpin for #orig_ident #ty_generics #full_where_clause { } // Generate a dummy impl of `UnsafeUnpin`, to ensure that the user cannot implement it. // // To ensure that users don't accidentally write a non-functional `UnsafeUnpin` // impls, we emit one ourselves. If the user ends up writing an `UnsafeUnpin` // impl, they'll get a "conflicting implementations of trait" error when // coherence checks are run. #[doc(hidden)] unsafe impl #proj_impl_generics _pin_project::UnsafeUnpin for #orig_ident #ty_generics #full_where_clause { } } } } } /// Creates `Drop` implementation for the original type. /// /// The kind of `Drop` impl generated depends on `pinned_drop` field: /// - `Some` - implements `Drop` via `PinnedDrop` impl. /// - `None` - generates code that ensures that `Drop` trait is not implemented, /// instead of generating `Drop` impl. fn make_drop_impl(cx: &Context<'_>) -> TokenStream { let ident = cx.orig.ident; let (impl_generics, ty_generics, where_clause) = cx.orig.generics.split_for_impl(); if let Some(span) = cx.pinned_drop { // For interoperability with `forbid(unsafe_code)`, `unsafe` token should be // call-site span. let unsafety = ::default(); quote_spanned! { span => impl #impl_generics _pin_project::__private::Drop for #ident #ty_generics #where_clause { fn drop(&mut self) { #unsafety { // Safety - we're in 'drop', so we know that 'self' will // never move again. let __pinned_self = _pin_project::__private::Pin::new_unchecked(self); // We call `pinned_drop` only once. Since `PinnedDrop::drop` // is an unsafe method and a private API, it is never called again in safe // code *unless the user uses a maliciously crafted macro*. _pin_project::__private::PinnedDrop::drop(__pinned_self); } } } } } else { // If the user does not provide a `PinnedDrop` impl, // we need to ensure that they don't provide a `Drop` impl of their // own. // Based on https://github.com/upsuper/assert-impl/blob/f503255b292ab0ba8d085b657f4065403cfa46eb/src/lib.rs#L80-L87 // // We create a new identifier for each struct, so that the traits // for different types do not conflict with each other. // // Another approach would be to provide an empty Drop impl, // which would conflict with a user-provided Drop impl. // However, this would trigger the compiler's special handling // of Drop types (e.g. fields cannot be moved out of a Drop type). // This approach prevents the creation of needless Drop impls, // giving users more flexibility. let trait_ident = format_ident!("{}MustNotImplDrop", ident); quote! { // 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 #trait_ident {} #[allow(clippy::drop_bounds, drop_bounds)] impl #trait_ident for T {} impl #impl_generics #trait_ident for #ident #ty_generics #where_clause {} // Generate a dummy impl of `PinnedDrop`, to ensure that the user cannot implement it. // Since the user did not pass `PinnedDrop` to `#[pin_project]`, any `PinnedDrop` // impl will not actually be called. Unfortunately, we can't detect this situation // directly from either the `#[pin_project]` or `#[pinned_drop]` attributes, since // we don't know what other attributes/impl may exist. // // To ensure that users don't accidentally write a non-functional `PinnedDrop` // impls, we emit one ourselves. If the user ends up writing a `PinnedDrop` impl, // they'll get a "conflicting implementations of trait" error when coherence // checks are run. #[doc(hidden)] impl #impl_generics _pin_project::__private::PinnedDrop for #ident #ty_generics #where_clause { unsafe fn drop(self: _pin_project::__private::Pin<&mut Self>) {} } } } } /// Creates an implementation of the projection methods. /// /// On structs, both the `project` and `project_ref` methods are always generated, /// and the `project_replace` method is only generated if `ProjReplace::span` is `Some`. /// /// On enums, only methods that the returned projected type is named will be generated. fn make_proj_impl( cx: &Context<'_>, proj_body: &TokenStream, proj_ref_body: &TokenStream, proj_own_body: &TokenStream, ) -> TokenStream { let vis = &cx.proj.vis; let lifetime = &cx.proj.lifetime; let orig_ident = cx.orig.ident; let proj_ident = &cx.proj.mut_ident; let proj_ref_ident = &cx.proj.ref_ident; let proj_own_ident = &cx.proj.own_ident; let orig_ty_generics = cx.orig.generics.split_for_impl().1; let proj_ty_generics = cx.proj.generics.split_for_impl().1; let (impl_generics, ty_generics, where_clause) = cx.orig.generics.split_for_impl(); // TODO: For enums and project_replace, dead_code warnings should not be // allowed because methods are not generated unless explicitly specified. // However, there is currently no good way to allow warnings for generated // code, so we allow warnings for all methods for now. let allow_dead_code = quote! { #[allow(dead_code)] }; let mut project = Some(quote! { #allow_dead_code #[inline] #vis fn project<#lifetime>( self: _pin_project::__private::Pin<&#lifetime mut Self>, ) -> #proj_ident #proj_ty_generics { unsafe { #proj_body } } }); let mut project_ref = Some(quote! { #allow_dead_code #[allow(clippy::missing_const_for_fn)] #[inline] #vis fn project_ref<#lifetime>( self: _pin_project::__private::Pin<&#lifetime Self>, ) -> #proj_ref_ident #proj_ty_generics { unsafe { #proj_ref_body } } }); let mut project_replace = cx.project_replace.span().map(|span| { // It is enough to only set the span of the signature. let sig = quote_spanned! { span => #allow_dead_code #[inline] #vis fn project_replace( self: _pin_project::__private::Pin<&mut Self>, __replacement: Self, ) -> #proj_own_ident #orig_ty_generics }; quote! { #sig { 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 = _pin_project::__private::UnsafeOverwriteGuard::new( __self_ptr, __replacement, ); #proj_own_body } } } }); if cx.kind == Enum { if !cx.project { project = None; } if !cx.project_ref { project_ref = None; } if cx.project_replace.ident().is_none() { project_replace = None; } } quote! { impl #impl_generics #orig_ident #ty_generics #where_clause { #project #project_ref #project_replace } } } /// Checks that the `[repr(packed)]` attribute is not included. /// /// This currently does two checks: /// - Checks the attributes of structs to ensure there is no `[repr(packed)]`. /// - Generates a function that borrows fields without an unsafe block and /// forbidding `unaligned_references` lint. fn ensure_not_packed(orig: &OriginalType<'_>, fields: Option<&Fields>) -> Result { for attr in orig.attrs { if let Meta::List(ref list) = attr.meta { if list.path.is_ident("repr") { for repr in list.parse_args_with(Punctuated::::parse_terminated)? { if repr.path().is_ident("packed") { let msg = if fields.is_none() { // #[repr(packed)] cannot be apply on enums and will be rejected by rustc. // However, we should not rely on the behavior of rustc that rejects this. // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001 "#[repr(packed)] attribute should be applied to a struct or union" } else if repr.require_name_value().is_ok() { // #[repr(packed = "")] is not valid format of #[repr(packed)] and will be // rejected by rustc. // However, we should not rely on the behavior of rustc that rejects this. // https://github.com/taiki-e/pin-project/pull/324#discussion_r612388001 "#[repr(packed)] attribute should not be name-value pair" } else { "#[pin_project] attribute may not be used on #[repr(packed)] types" }; bail!(repr, msg); } } } } } let fields = match fields { Some(fields) => fields, None => return Ok(TokenStream::new()), }; // Workaround for https://github.com/taiki-e/pin-project/issues/32 // Through the tricky use of proc macros, it's possible to bypass // the above check for the `repr` attribute. // To ensure that it's impossible to use pin projections on a `#[repr(packed)]` // struct, we generate code like this: // // ```rust // #[forbid(unaligned_references)] // fn assert_not_repr_packed(val: &MyStruct) { // let _field_1 = &val.field_1; // let _field_2 = &val.field_2; // ... // let _field_n = &val.field_n; // } // ``` // // 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. // // There is one exception: If the type of a struct field has an alignment of 1 // (e.g. u8), it is always safe to take a reference to it, even if the struct // is `#[repr(packed)]`. If the struct is composed entirely of types of // alignment 1, our generated method will not trigger an error if the // struct is `#[repr(packed)]`. // // Fortunately, this should have no observable consequence - `#[repr(packed)]` // is essentially a no-op on such a type. Nevertheless, we include a test // to ensure that the compiler doesn't ever try to copy the fields on // such a struct when trying to drop it - which is reason we prevent // `#[repr(packed)]` in the first place. // // See also https://github.com/taiki-e/pin-project/pull/34. // // 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 let mut field_refs = vec![]; match fields { Fields::Named(FieldsNamed { named, .. }) => { for Field { ident, .. } in named { field_refs.push(quote!(&this.#ident)); } } Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => { for (index, _) in unnamed.iter().enumerate() { let index = Index::from(index); field_refs.push(quote!(&this.#index)); } } Fields::Unit => {} } let (impl_generics, ty_generics, where_clause) = orig.generics.split_for_impl(); let ident = orig.ident; Ok(quote! { #[forbid(unaligned_references, safe_packed_borrows)] fn __assert_not_repr_packed #impl_generics (this: &#ident #ty_generics) #where_clause { #(let _ = #field_refs;)* } }) } pin-project-internal-1.1.3/src/pin_project/mod.rs000064400000000000000000000007031046102023000201220ustar 00000000000000mod args; mod attribute; mod derive; use proc_macro2::TokenStream; use syn::Error; /// The annotation for pinned type. const PIN: &str = "pin"; pub(crate) fn attribute(args: &TokenStream, input: TokenStream) -> TokenStream { attribute::parse_attribute(args, input).unwrap_or_else(Error::into_compile_error) } pub(crate) fn derive(input: TokenStream) -> TokenStream { derive::parse_derive(input).unwrap_or_else(Error::into_compile_error) } pin-project-internal-1.1.3/src/pinned_drop.rs000064400000000000000000000204051046102023000173310ustar 00000000000000use proc_macro2::TokenStream; use quote::{format_ident, quote, ToTokens}; use syn::{ parse_quote, spanned::Spanned, token::Colon, visit_mut::VisitMut, Error, FnArg, GenericArgument, Ident, ImplItem, ItemImpl, Pat, PatIdent, PatType, Path, PathArguments, Result, ReturnType, Signature, Token, Type, TypePath, TypeReference, }; use crate::utils::{ReplaceReceiver, SliceExt}; pub(crate) fn attribute(args: &TokenStream, mut input: ItemImpl) -> TokenStream { let res = (|| -> Result<()> { if !args.is_empty() { bail!(args, "unexpected argument: `{}`", args) } validate_impl(&input)?; expand_impl(&mut input); Ok(()) })(); if let Err(e) = res { let mut tokens = e.to_compile_error(); if let Type::Path(self_ty) = &*input.self_ty { let (impl_generics, _, where_clause) = input.generics.split_for_impl(); // Generate a dummy impl of `PinnedDrop`. // In many cases, `#[pinned_drop] impl` is declared after `#[pin_project]`. // Therefore, if `pinned_drop` compile fails, you will also get an error // about `PinnedDrop` not being implemented. // This can be prevented to some extent by generating a dummy // `PinnedDrop` implementation. // We already know that we will get a compile error, so this won't // accidentally compile successfully. // // However, if `input.self_ty` is not Type::Path, there is a high possibility that // the type does not exist (since #[pin_project] can only be used on struct/enum // definitions), so do not generate a dummy impl. tokens.extend(quote! { impl #impl_generics ::pin_project::__private::PinnedDrop for #self_ty #where_clause { unsafe fn drop(self: ::pin_project::__private::Pin<&mut Self>) {} } }); } tokens } else { input.into_token_stream() } } /// Validates the signature of given `PinnedDrop` impl. fn validate_impl(item: &ItemImpl) -> Result<()> { const INVALID_ITEM: &str = "#[pinned_drop] may only be used on implementation for the `PinnedDrop` trait"; if let Some(attr) = item.attrs.find("pinned_drop") { bail!(attr, "duplicate #[pinned_drop] attribute"); } if let Some((_, path, _)) = &item.trait_ { if !path.is_ident("PinnedDrop") { bail!(path, INVALID_ITEM); } } else { bail!(item.self_ty, INVALID_ITEM); } if item.unsafety.is_some() { bail!(item.unsafety, "implementing the trait `PinnedDrop` is not unsafe"); } if item.items.is_empty() { bail!(item, "not all trait items implemented, missing: `drop`"); } match &*item.self_ty { Type::Path(_) => {} ty => { bail!(ty, "implementing the trait `PinnedDrop` on this type is unsupported"); } } item.items.iter().enumerate().try_for_each(|(i, item)| match item { ImplItem::Const(item) => { bail!(item, "const `{}` is not a member of trait `PinnedDrop`", item.ident) } ImplItem::Type(item) => { bail!(item, "type `{}` is not a member of trait `PinnedDrop`", item.ident) } ImplItem::Fn(method) => { validate_sig(&method.sig)?; if i == 0 { Ok(()) } else { bail!(method, "duplicate definitions with name `drop`") } } _ => unreachable!("unexpected ImplItem"), }) } /// Validates the signature of given `PinnedDrop::drop` method. /// /// The correct signature is: `(mut) self: (::)Pin<&mut Self>` fn validate_sig(sig: &Signature) -> Result<()> { fn get_ty_path(ty: &Type) -> Option<&Path> { if let Type::Path(TypePath { qself: None, path }) = ty { Some(path) } else { None } } const INVALID_ARGUMENT: &str = "method `drop` must take an argument `self: Pin<&mut Self>`"; if sig.ident != "drop" { bail!(sig.ident, "method `{}` is not a member of trait `PinnedDrop", sig.ident,); } if let ReturnType::Type(_, ty) = &sig.output { match &**ty { Type::Tuple(ty) if ty.elems.is_empty() => {} _ => bail!(ty, "method `drop` must return the unit type"), } } match sig.inputs.len() { 1 => {} 0 => return Err(Error::new(sig.paren_token.span.join(), INVALID_ARGUMENT)), _ => bail!(sig.inputs, INVALID_ARGUMENT), } if let Some(arg) = sig.receiver() { // (mut) self: if let Some(path) = get_ty_path(&arg.ty) { let ty = path.segments.last().expect("Type paths should always have at least one segment"); if let PathArguments::AngleBracketed(args) = &ty.arguments { // (mut) self: (::)<&mut ..> if let Some(GenericArgument::Type(Type::Reference(TypeReference { mutability: Some(_), elem, .. }))) = args.args.first() { // (mut) self: (::)Pin<&mut Self> if args.args.len() == 1 && ty.ident == "Pin" && get_ty_path(elem).map_or(false, |path| path.is_ident("Self")) { if sig.unsafety.is_some() { bail!(sig.unsafety, "implementing the method `drop` is not unsafe"); } return Ok(()); } } } } } bail!(sig.inputs[0], INVALID_ARGUMENT) } // from: // // fn drop(self: Pin<&mut Self>) { // // ... // } // // into: // // unsafe fn drop(self: Pin<&mut Self>) { // fn __drop_inner(__self: Pin<&mut Foo<'_, T>>) { // fn __drop_inner() {} // // ... // } // __drop_inner(self); // } // fn expand_impl(item: &mut ItemImpl) { // `PinnedDrop` is a private trait and should not appear in docs. item.attrs.push(parse_quote!(#[doc(hidden)])); let path = &mut item.trait_.as_mut().expect("unexpected inherent impl").1; *path = parse_quote_spanned! { path.span() => ::pin_project::__private::PinnedDrop }; let method = if let ImplItem::Fn(method) = &mut item.items[0] { method } else { unreachable!() }; // `fn drop(mut self: Pin<&mut Self>)` -> `fn __drop_inner(mut __self: Pin<&mut Receiver>)` let drop_inner = { let mut drop_inner = method.clone(); let ident = format_ident!("__drop_inner"); // Add a dummy `__drop_inner` function to prevent users call outer `__drop_inner`. drop_inner.block.stmts.insert(0, parse_quote!(fn #ident() {})); drop_inner.sig.ident = ident; drop_inner.sig.generics = item.generics.clone(); let receiver = drop_inner.sig.receiver().expect("drop() should have a receiver").clone(); let pat = Box::new(Pat::Ident(PatIdent { attrs: Vec::new(), by_ref: None, mutability: receiver.mutability, ident: Ident::new("__self", receiver.self_token.span()), subpat: None, })); drop_inner.sig.inputs[0] = FnArg::Typed(PatType { attrs: receiver.attrs, pat, colon_token: Colon::default(), ty: receiver.ty, }); let self_ty = if let Type::Path(ty) = &*item.self_ty { ty } else { unreachable!() }; let mut visitor = ReplaceReceiver(self_ty); visitor.visit_signature_mut(&mut drop_inner.sig); visitor.visit_block_mut(&mut drop_inner.block); drop_inner }; // `fn drop(mut self: Pin<&mut Self>)` -> `unsafe fn drop(self: Pin<&mut Self>)` method.sig.unsafety = Some(::default()); let self_token = if let FnArg::Receiver(ref mut rec) = method.sig.inputs[0] { rec.mutability = None; &rec.self_token } else { panic!("drop() should have a receiver") }; method.block.stmts = parse_quote! { #[allow(clippy::needless_pass_by_value)] // This lint does not warn the receiver. #drop_inner __drop_inner(#self_token); }; } pin-project-internal-1.1.3/src/utils.rs000064400000000000000000000313431046102023000161730ustar 00000000000000use std::mem; use proc_macro2::{Group, Spacing, Span, TokenStream, TokenTree}; use quote::{quote, quote_spanned, ToTokens}; use syn::{ parse::{Parse, ParseBuffer, ParseStream}, parse_quote, punctuated::Punctuated, token, visit_mut::{self, VisitMut}, Attribute, ExprPath, ExprStruct, Generics, Ident, Item, Lifetime, LifetimeParam, Macro, PatStruct, PatTupleStruct, Path, PathArguments, PredicateType, QSelf, Result, Token, Type, TypeParamBound, TypePath, Variant, Visibility, WherePredicate, }; pub(crate) type Variants = Punctuated; macro_rules! format_err { ($span:expr, $msg:expr $(,)?) => { syn::Error::new_spanned(&$span as &dyn quote::ToTokens, &$msg as &dyn std::fmt::Display) }; ($span:expr, $($tt:tt)*) => { format_err!($span, format!($($tt)*)) }; } macro_rules! bail { ($($tt:tt)*) => { return Err(format_err!($($tt)*)) }; } macro_rules! parse_quote_spanned { ($span:expr => $($tt:tt)*) => { syn::parse2(quote::quote_spanned!($span => $($tt)*)).unwrap_or_else(|e| panic!("{}", e)) }; } /// Determines the lifetime names. Ensure it doesn't overlap with any existing /// lifetime names. pub(crate) fn determine_lifetime_name(lifetime_name: &mut String, generics: &mut Generics) { struct CollectLifetimes(Vec); impl VisitMut for CollectLifetimes { fn visit_lifetime_param_mut(&mut self, def: &mut LifetimeParam) { self.0.push(def.lifetime.to_string()); } } debug_assert!(lifetime_name.starts_with('\'')); let mut lifetimes = CollectLifetimes(Vec::new()); lifetimes.visit_generics_mut(generics); while lifetimes.0.iter().any(|name| name.starts_with(&**lifetime_name)) { lifetime_name.push('_'); } } /// Like `insert_lifetime`, but also generates a bound of the form /// `OriginalType: 'lifetime`. Used when generating the definition /// of a projection type pub(crate) fn insert_lifetime_and_bound( generics: &mut Generics, lifetime: Lifetime, orig_generics: &Generics, orig_ident: &Ident, ) -> WherePredicate { insert_lifetime(generics, lifetime.clone()); let orig_type: Type = parse_quote!(#orig_ident #orig_generics); let mut punct = Punctuated::new(); punct.push(TypeParamBound::Lifetime(lifetime)); WherePredicate::Type(PredicateType { lifetimes: None, bounded_ty: orig_type, colon_token: ::default(), bounds: punct, }) } /// Inserts a `lifetime` at position `0` of `generics.params`. pub(crate) fn insert_lifetime(generics: &mut Generics, lifetime: Lifetime) { generics.lt_token.get_or_insert_with(::default); generics.gt_token.get_or_insert_with(]>::default); generics.params.insert(0, LifetimeParam::new(lifetime).into()); } /// Determines the visibility of the projected types and projection methods. /// /// If given visibility is `pub`, returned visibility is `pub(crate)`. /// Otherwise, returned visibility is the same as given visibility. pub(crate) fn determine_visibility(vis: &Visibility) -> Visibility { if let Visibility::Public(token) = vis { parse_quote_spanned!(token.span => pub(crate)) } else { vis.clone() } } pub(crate) fn respan(node: &T, span: Span) -> T where T: ToTokens + Parse, { let tokens = node.to_token_stream(); let respanned = respan_tokens(tokens, span); syn::parse2(respanned).unwrap() } fn respan_tokens(tokens: TokenStream, span: Span) -> TokenStream { tokens .into_iter() .map(|mut token| { token.set_span(span); token }) .collect() } // ================================================================================================= // extension traits pub(crate) trait SliceExt { fn position_exact(&self, ident: &str) -> Result>; fn find(&self, ident: &str) -> Option<&Attribute>; } impl SliceExt for [Attribute] { /// # Errors /// /// - There are multiple specified attributes. /// - The `Attribute::tokens` field of the specified attribute is not empty. fn position_exact(&self, ident: &str) -> Result> { self.iter() .try_fold((0, None), |(i, mut prev), attr| { if attr.path().is_ident(ident) { if prev.replace(i).is_some() { bail!(attr, "duplicate #[{}] attribute", ident); } attr.meta.require_path_only()?; } Ok((i + 1, prev)) }) .map(|(_, pos)| pos) } fn find(&self, ident: &str) -> Option<&Attribute> { self.iter().position(|attr| attr.path().is_ident(ident)).map(|i| &self[i]) } } pub(crate) trait ParseBufferExt<'a> { fn parenthesized(self) -> Result>; } impl<'a> ParseBufferExt<'a> for ParseStream<'a> { fn parenthesized(self) -> Result> { let content; let _: token::Paren = syn::parenthesized!(content in self); Ok(content) } } impl<'a> ParseBufferExt<'a> for ParseBuffer<'a> { fn parenthesized(self) -> Result> { let content; let _: token::Paren = syn::parenthesized!(content in self); Ok(content) } } // ================================================================================================= // visitors // Replace `self`/`Self` with `__self`/`self_ty`. // Based on: // - https://github.com/dtolnay/async-trait/blob/0.1.35/src/receiver.rs // - https://github.com/dtolnay/async-trait/commit/6029cbf375c562ca98fa5748e9d950a8ff93b0e7 pub(crate) struct ReplaceReceiver<'a>(pub(crate) &'a TypePath); impl ReplaceReceiver<'_> { fn self_ty(&self, span: Span) -> TypePath { respan(self.0, span) } fn self_to_qself(&self, qself: &mut Option, path: &mut Path) { if path.leading_colon.is_some() { return; } let first = &path.segments[0]; if first.ident != "Self" || !first.arguments.is_empty() { return; } if path.segments.len() == 1 { self.self_to_expr_path(path); return; } let span = first.ident.span(); *qself = Some(QSelf { lt_token: Token![<](span), ty: Box::new(self.self_ty(span).into()), position: 0, as_token: None, gt_token: Token![>](span), }); path.leading_colon = Some(**path.segments.pairs().next().unwrap().punct().unwrap()); let segments = mem::replace(&mut path.segments, Punctuated::new()); path.segments = segments.into_pairs().skip(1).collect(); } fn self_to_expr_path(&self, path: &mut Path) { if path.leading_colon.is_some() { return; } let first = &path.segments[0]; if first.ident != "Self" || !first.arguments.is_empty() { return; } let self_ty = self.self_ty(first.ident.span()); let variant = mem::replace(path, self_ty.path); for segment in &mut path.segments { if let PathArguments::AngleBracketed(bracketed) = &mut segment.arguments { if bracketed.colon2_token.is_none() && !bracketed.args.is_empty() { bracketed.colon2_token = Some(::default()); } } } if variant.segments.len() > 1 { path.segments.push_punct(::default()); path.segments.extend(variant.segments.into_pairs().skip(1)); } } fn visit_token_stream(&self, tokens: &mut TokenStream) -> bool { let mut out = Vec::new(); let mut modified = false; let mut iter = tokens.clone().into_iter().peekable(); while let Some(tt) = iter.next() { match tt { TokenTree::Ident(mut ident) => { modified |= prepend_underscore_to_self(&mut ident); if ident == "Self" { modified = true; let self_ty = self.self_ty(ident.span()); match iter.peek() { Some(TokenTree::Punct(p)) if p.as_char() == ':' && p.spacing() == Spacing::Joint => { let next = iter.next().unwrap(); match iter.peek() { Some(TokenTree::Punct(p)) if p.as_char() == ':' => { let span = ident.span(); out.extend(quote_spanned!(span=> <#self_ty>)); } _ => out.extend(quote!(#self_ty)), } out.push(next); } _ => out.extend(quote!(#self_ty)), } } else { out.push(TokenTree::Ident(ident)); } } TokenTree::Group(group) => { let mut content = group.stream(); modified |= self.visit_token_stream(&mut content); let mut new = Group::new(group.delimiter(), content); new.set_span(group.span()); out.push(TokenTree::Group(new)); } other => out.push(other), } } if modified { *tokens = TokenStream::from_iter(out); } modified } } impl VisitMut for ReplaceReceiver<'_> { // `Self` -> `Receiver` fn visit_type_mut(&mut self, ty: &mut Type) { if let Type::Path(node) = ty { if node.qself.is_none() && node.path.is_ident("Self") { *ty = self.self_ty(node.path.segments[0].ident.span()).into(); } else { self.visit_type_path_mut(node); } } else { visit_mut::visit_type_mut(self, ty); } } // `Self::Assoc` -> `::Assoc` fn visit_type_path_mut(&mut self, ty: &mut TypePath) { if ty.qself.is_none() { self.self_to_qself(&mut ty.qself, &mut ty.path); } visit_mut::visit_type_path_mut(self, ty); } // `Self::method` -> `::method` fn visit_expr_path_mut(&mut self, expr: &mut ExprPath) { if expr.qself.is_none() { self.self_to_qself(&mut expr.qself, &mut expr.path); } visit_mut::visit_expr_path_mut(self, expr); } fn visit_expr_struct_mut(&mut self, expr: &mut ExprStruct) { self.self_to_expr_path(&mut expr.path); visit_mut::visit_expr_struct_mut(self, expr); } fn visit_pat_struct_mut(&mut self, pat: &mut PatStruct) { self.self_to_expr_path(&mut pat.path); visit_mut::visit_pat_struct_mut(self, pat); } fn visit_pat_tuple_struct_mut(&mut self, pat: &mut PatTupleStruct) { self.self_to_expr_path(&mut pat.path); visit_mut::visit_pat_tuple_struct_mut(self, pat); } fn visit_path_mut(&mut self, path: &mut Path) { if path.segments.len() == 1 { // Replace `self`, but not `self::function`. prepend_underscore_to_self(&mut path.segments[0].ident); } for segment in &mut path.segments { self.visit_path_arguments_mut(&mut segment.arguments); } } fn visit_item_mut(&mut self, item: &mut Item) { match item { // Visit `macro_rules!` because locally defined macros can refer to `self`. Item::Macro(item) if item.mac.path.is_ident("macro_rules") => { self.visit_macro_mut(&mut item.mac); } // Otherwise, do not recurse into nested items. _ => {} } } fn visit_macro_mut(&mut self, mac: &mut Macro) { // We can't tell in general whether `self` inside a macro invocation // refers to the self in the argument list or a different self // introduced within the macro. Heuristic: if the macro input contains // `fn`, then `self` is more likely to refer to something other than the // outer function's self argument. if !contains_fn(mac.tokens.clone()) { self.visit_token_stream(&mut mac.tokens); } } } fn contains_fn(tokens: TokenStream) -> bool { tokens.into_iter().any(|tt| match tt { TokenTree::Ident(ident) => ident == "fn", TokenTree::Group(group) => contains_fn(group.stream()), _ => false, }) } pub(crate) fn prepend_underscore_to_self(ident: &mut Ident) -> bool { let modified = ident == "self"; if modified { *ident = Ident::new("__self", ident.span()); } modified }