pin-project-internal-0.4.8/Cargo.toml.orig010064400007650000024000000011501361355302600166760ustar0000000000000000[package] name = "pin-project-internal" version = "0.4.8" authors = ["Taiki Endo "] edition = "2018" license = "Apache-2.0 OR MIT" repository = "https://github.com/taiki-e/pin-project" homepage = "https://github.com/taiki-e/pin-project" documentation = "https://docs.rs/pin-project-internal" keywords = ["pin", "macros", "attribute"] categories = ["no-std", "rust-patterns"] description = """ An internal crate to support pin_project - do not use directly """ [lib] proc-macro = true [dependencies] proc-macro2 = "1.0" quote = "1.0" syn = { version = "1.0", features = ["full", "visit-mut"] } pin-project-internal-0.4.8/Cargo.toml0000644000000022301361355305700132120ustar00# 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 believe there's an error in this file please file an # issue against the rust-lang/cargo repository. If you're # editing this file be aware that the upstream Cargo.toml # will likely look very different (and much more reasonable) [package] edition = "2018" name = "pin-project-internal" version = "0.4.8" authors = ["Taiki Endo "] description = "An internal crate to support pin_project - do not use directly\n" homepage = "https://github.com/taiki-e/pin-project" documentation = "https://docs.rs/pin-project-internal" keywords = ["pin", "macros", "attribute"] categories = ["no-std", "rust-patterns"] license = "Apache-2.0 OR MIT" repository = "https://github.com/taiki-e/pin-project" [lib] proc-macro = true [dependencies.proc-macro2] version = "1.0" [dependencies.quote] version = "1.0" [dependencies.syn] version = "1.0" features = ["full", "visit-mut"] pin-project-internal-0.4.8/LICENSE-APACHE010064400007650000024000000261361356530430100157420ustar0000000000000000 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 APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. pin-project-internal-0.4.8/LICENSE-MIT010064400007650000024000000017771356530430100154560ustar0000000000000000Permission 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-0.4.8/src/lib.rs010064400007650000024000000417171361355232600157310ustar0000000000000000//! An internal crate to support pin_project - **do not use directly** #![recursion_limit = "256"] #![doc(html_root_url = "https://docs.rs/pin-project-internal/0.4.8")] #![doc(test( no_crate_inject, attr(deny(warnings, rust_2018_idioms, single_use_lifetimes), allow(dead_code)) ))] #![warn(unsafe_code)] #![warn(rust_2018_idioms, single_use_lifetimes, unreachable_pub)] #![warn(clippy::all)] // mem::take requires Rust 1.40 #![allow(clippy::mem_replace_with_default)] #![allow(clippy::needless_doctest_main)] // While this crate supports stable Rust, it currently requires // nightly Rust in order for rustdoc to correctly document auto-generated // `Unpin` impls. This does not affect the runtime functionality of this crate, // nor does it affect the safety of the api provided by this crate. // // This is disabled by default and can be enabled using // `--cfg pin_project_show_unpin_struct` in RUSTFLAGS. // // Refs: // * https://github.com/taiki-e/pin-project/pull/53#issuecomment-525906867 // * https://github.com/taiki-e/pin-project/pull/70 // * https://github.com/rust-lang/rust/issues/63281 #![cfg_attr(pin_project_show_unpin_struct, feature(proc_macro_def_site))] // older compilers require explicit `extern crate`. #[allow(unused_extern_crates)] extern crate proc_macro; #[macro_use] mod utils; mod pin_project; mod pinned_drop; mod project; use proc_macro::TokenStream; use utils::{Immutable, Mutable}; /// An attribute that creates a projection struct covering all the fields. /// /// This attribute creates a projection struct 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. /// /// The following methods are implemented on the original `#[pin_project]` type: /// /// ``` /// # #[rustversion::since(1.36)] /// # fn dox() { /// # 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<'_>; /// # } /// # } /// ``` /// /// The visibility of the projected type and projection method is based on the /// original type. However, if the visibility of the original type is `pub`, /// the visibility of the projected type and the projection method is `pub(crate)`. /// /// 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`. /// /// ## Safety /// /// This attribute is completely safe. In the absence of other `unsafe` code *that you write*, /// it is impossible to cause undefined behavior with this attribute. /// /// This is accomplished by enforcing the four requirements for pin projection /// stated in [the Rust documentation](https://doc.rust-lang.org/nightly/std/pin/index.html#projections-and-structural-pinning): /// /// 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 wish to provide an manual `Unpin` impl, you can do so via the /// `UnsafeUnpin` 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 {} /// 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 a function /// with `#[pinned_drop]`. This function 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: 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 wait 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)]` structs. Attempting to use this attribute /// on a `#[repr(packed)]` struct results in a compile-time error. /// /// /// ## Examples /// /// Using `#[pin_project]` will automatically create the appropriate /// conditional [`Unpin`] implementation: /// /// ```rust /// use pin_project::pin_project; /// use std::pin::Pin; /// /// #[pin_project] /// struct Foo { /// #[pin] /// future: T, /// field: U, /// } /// /// impl Foo { /// fn baz(self: Pin<&mut Self>) { /// let this = self.project(); /// let _: Pin<&mut T> = this.future; // Pinned reference to the field /// let _: &mut U = this.field; // Normal reference to the field /// } /// } /// ``` /// /// Note that borrowing the field where `#[pin]` attribute is used multiple /// times requires using [`.as_mut()`][`Pin::as_mut`] to avoid /// consuming the `Pin`. /// /// If you want to implement [`Unpin`] manually, you must use the `UnsafeUnpin` /// argument to `#[pin_project]`. /// /// ```rust /// use pin_project::{pin_project, UnsafeUnpin}; /// use std::pin::Pin; /// /// #[pin_project(UnsafeUnpin)] /// struct Foo { /// #[pin] /// future: T, /// field: U, /// } /// /// impl Foo { /// fn baz(self: Pin<&mut Self>) { /// let this = self.project(); /// let _: Pin<&mut T> = this.future; // Pinned reference to the field /// let _: &mut U = this.field; // Normal reference to the field /// } /// } /// /// unsafe impl UnsafeUnpin for Foo {} // Conditional Unpin impl /// ``` /// /// 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`. /// /// `#[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 pin_project::{pin_project, pinned_drop}; /// use std::{fmt::Debug, pin::Pin}; /// /// #[pin_project(PinnedDrop)] /// pub struct Foo { /// #[pin] /// pinned_field: T, /// unpin_field: U, /// } /// /// #[pinned_drop] /// impl PinnedDrop for Foo { /// fn drop(self: Pin<&mut Self>) { /// println!("Dropping pinned field: {:?}", self.pinned_field); /// println!("Dropping unpin field: {:?}", self.unpin_field); /// } /// } /// /// fn main() { /// let _x = Foo { pinned_field: true, unpin_field: 40 }; /// } /// ``` /// /// See also [`pinned_drop`] attribute. /// /// ## Supported Items /// /// The current pin-project supports the following types of items. /// /// ### Structs (structs with named fields): /// /// ```rust /// use pin_project::pin_project; /// use std::pin::Pin; /// /// #[pin_project] /// struct Foo { /// #[pin] /// future: T, /// field: U, /// } /// /// impl Foo { /// fn baz(self: Pin<&mut Self>) { /// let this = self.project(); /// let _: Pin<&mut T> = this.future; /// let _: &mut U = this.field; /// } /// } /// ``` /// /// ### Tuple structs (structs with unnamed fields): /// /// ```rust /// use pin_project::pin_project; /// use std::pin::Pin; /// /// #[pin_project] /// struct Foo(#[pin] T, U); /// /// impl Foo { /// fn baz(self: Pin<&mut Self>) { /// let this = self.project(); /// let _: Pin<&mut T> = this.0; /// let _: &mut U = this.1; /// } /// } /// ``` /// /// Structs without fields (unit-like struct and zero fields struct) are not /// supported. /// /// ### Enums /// /// `pin_project` also supports enums, but to use it, you need to use with the /// [`project`] attribute. /// /// The attribute at the expression position is not stable, so you need to use /// a dummy `#[project]` attribute for the function. /// /// ```rust /// use pin_project::{pin_project, project}; /// use std::pin::Pin; /// /// #[pin_project] /// enum Foo { /// Tuple(#[pin] A, B), /// Struct { field: C }, /// Unit, /// } /// /// impl Foo { /// #[project] // Nightly does not need a dummy attribute to the function. /// fn baz(self: Pin<&mut Self>) { /// #[project] /// match self.project() { /// Foo::Tuple(x, y) => { /// let _: Pin<&mut A> = x; /// let _: &mut B = y; /// } /// Foo::Struct { field } => { /// let _: &mut C = field; /// } /// Foo::Unit => {} /// } /// } /// } /// ``` /// /// Enums without variants (zero-variant enums) are not supported. /// /// See also [`project`] and [`project_ref`] attributes. /// /// [`Pin::as_mut`]: core::pin::Pin::as_mut /// [`Pin::set`]: core::pin::Pin::set /// [`drop`]: Drop::drop /// [`UnsafeUnpin`]: https://docs.rs/pin-project/0.4/pin_project/trait.UnsafeUnpin.html /// [`project`]: ./attr.project.html /// [`project_ref`]: ./attr.project_ref.html /// [`pinned_drop`]: ./attr.pinned_drop.html #[proc_macro_attribute] pub fn pin_project(args: TokenStream, input: TokenStream) -> TokenStream { pin_project::attribute(&args.into(), input.into()).into() } /// An attribute for annotating an impl block that implements [`Drop`]. /// /// This attribute is only needed when you wish to provide a [`Drop`] /// impl for your type. The impl block annotated with `#[pinned_drop]` acts just /// like a normal [`Drop`] impl, except for the fact that `drop` method takes /// `Pin<&mut Self>`. In particular, it will never be called more than once, /// just like [`Drop::drop`]. /// /// ## Example /// /// ```rust /// use pin_project::{pin_project, pinned_drop}; /// use std::pin::Pin; /// /// #[pin_project(PinnedDrop)] /// struct Foo { /// #[pin] /// field: u8, /// } /// /// #[pinned_drop] /// impl PinnedDrop for Foo { /// fn drop(self: Pin<&mut Self>) { /// println!("Dropping: {}", self.field); /// } /// } /// /// fn main() { /// let _x = Foo { field: 50 }; /// } /// ``` /// /// See ["pinned-drop" section of `pin_project` attribute][pinned-drop] for more details. /// /// [pinned-drop]: ./attr.pin_project.html#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() } /// An attribute to provide way to refer to the projected type returned by /// `project` method. /// /// The following syntaxes are supported. /// /// ## `impl` blocks /// /// All methods (and associated functions) in `#[project] impl` block become /// methods of the projected type. If you want to implement methods on the /// original type, you need to create another (non-`#[project]`) `impl` block. /// /// To call a method implemented in `#[project] impl` block, you need to first /// get the projected-type with `let this = self.project();`. /// /// ### Examples /// /// ```rust /// use pin_project::{pin_project, project}; /// use std::pin::Pin; /// /// #[pin_project] /// struct Foo { /// #[pin] /// future: T, /// field: U, /// } /// /// // impl for the original type /// impl Foo { /// fn bar(self: Pin<&mut Self>) { /// self.project().baz() /// } /// } /// /// // impl for the projected type /// #[project] /// impl Foo { /// fn baz(self) { /// let Self { future, field } = self; /// /// let _: Pin<&mut T> = future; /// let _: &mut U = field; /// } /// } /// ``` /// /// ## `let` bindings /// /// *The attribute at the expression position is not stable, so you need to use /// a dummy `#[project]` attribute for the function.* /// /// ### Examples /// /// ```rust /// use pin_project::{pin_project, project}; /// use std::pin::Pin; /// /// #[pin_project] /// struct Foo { /// #[pin] /// future: T, /// field: U, /// } /// /// impl Foo { /// #[project] // Nightly does not need a dummy attribute to the function. /// fn baz(self: Pin<&mut Self>) { /// #[project] /// let Foo { future, field } = self.project(); /// /// let _: Pin<&mut T> = future; /// let _: &mut U = field; /// } /// } /// ``` /// /// ## `match` expressions /// /// *The attribute at the expression position is not stable, so you need to use /// a dummy `#[project]` attribute for the function.* /// /// ### Examples /// /// ```rust /// use pin_project::{pin_project, project}; /// use std::pin::Pin; /// /// #[pin_project] /// enum Foo { /// Tuple(#[pin] A, B), /// Struct { field: C }, /// Unit, /// } /// /// impl Foo { /// #[project] // Nightly does not need a dummy attribute to the function. /// fn baz(self: Pin<&mut Self>) { /// #[project] /// match self.project() { /// Foo::Tuple(x, y) => { /// let _: Pin<&mut A> = x; /// let _: &mut B = y; /// } /// Foo::Struct { field } => { /// let _: &mut C = field; /// } /// Foo::Unit => {} /// } /// } /// } /// ``` /// /// ## `use` statements /// /// ### Examples /// /// ```rust /// # mod dox { /// use pin_project::pin_project; /// /// #[pin_project] /// struct Foo { /// #[pin] /// field: A, /// } /// /// mod bar { /// use super::Foo; /// use pin_project::project; /// use std::pin::Pin; /// /// #[project] /// use super::Foo; /// /// #[project] /// fn baz(foo: Pin<&mut Foo>) { /// #[project] /// let Foo { field } = foo.project(); /// let _: Pin<&mut A> = field; /// } /// } /// # } /// ``` #[proc_macro_attribute] pub fn project(args: TokenStream, input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input); project::attribute(&args.into(), input, Mutable).into() } /// An attribute to provide way to refer to the projected type returned by /// `project_ref` method. /// /// This is the same as [`project`] attribute except it refers to the projected /// type returned by `project_ref` method. /// /// See [`project`] attribute for more details. /// /// [`project`]: ./attr.project.html #[proc_macro_attribute] pub fn project_ref(args: TokenStream, input: TokenStream) -> TokenStream { let input = syn::parse_macro_input!(input); project::attribute(&args.into(), input, Immutable).into() } /// An internal helper macro. #[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-0.4.8/src/pin_project/attribute.rs010064400007650000024000000053371356530425500215020ustar0000000000000000use proc_macro2::{Span, TokenStream}; use quote::quote; use syn::{ parse::{Parse, ParseStream}, *, }; use crate::utils::{SliceExt, CURRENT_PRIVATE_MODULE}; use super::PIN; // 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 { mut attrs, body } = syn::parse2(input)?; let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site()); attrs.push(syn::parse_quote! { #[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. attrs.push(syn::parse_quote! { #[pin(#private(#args))] }); Ok(quote! { #(#attrs)* #body }) } #[allow(dead_code)] // https://github.com/rust-lang/rust/issues/56750 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. Err(error!( input.parse::()?, "#[pin_project] attribute may only be used on structs or enums" )) } else if let Some(attr) = attrs.find(PIN) { Err(error!(attr, "#[pin] attribute may only be used on fields of structs or variants")) } else if let Some(attr) = attrs.find("pin_project") { Err(error!(attr, "only one #[pin_project] attribute is allowed")) } else { Ok(Self { attrs, body: input.parse()? }) } } } pin-project-internal-0.4.8/src/pin_project/derive.rs010064400007650000024000001012151361355151100207360ustar0000000000000000use proc_macro2::{Span, TokenStream}; use quote::{format_ident, quote, quote_spanned}; use syn::{ parse::{Parse, ParseBuffer, ParseStream}, visit_mut::VisitMut, *, }; use crate::utils::*; use super::PIN; pub(super) fn parse_derive(input: TokenStream) -> Result { match syn::parse2(input)? { Item::Struct(ItemStruct { attrs, vis, ident, generics, fields, .. }) => { validate_struct(&ident, &fields)?; let mut cx = Context::new(attrs, vis, ident, generics)?; let packed_check = cx.ensure_not_packed(&fields)?; let mut proj_items = cx.parse_struct(&fields)?; proj_items.extend(packed_check); proj_items.extend(cx.make_unpin_impl()); proj_items.extend(cx.make_drop_impl()); Ok(proj_items) } Item::Enum(ItemEnum { attrs, vis, ident, generics, brace_token, variants, .. }) => { validate_enum(brace_token, &variants)?; let mut cx = Context::new(attrs, vis, ident, generics)?; // We don't need to check for '#[repr(packed)]', // since it does not apply to enums. let mut proj_items = cx.parse_enum(&variants)?; proj_items.extend(cx.make_unpin_impl()); proj_items.extend(cx.make_drop_impl()); Ok(proj_items) } item => Err(error!(item, "#[pin_project] attribute may only be used on structs or enums")), } } fn validate_struct(ident: &Ident, fields: &Fields) -> Result<()> { match fields { Fields::Named(FieldsNamed { named: f, .. }) | Fields::Unnamed(FieldsUnnamed { unnamed: f, .. }) if f.is_empty() => { Err(error!( fields, "#[pin_project] attribute may not be used on structs with zero fields" )) } Fields::Unit => { Err(error!(ident, "#[pin_project] attribute may not be used on structs with units")) } _ => Ok(()), } } fn validate_enum(brace_token: token::Brace, variants: &Variants) -> Result<()> { if variants.is_empty() { return Err(syn::Error::new( brace_token.span, "#[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 { Err(error!(e, "#[pin_project] attribute may not be used on enums with discriminants")) } else if let Some(attr) = v.attrs.find(PIN) { Err(error!(attr, "#[pin] attribute may only be used on fields of structs or variants")) } else if let Fields::Unit = v.fields { Ok(has_field) } else { Ok(true) } })?; if has_field { Ok(()) } else { Err(error!( variants, "#[pin_project] attribute may not be used on enums that have no field" )) } } #[derive(Default)] struct Args { pinned_drop: Option, unsafe_unpin: Option, } const DUPLICATE_PIN: &str = "duplicate #[pin] attribute"; impl Args { fn get(attrs: &[Attribute]) -> Result { let mut prev: Option<(&Attribute, Result)> = None; for attr in attrs { if attr.path.is_ident(PIN) { if let Some((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. let res = syn::parse2::(attr.tokens.clone()); let span = match (&prev_res, res) { (Ok(_), Ok(_)) => unreachable!(), (_, Ok(_)) => prev_attr, (Ok(_), _) => attr, (Err(prev_err), Err(_)) => { if prev_err.to_string() == DUPLICATE_PIN { attr } else { prev_attr } } }; return Err(error!(span, DUPLICATE_PIN)); } prev = Some((attr, syn::parse2::(attr.tokens.clone()))); } } // This `unwrap` only fails if another macro removes `#[pin]`. prev.unwrap().1 } } impl Parse for Args { fn parse(input: ParseStream<'_>) -> Result { fn parse_input(input: ParseStream<'_>) -> Result> { // Extracts `#args` from `(#private(#args))`. if let Ok(content) = input.parenthesized() { if let Ok(private) = content.parse::() { if private == CURRENT_PRIVATE_MODULE { if let Ok(args) = content.parenthesized() { return Ok(args); } } } } // If this fails, it means that there is a `#[pin]` attribute // inserted by something other than #[pin_project] attribute. Err(error!(TokenStream::new(), DUPLICATE_PIN)) } let input = parse_input(input)?; let mut args = Self::default(); while !input.is_empty() { let ident = input.parse::()?; match &*ident.to_string() { "PinnedDrop" => { if args.pinned_drop.is_some() { return Err(error!(ident, "duplicate `PinnedDrop` argument")); } args.pinned_drop = Some(ident.span()); } "UnsafeUnpin" => { if args.unsafe_unpin.is_some() { return Err(error!(ident, "duplicate `UnsafeUnpin` argument")); } args.unsafe_unpin = Some(ident.span()); } _ => return Err(error!(ident, "unexpected argument: {}", ident)), } if !input.is_empty() { let _: token::Comma = input.parse()?; } } Ok(args) } } struct OriginalType { /// Attributes of the original type. attrs: Vec, /// Visibility of the original type. vis: Visibility, /// Name of the original type. ident: Ident, /// Generics of the original type. generics: Generics, } struct ProjectedType { /// Visibility of the projected type. 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, /// Lifetime on the generated projected type. lifetime: Lifetime, /// Generics of the projected type. generics: Generics, } struct Context { orig: OriginalType, proj: ProjectedType, /// Types of the pinned fields. pinned_fields: Vec, /// `PinnedDrop` attribute. pinned_drop: Option, /// `UnsafeUnpin` attribute. unsafe_unpin: Option, } impl Context { fn new( attrs: Vec, vis: Visibility, ident: Ident, mut generics: Generics, ) -> Result { let Args { pinned_drop, unsafe_unpin } = Args::get(&attrs)?; { let ty_generics = generics.split_for_impl().1; let self_ty = syn::parse_quote!(#ident #ty_generics); let mut visitor = ReplaceReceiver::new(&self_ty); visitor.visit_where_clause_mut(generics.make_where_clause()); } let mut lifetime_name = String::from(DEFAULT_LIFETIME_NAME); determine_lifetime_name(&mut lifetime_name, &generics.params); let lifetime = Lifetime::new(&lifetime_name, Span::call_site()); let mut proj_generics = generics.clone(); insert_lifetime(&mut proj_generics, lifetime.clone()); Ok(Self { proj: ProjectedType { vis: determine_visibility(&vis), mut_ident: proj_ident(&ident, Mutable), ref_ident: proj_ident(&ident, Immutable), lifetime, generics: proj_generics, }, orig: OriginalType { attrs, vis, ident, generics }, pinned_drop, unsafe_unpin, pinned_fields: Vec::new(), }) } fn parse_struct(&mut self, fields: &Fields) -> Result { let (proj_pat, proj_init, proj_fields, proj_ref_fields) = match fields { Fields::Named(fields) => self.visit_named(fields)?, Fields::Unnamed(fields) => self.visit_unnamed(fields, true)?, Fields::Unit => unreachable!(), }; let orig_ident = &self.orig.ident; let proj_ident = &self.proj.mut_ident; let proj_ref_ident = &self.proj.ref_ident; let vis = &self.proj.vis; let proj_generics = &self.proj.generics; let where_clause = self.orig.generics.split_for_impl().2; let mut proj_items = quote! { #[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. #[allow(dead_code)] // This lint warns unused fields/variants. #vis struct #proj_ident #proj_generics #where_clause #proj_fields #[allow(dead_code)] // This lint warns unused fields/variants. #vis struct #proj_ref_ident #proj_generics #where_clause #proj_ref_fields }; let proj_body = quote! { let #orig_ident #proj_pat = self.get_unchecked_mut(); #proj_ident #proj_init }; let proj_ref_body = quote! { let #orig_ident #proj_pat = self.get_ref(); #proj_ref_ident #proj_init }; proj_items.extend(self.make_proj_impl(&proj_body, &proj_ref_body)); Ok(proj_items) } fn parse_enum(&mut self, variants: &Variants) -> Result { let (proj_variants, proj_ref_variants, proj_arms, proj_ref_arms) = self.visit_variants(variants)?; let proj_ident = &self.proj.mut_ident; let proj_ref_ident = &self.proj.ref_ident; let vis = &self.proj.vis; let proj_generics = &self.proj.generics; let where_clause = self.orig.generics.split_for_impl().2; let mut proj_items = quote! { #[allow(clippy::mut_mut)] // This lint warns `&mut &mut `. #[allow(dead_code)] // This lint warns unused fields/variants. #vis enum #proj_ident #proj_generics #where_clause { #proj_variants } #[allow(dead_code)] // This lint warns unused fields/variants. #vis enum #proj_ref_ident #proj_generics #where_clause { #proj_ref_variants } }; let proj_body = quote! { match self.get_unchecked_mut() { #proj_arms } }; let proj_ref_body = quote! { match self.get_ref() { #proj_ref_arms } }; proj_items.extend(self.make_proj_impl(&proj_body, &proj_ref_body)); Ok(proj_items) } fn visit_variants( &mut self, variants: &Variants, ) -> Result<(TokenStream, TokenStream, TokenStream, TokenStream)> { let mut proj_variants = TokenStream::new(); let mut proj_ref_variants = TokenStream::new(); let mut proj_arms = TokenStream::new(); let mut proj_ref_arms = TokenStream::new(); for Variant { ident, fields, .. } in variants { let (proj_pat, proj_body, proj_fields, proj_ref_fields) = match fields { Fields::Named(fields) => self.visit_named(fields)?, Fields::Unnamed(fields) => self.visit_unnamed(fields, false)?, Fields::Unit => { (TokenStream::new(), TokenStream::new(), TokenStream::new(), TokenStream::new()) } }; let orig_ident = &self.orig.ident; let proj_ident = &self.proj.mut_ident; let proj_ref_ident = &self.proj.ref_ident; proj_variants.extend(quote! { #ident #proj_fields, }); proj_ref_variants.extend(quote! { #ident #proj_ref_fields, }); proj_arms.extend(quote! { #orig_ident::#ident #proj_pat => { #proj_ident::#ident #proj_body } }); proj_ref_arms.extend(quote! { #orig_ident::#ident #proj_pat => { #proj_ref_ident::#ident #proj_body } }); } Ok((proj_variants, proj_ref_variants, proj_arms, proj_ref_arms)) } fn visit_named( &mut self, FieldsNamed { named: fields, .. }: &FieldsNamed, ) -> Result<(TokenStream, TokenStream, TokenStream, TokenStream)> { let mut proj_pat = Vec::with_capacity(fields.len()); let mut proj_body = Vec::with_capacity(fields.len()); let mut proj_fields = Vec::with_capacity(fields.len()); let mut proj_ref_fields = Vec::with_capacity(fields.len()); for Field { attrs, vis, ident, ty, .. } in fields { if attrs.find_exact(PIN)?.is_some() { self.pinned_fields.push(ty.clone()); let lifetime = &self.proj.lifetime; proj_fields.push(quote! { #vis #ident: ::core::pin::Pin<&#lifetime mut (#ty)> }); proj_ref_fields.push(quote! { #vis #ident: ::core::pin::Pin<&#lifetime (#ty)> }); proj_body.push(quote! { #ident: ::core::pin::Pin::new_unchecked(#ident) }); } else { let lifetime = &self.proj.lifetime; proj_fields.push(quote! { #vis #ident: &#lifetime mut (#ty) }); proj_ref_fields.push(quote! { #vis #ident: &#lifetime (#ty) }); proj_body.push(quote! { #ident }); } proj_pat.push(ident); } let proj_pat = quote!({ #(#proj_pat),* }); let proj_body = quote!({ #(#proj_body),* }); let proj_fields = quote!({ #(#proj_fields),* }); let proj_ref_fields = quote!({ #(#proj_ref_fields),* }); Ok((proj_pat, proj_body, proj_fields, proj_ref_fields)) } fn visit_unnamed( &mut self, FieldsUnnamed { unnamed: fields, .. }: &FieldsUnnamed, is_struct: bool, ) -> Result<(TokenStream, TokenStream, TokenStream, TokenStream)> { let mut proj_pat = Vec::with_capacity(fields.len()); let mut proj_body = Vec::with_capacity(fields.len()); let mut proj_fields = Vec::with_capacity(fields.len()); let mut proj_ref_fields = Vec::with_capacity(fields.len()); for (i, Field { attrs, vis, ty, .. }) in fields.iter().enumerate() { let id = format_ident!("_{}", i); if attrs.find_exact(PIN)?.is_some() { self.pinned_fields.push(ty.clone()); let lifetime = &self.proj.lifetime; proj_fields.push(quote! { #vis ::core::pin::Pin<&#lifetime mut (#ty)> }); proj_ref_fields.push(quote! { #vis ::core::pin::Pin<&#lifetime (#ty)> }); proj_body.push(quote! { ::core::pin::Pin::new_unchecked(#id) }); } else { let lifetime = &self.proj.lifetime; proj_fields.push(quote! { #vis &#lifetime mut (#ty) }); proj_ref_fields.push(quote! { #vis &#lifetime (#ty) }); proj_body.push(quote! { #id }); } proj_pat.push(id); } let proj_pat = quote!((#(#proj_pat),*)); let proj_body = quote!((#(#proj_body),*)); let (proj_fields, proj_ref_fields) = if is_struct { (quote!((#(#proj_fields),*);), quote!((#(#proj_ref_fields),*);)) } else { (quote!((#(#proj_fields),*)), quote!((#(#proj_ref_fields),*))) }; Ok((proj_pat, proj_body, proj_fields, proj_ref_fields)) } /// Creates conditional `Unpin` implementation for original type. fn make_unpin_impl(&mut self) -> TokenStream { if let Some(unsafe_unpin) = self.unsafe_unpin { let mut proj_generics = self.proj.generics.clone(); let orig_ident = &self.orig.ident; let lifetime = &self.proj.lifetime; let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site()); proj_generics.make_where_clause().predicates.push( // Make the error message highlight `UnsafeUnpin` argument. syn::parse2(quote_spanned! { unsafe_unpin => ::pin_project::#private::Wrapper<#lifetime, Self>: ::pin_project::UnsafeUnpin }) .unwrap(), ); let (impl_generics, _, where_clause) = proj_generics.split_for_impl(); let ty_generics = self.orig.generics.split_for_impl().1; quote! { #[allow(single_use_lifetimes)] impl #impl_generics ::core::marker::Unpin for #orig_ident #ty_generics #where_clause {} } } else { let mut full_where_clause = self.orig.generics.where_clause.as_ref().cloned().unwrap(); let orig_ident = &self.orig.ident; let make_span = || { #[cfg(pin_project_show_unpin_struct)] { proc_macro::Span::def_site().into() } #[cfg(not(pin_project_show_unpin_struct))] { Span::call_site() } }; let struct_ident = format_ident!("__{}", orig_ident, span = make_span()); // Generate a field in our new struct for every // pinned field in the original type. let fields: Vec<_> = self .pinned_fields .iter() .enumerate() .map(|(i, ty)| { let field_ident = format_ident!("__field{}", i); quote! { #field_ident: #ty } }) .collect(); // 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: Vec<_> = self .orig .generics .lifetimes() .enumerate() .map(|(i, LifetimeDef { lifetime, .. })| { let field_ident = format_ident!("__lifetime{}", i); quote! { #field_ident: &#lifetime () } }) .collect(); let scope_ident = format_ident!("__unpin_scope_{}", orig_ident); let vis = &self.orig.vis; let lifetime = &self.proj.lifetime; let type_params: Vec<_> = self.orig.generics.type_params().map(|t| &t.ident).collect(); let proj_generics = &self.proj.generics; let (impl_generics, proj_ty_generics, _) = proj_generics.split_for_impl(); let (_, ty_generics, where_clause) = self.orig.generics.split_for_impl(); full_where_clause.predicates.push(syn::parse_quote! { #struct_ident #proj_ty_generics: ::core::marker::Unpin }); let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site()); let inner_data = quote! { // This needs to have the same visibility as the original type, // due to the limitations of the 'public in private' error. // // Out 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 take // steps to ensure that the user can never actually reference // this 'public' type. These steps are described below. // // See also https://github.com/taiki-e/pin-project/pull/53. #vis struct #struct_ident #proj_generics #where_clause { __pin_project_use_generics: ::pin_project::#private::AlwaysUnpin<#lifetime, (#(#type_params),*)>, #(#fields,)* #(#lifetime_fields,)* } impl #impl_generics ::core::marker::Unpin for #orig_ident #ty_generics #full_where_clause {} }; if cfg!(pin_project_show_unpin_struct) { // On nightly, we use def-site hygiene to make it impossible // for user code to refer to any of the types we define. // This allows us to omit wrapping the generated types // in an fn() scope, allowing rustdoc to properly document // them. inner_data } else { // When we're not on nightly, we need to create an enclosing fn() scope // for all of our generated items. This makes it impossible for // user code to refer to any of our generated types, but has // the advantage of preventing Rustdoc from displaying // docs for any of our types. In particular, users cannot see // the automatically generated Unpin impl for the 'UnpinStruct$Name' types. quote! { #[allow(non_snake_case)] fn #scope_ident() { #inner_data } } } } } /// Creates `Drop` implementation for original type. fn make_drop_impl(&self) -> TokenStream { let ident = &self.orig.ident; let (impl_generics, ty_generics, where_clause) = self.orig.generics.split_for_impl(); let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site()); if let Some(pinned_drop) = self.pinned_drop { // Make the error message highlight `PinnedDrop` argument. // See https://github.com/taiki-e/pin-project/issues/16#issuecomment-513586812 // for why this is only for the span of function calls, not the entire `impl` block. let call_drop = quote_spanned! { pinned_drop => ::pin_project::#private::PinnedDrop::drop(pinned_self) }; quote! { #[allow(single_use_lifetimes)] impl #impl_generics ::core::ops::Drop for #ident #ty_generics #where_clause { fn drop(&mut self) { // Safety - we're in 'drop', so we know that 'self' will // never move again. let pinned_self = unsafe { ::core::pin::Pin::new_unchecked(self) }; // We call `pinned_drop` only once. Since `PinnedDrop::drop` // is an unsafe function and a private API, it is never called again in safe // code *unless the user uses a maliciously crafted macro*. unsafe { #call_drop; } } } } } else { // If the user does not provide a pinned_drop 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)] impl #trait_ident for T {} #[allow(single_use_lifetimes)] impl #impl_generics #trait_ident for #ident #ty_generics #where_clause {} // 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 attirbutes/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 #[allow(single_use_lifetimes)] impl #impl_generics ::pin_project::#private::PinnedDrop for #ident #ty_generics #where_clause { unsafe fn drop(self: ::core::pin::Pin<&mut Self>) {} } } } } /// Creates an implementation of the projection method. fn make_proj_impl(&self, proj_body: &TokenStream, proj_ref_body: &TokenStream) -> TokenStream { let vis = &self.proj.vis; let lifetime = &self.proj.lifetime; let orig_ident = &self.orig.ident; let proj_ident = &self.proj.mut_ident; let proj_ref_ident = &self.proj.ref_ident; let proj_ty_generics = self.proj.generics.split_for_impl().1; let (impl_generics, ty_generics, where_clause) = self.orig.generics.split_for_impl(); quote! { impl #impl_generics #orig_ident #ty_generics #where_clause { #vis fn project<#lifetime>( self: ::core::pin::Pin<&#lifetime mut Self>, ) -> #proj_ident #proj_ty_generics { unsafe { #proj_body } } #vis fn project_ref<#lifetime>( self: ::core::pin::Pin<&#lifetime Self>, ) -> #proj_ref_ident #proj_ty_generics { unsafe { #proj_ref_body } } } } } fn ensure_not_packed(&self, fields: &Fields) -> Result { for meta in self.orig.attrs.iter().filter_map(|attr| attr.parse_meta().ok()) { if let Meta::List(l) = meta { if l.path.is_ident("repr") { for repr in l.nested.iter() { match repr { NestedMeta::Meta(Meta::Path(path)) | NestedMeta::Meta(Meta::List(MetaList { path, .. })) if path.is_ident("packed") => { return Err(error!( repr, "#[pin_project] attribute may not be used on #[repr(packed)] types" )); } _ => {} } } } } } // As proc-macro-derive can't rewrite the structure definition, // it's probably no longer necessary, but it keeps it for now. // 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: // // #[deny(safe_packed_borrows)] // fn enforce_not_packed_for_MyStruct(val: &MyStruct) { // let _field1 = &val.field1; // let _field2 = &val.field2; // ... // let _fieldn = &val.fieldn; // } // // Taking a reference to a packed field is unsafe, and applying // #[deny(safe_packed_borrows)] makes sure that doing this without // an 'unsafe' block (which we deliberately do not generate) // 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. let mut field_refs = vec![]; match fields { Fields::Named(FieldsNamed { named, .. }) => { for Field { ident, .. } in named { field_refs.push(quote! { &val.#ident; }); } } Fields::Unnamed(FieldsUnnamed { unnamed, .. }) => { for (index, _) in unnamed.iter().enumerate() { let index = Index::from(index); field_refs.push(quote! { &val.#index; }); } } Fields::Unit => {} } let (impl_generics, ty_generics, where_clause) = self.orig.generics.split_for_impl(); let struct_name = &self.orig.ident; let method_name = format_ident!("__pin_project_assert_not_repr_packed_{}", self.orig.ident); Ok(quote! { #[allow(single_use_lifetimes)] #[allow(non_snake_case)] #[deny(safe_packed_borrows)] fn #method_name #impl_generics (val: &#struct_name #ty_generics) #where_clause { #(#field_refs)* } }) } } pin-project-internal-0.4.8/src/pin_project/mod.rs010064400007650000024000000006471356530425500202550ustar0000000000000000use proc_macro2::TokenStream; mod attribute; mod derive; /// 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(|e| e.to_compile_error()) } pub(crate) fn derive(input: TokenStream) -> TokenStream { derive::parse_derive(input).unwrap_or_else(|e| e.to_compile_error()) } pin-project-internal-0.4.8/src/pinned_drop.rs010064400007650000024000000160221361133565000174500ustar0000000000000000use proc_macro2::{Span, TokenStream}; use quote::{quote, quote_spanned, ToTokens}; use syn::{spanned::Spanned, visit_mut::VisitMut, *}; use crate::utils::{ parse_as_empty, prepend_underscore_to_self, ReplaceReceiver, CURRENT_PRIVATE_MODULE, }; pub(crate) fn attribute(args: &TokenStream, mut input: ItemImpl) -> TokenStream { if let Err(e) = parse_as_empty(args).and_then(|()| parse(&mut input)) { let self_ty = &input.self_ty; let (impl_generics, _, where_clause) = input.generics.split_for_impl(); let mut tokens = e.to_compile_error(); let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site()); // Generate a dummy `PinnedDrop` implementation. // 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. tokens.extend(quote! { impl #impl_generics ::pin_project::#private::PinnedDrop for #self_ty #where_clause { unsafe fn drop(self: ::core::pin::Pin<&mut Self>) {} } }); tokens } else { input.into_token_stream() } } fn parse_method(method: &ImplItemMethod) -> 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 method.sig.ident != "drop" { return Err(error!( method.sig.ident, "method `{}` is not a member of trait `PinnedDrop", method.sig.ident, )); } if let ReturnType::Type(_, ty) = &method.sig.output { match &**ty { Type::Tuple(TypeTuple { elems, .. }) if elems.is_empty() => {} _ => return Err(error!(ty, "method `drop` must return the unit type")), } } if method.sig.inputs.len() != 1 { if method.sig.inputs.is_empty() { return Err(syn::Error::new(method.sig.paren_token.span, INVALID_ARGUMENT)); } else { return Err(error!(&method.sig.inputs, INVALID_ARGUMENT)); } } if let FnArg::Typed(PatType { pat, ty, .. }) = &method.sig.inputs[0] { // !by_ref (mutability) ident !subpat: path if let (Pat::Ident(PatIdent { by_ref: None, ident, subpat: None, .. }), Some(path)) = (&**pat, get_ty_path(ty)) { let ty = &path.segments.last().unwrap(); if let PathArguments::AngleBracketed(args) = &ty.arguments { // (mut) self: (path::)Pin if ident == "self" && args.args.len() == 1 && ty.ident == "Pin" { // &mut if let GenericArgument::Type(Type::Reference(TypeReference { mutability: Some(_), elem, .. })) = &args.args[0] { if get_ty_path(elem).map_or(false, |path| path.is_ident("Self")) { if method.sig.unsafety.is_some() { return Err(error!( method.sig.unsafety, "implementing the method `drop` is not unsafe" )); } return Ok(()); } } } } } } Err(error!(method.sig.inputs[0], INVALID_ARGUMENT)) } fn parse(item: &mut ItemImpl) -> Result<()> { if let Some((_, path, _)) = &mut item.trait_ { if path.is_ident("PinnedDrop") { let private = Ident::new(CURRENT_PRIVATE_MODULE, Span::call_site()); *path = syn::parse2(quote_spanned! { path.span() => ::pin_project::#private::PinnedDrop }) .unwrap(); } else { return Err(error!( path, "#[pinned_drop] may only be used on implementation for the `PinnedDrop` trait" )); } } else { return Err(error!( item.self_ty, "#[pinned_drop] may only be used on implementation for the `PinnedDrop` trait" )); } if item.unsafety.is_some() { return Err(error!(item.unsafety, "implementing the trait `PinnedDrop` is not unsafe")); } if item.items.is_empty() { return Err(error!(item, "not all trait items implemented, missing: `drop`")); } for (i, item) in item.items.iter().enumerate() { match item { ImplItem::Const(item) => { return Err(error!( item, "const `{}` is not a member of trait `PinnedDrop`", item.ident )); } ImplItem::Type(item) => { return Err(error!( item, "type `{}` is not a member of trait `PinnedDrop`", item.ident )); } ImplItem::Method(method) => { parse_method(method)?; if i != 0 { return Err(error!(method, "duplicate definitions with name `drop`")); } } _ => parse_as_empty(&item.to_token_stream())?, } } expand_item(item); Ok(()) } // from: // // fn drop(self: Pin<&mut Self>) { // // something // } // // into: // // unsafe fn drop(self: Pin<&mut Self>) { // fn __drop_inner(__self: Pin<&mut Foo<'_, T>>) { // // something // } // __drop_inner(self); // } // fn expand_item(item: &mut ItemImpl) { let method = if let ImplItem::Method(method) = &mut item.items[0] { method } else { unreachable!() }; let mut drop_inner = method.clone(); // `fn drop(mut self: Pin<&mut Self>)` -> `fn __drop_inner(mut __self: Pin<&mut Receiver>)` drop_inner.sig.ident = Ident::new("__drop_inner", drop_inner.sig.ident.span()); drop_inner.sig.generics = item.generics.clone(); if let FnArg::Typed(arg) = &mut drop_inner.sig.inputs[0] { if let Pat::Ident(ident) = &mut *arg.pat { prepend_underscore_to_self(&mut ident.ident); } } let mut visitor = ReplaceReceiver::new(&item.self_ty); visitor.visit_signature_mut(&mut drop_inner.sig); visitor.visit_block_mut(&mut drop_inner.block); // `fn drop(mut self: Pin<&mut Self>)` -> `unsafe fn drop(self: Pin<&mut Self>)` method.sig.unsafety = Some(token::Unsafe::default()); if let FnArg::Typed(arg) = &mut method.sig.inputs[0] { if let Pat::Ident(ident) = &mut *arg.pat { ident.mutability = None; } } method.block = syn::parse_quote! {{ #drop_inner __drop_inner(self); }}; } pin-project-internal-0.4.8/src/project.rs010064400007650000024000000205321361143547600166250ustar0000000000000000use proc_macro2::{Span, TokenStream}; use quote::ToTokens; use syn::{ visit_mut::{self, VisitMut}, *, }; use crate::utils::*; pub(crate) fn attribute(args: &TokenStream, input: Stmt, mutability: Mutability) -> TokenStream { parse_as_empty(args) .and_then(|()| parse(input, mutability)) .unwrap_or_else(|e| e.to_compile_error()) } fn parse(mut stmt: Stmt, mutability: Mutability) -> Result { match &mut stmt { Stmt::Expr(Expr::Match(expr)) | Stmt::Semi(Expr::Match(expr), _) => { Context::new(mutability).replace_expr_match(expr) } Stmt::Local(local) => Context::new(mutability).replace_local(local)?, Stmt::Item(Item::Fn(item)) => replace_item_fn(item, mutability)?, Stmt::Item(Item::Impl(item)) => replace_item_impl(item, mutability), Stmt::Item(Item::Use(item)) => replace_item_use(item, mutability)?, _ => {} } Ok(stmt.into_token_stream()) } struct Context { register: Option<(Ident, usize)>, replaced: bool, mutability: Mutability, } impl Context { fn new(mutability: Mutability) -> Self { Self { register: None, replaced: false, mutability } } fn update(&mut self, ident: &Ident, len: usize) { if self.register.is_none() { self.register = Some((ident.clone(), len)); } } fn compare_paths(&self, ident: &Ident, len: usize) -> bool { match &self.register { Some((i, l)) => *l == len && ident == i, None => false, } } fn replace_local(&mut self, local: &mut Local) -> Result<()> { if let Some(Expr::Match(expr)) = local.init.as_mut().map(|(_, expr)| &mut **expr) { self.replace_expr_match(expr); } if self.replaced { if is_replaceable(&local.pat, false) { return Err(error!( local.pat, "Both initializer expression and pattern are replaceable, \ you need to split the initializer expression into separate let bindings \ to avoid ambiguity" )); } } else { self.replace_pat(&mut local.pat, false); } Ok(()) } fn replace_expr_match(&mut self, expr: &mut ExprMatch) { expr.arms.iter_mut().for_each(|Arm { pat, .. }| self.replace_pat(pat, true)) } fn replace_pat(&mut self, pat: &mut Pat, allow_pat_path: bool) { match pat { Pat::Ident(PatIdent { subpat: Some((_, pat)), .. }) | Pat::Reference(PatReference { pat, .. }) | Pat::Box(PatBox { pat, .. }) | Pat::Type(PatType { pat, .. }) => self.replace_pat(pat, allow_pat_path), Pat::Or(PatOr { cases, .. }) => { cases.iter_mut().for_each(|pat| self.replace_pat(pat, allow_pat_path)) } Pat::Struct(PatStruct { path, .. }) | Pat::TupleStruct(PatTupleStruct { path, .. }) => { self.replace_path(path) } Pat::Path(PatPath { qself: None, path, .. }) if allow_pat_path => { self.replace_path(path) } _ => {} } } fn replace_path(&mut self, path: &mut Path) { let len = match path.segments.len() { // 1: struct // 2: enum len @ 1 | len @ 2 => len, // other path _ => return, }; if self.register.is_none() || self.compare_paths(&path.segments[0].ident, len) { self.update(&path.segments[0].ident, len); self.replaced = true; replace_ident(&mut path.segments[0].ident, self.mutability); } } } fn is_replaceable(pat: &Pat, allow_pat_path: bool) -> bool { match pat { Pat::Ident(PatIdent { subpat: Some((_, pat)), .. }) | Pat::Reference(PatReference { pat, .. }) | Pat::Box(PatBox { pat, .. }) | Pat::Type(PatType { pat, .. }) => is_replaceable(pat, allow_pat_path), Pat::Or(PatOr { cases, .. }) => cases.iter().any(|pat| is_replaceable(pat, allow_pat_path)), Pat::Struct(_) | Pat::TupleStruct(_) => true, Pat::Path(PatPath { qself: None, .. }) => allow_pat_path, _ => false, } } fn replace_item_impl(item: &mut ItemImpl, mutability: Mutability) { let PathSegment { ident, arguments } = match &mut *item.self_ty { Type::Path(TypePath { qself: None, path }) => path.segments.last_mut().unwrap(), _ => return, }; replace_ident(ident, mutability); let mut lifetime_name = String::from(DEFAULT_LIFETIME_NAME); determine_lifetime_name(&mut lifetime_name, &item.generics.params); item.items .iter_mut() .filter_map(|i| if let ImplItem::Method(i) = i { Some(i) } else { None }) .for_each(|item| determine_lifetime_name(&mut lifetime_name, &item.sig.generics.params)); let lifetime = Lifetime::new(&lifetime_name, Span::call_site()); insert_lifetime(&mut item.generics, lifetime.clone()); match arguments { PathArguments::None => { *arguments = PathArguments::AngleBracketed(syn::parse_quote!(<#lifetime>)); } PathArguments::AngleBracketed(args) => { args.args.insert(0, syn::parse_quote!(#lifetime)); } PathArguments::Parenthesized(_) => unreachable!(), } } fn replace_item_fn(item: &mut ItemFn, mutability: Mutability) -> Result<()> { let mut visitor = FnVisitor { res: Ok(()), mutability }; visitor.visit_block_mut(&mut item.block); visitor.res } fn replace_item_use(item: &mut ItemUse, mutability: Mutability) -> Result<()> { let mut visitor = UseTreeVisitor { res: Ok(()), mutability }; visitor.visit_item_use_mut(item); visitor.res } fn replace_ident(ident: &mut Ident, mutability: Mutability) { *ident = proj_ident(ident, mutability); } // ================================================================================================= // visitors struct FnVisitor { res: Result<()>, mutability: Mutability, } impl FnVisitor { /// Returns the attribute name. fn name(&self) -> &str { if self.mutability == Mutable { "project" } else { "project_ref" } } fn visit_stmt(&mut self, node: &mut Stmt) -> Result<()> { let attr = match node { Stmt::Expr(Expr::Match(expr)) | Stmt::Semi(Expr::Match(expr), _) => { expr.attrs.find_remove(self.name())? } Stmt::Local(local) => local.attrs.find_remove(self.name())?, _ => return Ok(()), }; if let Some(attr) = attr { parse_as_empty(&attr.tokens)?; match node { Stmt::Expr(Expr::Match(expr)) | Stmt::Semi(Expr::Match(expr), _) => { Context::new(self.mutability).replace_expr_match(expr) } Stmt::Local(local) => Context::new(self.mutability).replace_local(local)?, _ => unreachable!(), } } Ok(()) } } impl VisitMut for FnVisitor { fn visit_stmt_mut(&mut self, node: &mut Stmt) { if self.res.is_err() { return; } visit_mut::visit_stmt_mut(self, node); if let Err(e) = self.visit_stmt(node) { self.res = Err(e) } } fn visit_item_mut(&mut self, _: &mut Item) { // Do not recurse into nested items. } } struct UseTreeVisitor { res: Result<()>, mutability: Mutability, } impl VisitMut for UseTreeVisitor { fn visit_use_tree_mut(&mut self, node: &mut UseTree) { if self.res.is_err() { return; } match node { // Desugar `use tree::` into `tree::__Projection`. UseTree::Name(name) => replace_ident(&mut name.ident, self.mutability), UseTree::Glob(glob) => { self.res = Err(error!(glob, "#[project] attribute may not be used on glob imports")); } UseTree::Rename(rename) => { // TODO: Consider allowing the projected type to be renamed by `#[project] use Foo as Bar`. self.res = Err(error!(rename, "#[project] attribute may not be used on renamed imports")); } node @ UseTree::Path(_) | node @ UseTree::Group(_) => { visit_mut::visit_use_tree_mut(self, node) } } } } pin-project-internal-0.4.8/src/utils.rs010064400007650000024000000235241361143547600163230ustar0000000000000000use std::mem; use proc_macro2::{Group, TokenStream, TokenTree}; use quote::{format_ident, quote_spanned}; use syn::{ parse::{ParseBuffer, ParseStream}, punctuated::Punctuated, token::{self, Comma}, visit_mut::{self, VisitMut}, *, }; pub(crate) const DEFAULT_LIFETIME_NAME: &str = "'pin"; pub(crate) const CURRENT_PRIVATE_MODULE: &str = "__private"; pub(crate) type Variants = Punctuated; pub(crate) use Mutability::{Immutable, Mutable}; macro_rules! error { ($span:expr, $msg:expr) => { syn::Error::new_spanned(&$span, $msg) }; ($span:expr, $($tt:tt)*) => { error!($span, format!($($tt)*)) }; } #[derive(Clone, Copy, Eq, PartialEq)] pub(crate) enum Mutability { Mutable, Immutable, } /// Creates the ident of projected type from the ident of the original type. pub(crate) fn proj_ident(ident: &Ident, mutability: Mutability) -> Ident { if mutability == Mutable { format_ident!("__{}Projection", ident) } else { format_ident!("__{}ProjectionRef", ident) } } /// 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: &Punctuated, ) { let existing_lifetimes: Vec = generics .iter() .filter_map(|param| { if let GenericParam::Lifetime(LifetimeDef { lifetime, .. }) = param { Some(lifetime.to_string()) } else { None } }) .collect(); while existing_lifetimes.iter().any(|name| name.starts_with(&**lifetime_name)) { lifetime_name.push('_'); } } /// Inserts a `lifetime` at position `0` of `generics.params`. pub(crate) fn insert_lifetime(generics: &mut Generics, lifetime: Lifetime) { if generics.lt_token.is_none() { generics.lt_token = Some(token::Lt::default()) } if generics.gt_token.is_none() { generics.gt_token = Some(token::Gt::default()) } generics.params.insert( 0, GenericParam::Lifetime(LifetimeDef { attrs: Vec::new(), lifetime, colon_token: None, bounds: Punctuated::new(), }), ); } /// Determines the visibility of the projected type and projection method. pub(crate) fn determine_visibility(vis: &Visibility) -> Visibility { if let Visibility::Public(token) = vis { syn::parse2(quote_spanned! { token.pub_token.span => pub(crate) }) .unwrap() } else { vis.clone() } } /// Check if `tokens` is an empty `TokenStream`. /// This is almost equivalent to `syn::parse2::()`, /// but produces a better error message and does not require ownership of `tokens`. pub(crate) fn parse_as_empty(tokens: &TokenStream) -> Result<()> { if tokens.is_empty() { Ok(()) } else { Err(error!(tokens, "unexpected token: {}", tokens)) } } // ================================================================================================= // extension traits pub(crate) trait SliceExt { fn position_exact(&self, ident: &str) -> Result>; fn find(&self, ident: &str) -> Option<&Attribute>; fn find_exact(&self, ident: &str) -> Result>; } pub(crate) trait VecExt { fn find_remove(&mut self, ident: &str) -> Result>; } impl SliceExt for [Attribute] { 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.is_some() { return Err(error!(attr, "duplicate #[{}] attribute", ident)); } parse_as_empty(&attr.tokens)?; prev = Some(i); } Ok((i + 1, prev)) }) .map(|(_, pos)| pos) } fn find(&self, ident: &str) -> Option<&Attribute> { self.iter().position(|attr| attr.path.is_ident(ident)).and_then(|i| self.get(i)) } fn find_exact(&self, ident: &str) -> Result> { self.position_exact(ident).map(|pos| pos.and_then(|i| self.get(i))) } } impl VecExt for Vec { fn find_remove(&mut self, ident: &str) -> Result> { self.position_exact(ident).map(|pos| pos.map(|i| self.remove(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.22/src/receiver.rs pub(crate) struct ReplaceReceiver<'a> { self_ty: &'a Type, } impl<'a> ReplaceReceiver<'a> { pub(crate) fn new(self_ty: &'a Type) -> Self { Self { self_ty } } fn self_to_qself(&mut 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; } *qself = Some(QSelf { lt_token: token::Lt::default(), ty: Box::new(self.self_ty.clone()), position: 0, as_token: None, gt_token: token::Gt::default(), }); match path.segments.pairs().next().unwrap().punct() { Some(&&colon) => path.leading_colon = Some(colon), None => return, } 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 let Type::Path(self_ty) = &self.self_ty { *path = self_ty.path.clone(); 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(token::Colon2::default()); } } } } else { let span = path.segments[0].ident.span(); let msg = "Self type of this impl is unsupported in expression position"; let error = Error::new(span, msg).to_compile_error(); *path = parse_quote!(::core::marker::PhantomData::<#error>); } } } 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.clone(); } 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() { prepend_underscore_to_self(&mut expr.path.segments[0].ident); 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) { if expr.path.is_ident("Self") { self.self_to_expr_path(&mut expr.path); } visit_mut::visit_expr_struct_mut(self, expr); } fn visit_macro_mut(&mut self, node: &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(node.tokens.clone()) { node.tokens = fold_token_stream(node.tokens.clone()); } } fn visit_item_mut(&mut self, _: &mut Item) { // Do not recurse into nested items. } } 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, }) } fn fold_token_stream(tokens: TokenStream) -> TokenStream { tokens .into_iter() .map(|tt| match tt { TokenTree::Ident(mut ident) => { prepend_underscore_to_self(&mut ident); TokenTree::Ident(ident) } TokenTree::Group(group) => { let content = fold_token_stream(group.stream()); TokenTree::Group(Group::new(group.delimiter(), content)) } other => other, }) .collect() } pub(crate) fn prepend_underscore_to_self(ident: &mut Ident) { if ident == "self" { *ident = Ident::new("__self", ident.span()); } }