diff options
author | Haibo Huang <hhb@google.com> | 2021-01-12 12:42:47 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2021-01-12 12:42:47 +0000 |
commit | 706307e81bd30f3603b2af6280e475cc85fb1c0b (patch) | |
tree | b8994b238055e12f5341f5a786ef9823e51d6491 | |
parent | f307beb3ec3abce3be485d39a07912f2f78df48a (diff) | |
parent | 209c5ede38dde24c6d38b8e6286504337b8b7b60 (diff) | |
download | pin-project-lite-706307e81bd30f3603b2af6280e475cc85fb1c0b.tar.gz |
Upgrade rust/crates/pin-project-lite to 0.2.4 am: ffd64ca74d am: 82f9fa1653 am: 209c5ede38
Original change: https://android-review.googlesource.com/c/platform/external/rust/crates/pin-project-lite/+/1547177
MUST ONLY BE SUBMITTED BY AUTOMERGER
Change-Id: Ifb76e168c2d1ed8649b9be37e62e4d912928d849
-rw-r--r-- | .cargo_vcs_info.json | 2 | ||||
-rw-r--r-- | CHANGELOG.md | 58 | ||||
-rw-r--r-- | Cargo.toml | 2 | ||||
-rw-r--r-- | Cargo.toml.orig | 2 | ||||
-rw-r--r-- | METADATA | 6 | ||||
-rw-r--r-- | src/lib.rs | 480 | ||||
-rw-r--r-- | src/lib.rs.orig | 480 | ||||
-rw-r--r-- | tests/compiletest.rs | 1 | ||||
-rw-r--r-- | tests/drop_order.rs | 168 | ||||
-rw-r--r-- | tests/lint.rs | 26 | ||||
-rw-r--r-- | tests/test.rs | 22 |
11 files changed, 1190 insertions, 57 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index f892109..32ae14a 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,5 @@ { "git": { - "sha1": "f1a711f00677639a51118cc4f31ea4ec59220f0e" + "sha1": "416be96f7777862c68b567c92a91887f69a8c2b3" } } diff --git a/CHANGELOG.md b/CHANGELOG.md index fc1b7d1..e9d1276 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,13 +10,25 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com ## [Unreleased] +## [0.2.4] - 2021-01-11 + +- [Add `project_replace`.](https://github.com/taiki-e/pin-project-lite/pull/43) + +## [0.2.3] - 2021-01-09 + +- [Suppress `clippy::unknown_clippy_lints` lint in generated code.](https://github.com/taiki-e/pin-project-lite/pull/47) + +## [0.2.2] - 2021-01-09 + +- [Suppress `clippy::ref_option_ref` lint in generated code.](https://github.com/taiki-e/pin-project-lite/pull/45) + ## [0.2.1] - 2021-01-05 - Exclude unneeded files from crates.io. ## [0.2.0] - 2020-11-13 -- [`pin_project!` macro now supports enums.][28] +- [`pin_project!` macro now supports enums.](https://github.com/taiki-e/pin-project-lite/pull/28) To use `pin_project!` on enums, you need to name the projection type returned from the method. @@ -43,7 +55,7 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com } ``` -- [Support naming the projection types.][28] +- [Support naming the projection types.](https://github.com/taiki-e/pin-project-lite/pull/28) By passing an attribute with the same name as the method, you can name the projection type returned from the method: @@ -65,8 +77,6 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com } ``` -[28]: https://github.com/taiki-e/pin-project-lite/pull/28 - ## [0.1.11] - 2020-10-20 - Suppress `clippy::redundant_pub_crate` lint in generated code. @@ -79,71 +89,59 @@ Note: In this file, do not use the hard wrap in the middle of a sentence for com ## [0.1.9] - 2020-09-29 -- Fix trailing comma support in generics +- [Fix trailing comma support in generics.](https://github.com/taiki-e/pin-project-lite/pull/32) ## [0.1.8] - 2020-09-26 -- Fix compatibility of generated code with `forbid(future_incompatible)` +- [Fix compatibility of generated code with `forbid(future_incompatible)`.](https://github.com/taiki-e/pin-project-lite/pull/30) Note: This does not guarantee compatibility with `forbid(future_incompatible)` in the future. If rustc adds a new lint, we may not be able to keep this. ## [0.1.7] - 2020-06-04 -- [Support `?Sized` bounds in where clauses.][22] +- [Support `?Sized` bounds in where clauses.](https://github.com/taiki-e/pin-project-lite/pull/22) -- [Fix lifetime inference error when an associated type is used in fields.][20] +- [Fix lifetime inference error when an associated type is used in fields.](https://github.com/taiki-e/pin-project-lite/pull/20) - Suppress `clippy::used_underscore_binding` lint in generated code. - Documentation improvements. -[20]: https://github.com/taiki-e/pin-project-lite/pull/20 -[22]: https://github.com/taiki-e/pin-project-lite/pull/22 - ## [0.1.6] - 2020-05-31 -- [Support lifetime bounds in where clauses.][18] +- [Support lifetime bounds in where clauses.](https://github.com/taiki-e/pin-project-lite/pull/18) - Documentation improvements. -[18]: https://github.com/taiki-e/pin-project-lite/pull/18 - ## [0.1.5] - 2020-05-07 -- [Support overwriting the name of core crate.][14] - -[14]: https://github.com/taiki-e/pin-project-lite/pull/14 +- [Support overwriting the name of `core` crate.](https://github.com/taiki-e/pin-project-lite/pull/14) ## [0.1.4] - 2020-01-20 -- [Support ?Sized bounds in generic parameters.][9] - -[9]: https://github.com/taiki-e/pin-project-lite/pull/9 +- [Support ?Sized bounds in generic parameters.](https://github.com/taiki-e/pin-project-lite/pull/9) ## [0.1.3] - 2020-01-20 -- [Support lifetime bounds in generic parameters.][7] - -[7]: https://github.com/taiki-e/pin-project-lite/pull/7 +- [Support lifetime bounds in generic parameters.](https://github.com/taiki-e/pin-project-lite/pull/7) ## [0.1.2] - 2020-01-05 -- [Support recognizing default generic parameters.][6] - -[6]: https://github.com/taiki-e/pin-project-lite/pull/6 +- [Support recognizing default generic parameters.](https://github.com/taiki-e/pin-project-lite/pull/6) ## [0.1.1] - 2019-11-15 -- [`pin_project!` macro now determines the visibility of the projection type/method is based on the original type.][5] - -[5]: https://github.com/taiki-e/pin-project-lite/pull/5 +- [`pin_project!` macro now determines the visibility of the projection type/method is based on the original type.](https://github.com/taiki-e/pin-project-lite/pull/5) ## [0.1.0] - 2019-10-22 Initial release -[Unreleased]: https://github.com/taiki-e/pin-project-lite/compare/v0.2.1...HEAD +[Unreleased]: https://github.com/taiki-e/pin-project-lite/compare/v0.2.4...HEAD +[0.2.4]: https://github.com/taiki-e/pin-project-lite/compare/v0.2.3...v0.2.4 +[0.2.3]: https://github.com/taiki-e/pin-project-lite/compare/v0.2.2...v0.2.3 +[0.2.2]: https://github.com/taiki-e/pin-project-lite/compare/v0.2.1...v0.2.2 [0.2.1]: https://github.com/taiki-e/pin-project-lite/compare/v0.2.0...v0.2.1 [0.2.0]: https://github.com/taiki-e/pin-project-lite/compare/v0.1.11...v0.2.0 [0.1.11]: https://github.com/taiki-e/pin-project-lite/compare/v0.1.10...v0.1.11 @@ -13,7 +13,7 @@ [package] edition = "2018" name = "pin-project-lite" -version = "0.2.1" +version = "0.2.4" authors = ["Taiki Endo <te316e89@gmail.com>"] exclude = ["/.github", "/scripts"] description = "A lightweight version of pin-project written with declarative macros.\n" diff --git a/Cargo.toml.orig b/Cargo.toml.orig index 539de51..a909043 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -1,6 +1,6 @@ [package] name = "pin-project-lite" -version = "0.2.1" +version = "0.2.4" authors = ["Taiki Endo <te316e89@gmail.com>"] edition = "2018" license = "Apache-2.0 OR MIT" @@ -7,13 +7,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/pin-project-lite/pin-project-lite-0.2.1.crate" + value: "https://static.crates.io/crates/pin-project-lite/pin-project-lite-0.2.4.crate" } - version: "0.2.1" + version: "0.2.4" license_type: NOTICE last_upgrade_date { year: 2021 month: 1 - day: 5 + day: 11 } } @@ -105,7 +105,6 @@ allow(dead_code, unused_variables) ) ))] -#![warn(unsafe_code)] #![warn(future_incompatible, rust_2018_idioms, single_use_lifetimes, unreachable_pub)] #![warn(clippy::all, clippy::default_trait_access)] @@ -157,6 +156,18 @@ extern crate std; /// } /// ``` /// +/// By passing the `#[project_replace = MyProjReplace]` attribute you may create an additional +/// method which allows the contents of `Pin<&mut Self>` to be replaced while simultaneously moving +/// out all unpinned fields in `Self`. +/// +/// ```rust +/// # use std::pin::Pin; +/// # type MyProjReplace = (); +/// # trait Dox { +/// fn project_replace(self: Pin<&mut Self>, replacement: Self) -> MyProjReplace; +/// # } +/// ``` +/// /// The `#[project]` (and `#[project_ref]`) attribute must precede the other /// attributes except for `#[doc]`. For example, the following code will not be compiled: /// @@ -302,10 +313,47 @@ macro_rules! pin_project { $(#[doc $($doc:tt)*])* #[project = $proj_mut_ident:ident] #[project_ref = $proj_ref_ident:ident] + #[project_replace = $proj_replace_ident:ident] + $($tt:tt)* + ) => { + $crate::__pin_project_internal! { + [$proj_mut_ident][$proj_ref_ident][$proj_replace_ident] + $(#[doc $($doc)*])* + $($tt)* + } + }; + ( + $(#[doc $($doc:tt)*])* + #[project = $proj_mut_ident:ident] + #[project_ref = $proj_ref_ident:ident] + $($tt:tt)* + ) => { + $crate::__pin_project_internal! { + [$proj_mut_ident][$proj_ref_ident][] + $(#[doc $($doc)*])* + $($tt)* + } + }; + ( + $(#[doc $($doc:tt)*])* + #[project = $proj_mut_ident:ident] + #[project_replace = $proj_replace_ident:ident] + $($tt:tt)* + ) => { + $crate::__pin_project_internal! { + [$proj_mut_ident][][$proj_replace_ident] + $(#[doc $($doc)*])* + $($tt)* + } + }; + ( + $(#[doc $($doc:tt)*])* + #[project_ref = $proj_ref_ident:ident] + #[project_replace = $proj_replace_ident:ident] $($tt:tt)* ) => { $crate::__pin_project_internal! { - [$proj_mut_ident][$proj_ref_ident] + [][$proj_ref_ident][$proj_replace_ident] $(#[doc $($doc)*])* $($tt)* } @@ -316,7 +364,7 @@ macro_rules! pin_project { $($tt:tt)* ) => { $crate::__pin_project_internal! { - [$proj_mut_ident][] + [$proj_mut_ident][][] $(#[doc $($doc)*])* $($tt)* } @@ -327,16 +375,27 @@ macro_rules! pin_project { $($tt:tt)* ) => { $crate::__pin_project_internal! { - [][$proj_ref_ident] + [][$proj_ref_ident][] $(#[doc $($doc)*])* $($tt)* } }; ( + $(#[doc $($doc:tt)*])* + #[project_replace = $proj_replace_ident:ident] $($tt:tt)* ) => { $crate::__pin_project_internal! { - [][] + [][][$proj_replace_ident] + $(#[doc $($doc)*])* + $($tt)* + } + }; + ( + $($tt:tt)* + ) => { + $crate::__pin_project_internal! { + [][][] $($tt)* } }; @@ -360,6 +419,7 @@ macro_rules! __pin_project_internal { (@struct=>internal; [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] + [$($proj_replace_ident:ident)?] [$proj_vis:vis] [$(#[$attrs:meta])* $vis:vis struct $ident:ident] [$($def_generics:tt)*] @@ -407,10 +467,26 @@ macro_rules! __pin_project_internal { ),+ } } + $crate::__pin_project_internal! { @struct=>make_proj_replace_ty=>named; + [$proj_vis] + [$($proj_replace_ident)?] + [make_proj_field_replace] + [$ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + { + $( + $(#[$pin])? + $field_vis $field: $field_ty + ),+ + } + } - #[allow(explicit_outlives_requirements)] + #[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(clippy::redundant_pub_crate)] + // This lint warns of `clippy::*` generated by external macros. + // We allow this lint for compatibility with older compilers. + #[allow(clippy::unknown_clippy_lints)] + #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct. #[allow(clippy::used_underscore_binding)] const _: () = { $crate::__pin_project_internal! { @struct=>make_proj_ty=>unnamed; @@ -439,6 +515,19 @@ macro_rules! __pin_project_internal { ),+ } } + $crate::__pin_project_internal! { @struct=>make_proj_replace_ty=>unnamed; + [$proj_vis] + [$($proj_replace_ident)?][ProjectionReplace] + [make_proj_field_replace] + [$ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + { + $( + $(#[$pin])? + $field_vis $field: $field_ty + ),+ + } + } impl <$($impl_generics)*> $ident <$($ty_generics)*> $(where @@ -468,6 +557,17 @@ macro_rules! __pin_project_internal { ),+ } } + $crate::__pin_project_internal! { @struct=>make_proj_replace_method; + [$proj_vis] + [$($proj_replace_ident)?][ProjectionReplace] + [$($ty_generics)*] + { + $( + $(#[$pin])? + $field_vis $field + ),+ + } + } } $crate::__pin_project_internal! { @make_unpin_impl; @@ -514,6 +614,7 @@ macro_rules! __pin_project_internal { (@enum=>internal; [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] + [$($proj_replace_ident:ident)?] [$proj_vis:vis] [$(#[$attrs:meta])* $vis:vis enum $ident:ident] [$($def_generics:tt)*] @@ -579,8 +680,28 @@ macro_rules! __pin_project_internal { ),+ } } + $crate::__pin_project_internal! { @enum=>make_proj_replace_ty; + [$proj_vis] + [$($proj_replace_ident)?] + [make_proj_field_replace] + [$ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + { + $( + $variant $({ + $( + $(#[$pin])? + $field: $field_ty + ),+ + })? + ),+ + } + } #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + // This lint warns of `clippy::*` generated by external macros. + // We allow this lint for compatibility with older compilers. + #[allow(clippy::unknown_clippy_lints)] #[allow(clippy::used_underscore_binding)] const _: () = { impl <$($impl_generics)*> $ident <$($ty_generics)*> @@ -619,6 +740,21 @@ macro_rules! __pin_project_internal { ),+ } } + $crate::__pin_project_internal! { @enum=>make_proj_replace_method; + [$proj_vis] + [$($proj_replace_ident)?] + [$($ty_generics)*] + { + $( + $variant $({ + $( + $(#[$pin])? + $field + ),+ + })? + ),+ + } + } } $crate::__pin_project_internal! { @make_unpin_impl; @@ -687,8 +823,12 @@ macro_rules! __pin_project_internal { ) => { #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + // This lint warns of `clippy::*` generated by external macros. + // We allow this lint for compatibility with older compilers. + #[allow(clippy::unknown_clippy_lints)] #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. (only needed for project) - #[allow(clippy::redundant_pub_crate)] + #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct. + #[allow(clippy::ref_option_ref)] // This lint warns `&Option<&<ty>>`. (only needed for project_ref) #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 $proj_vis struct $proj_ty_ident <'__pin, $($impl_generics)*> where @@ -710,6 +850,61 @@ macro_rules! __pin_project_internal { [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] $($field:tt)* ) => {}; + + (@struct=>make_proj_replace_ty=>unnamed; + [$proj_vis:vis] + [$_proj_ty_ident:ident][$proj_ty_ident:ident] + [$make_proj_field:ident] + [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + $($field:tt)* + ) => {}; + (@struct=>make_proj_replace_ty=>unnamed; + [$proj_vis:vis] + [][$proj_ty_ident:ident] + [$make_proj_field:ident] + [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + $($field:tt)* + ) => { + }; + (@struct=>make_proj_replace_ty=>named; + [$proj_vis:vis] + [$proj_ty_ident:ident] + [$make_proj_field:ident] + [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + { + $( + $(#[$pin:ident])? + $field_vis:vis $field:ident: $field_ty:ty + ),+ + } + ) => { + #[allow(dead_code)] // This lint warns unused fields/variants. + #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. (only needed for project) + #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct. + #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 + $proj_vis struct $proj_ty_ident <$($impl_generics)*> + where + $($($where_clause)*)? + { + $( + $field_vis $field: $crate::__pin_project_internal!(@$make_proj_field; + $(#[$pin])? $field_ty + ) + ),+ + } + }; + (@struct=>make_proj_replace_ty=>named; + [$proj_vis:vis] + [] + [$make_proj_field:ident] + [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + $($field:tt)* + ) => {}; // ============================================================================================= // enum:make_proj_ty (@enum=>make_proj_ty; @@ -731,8 +926,12 @@ macro_rules! __pin_project_internal { ) => { #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + // This lint warns of `clippy::*` generated by external macros. + // We allow this lint for compatibility with older compilers. + #[allow(clippy::unknown_clippy_lints)] #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. (only needed for project) - #[allow(clippy::redundant_pub_crate)] + #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct. + #[allow(clippy::ref_option_ref)] // This lint warns `&Option<&<ty>>`. (only needed for project_ref) #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 $proj_vis enum $proj_ty_ident <'__pin, $($impl_generics)*> where @@ -759,6 +958,86 @@ macro_rules! __pin_project_internal { $($variant:tt)* ) => {}; + (@enum=>make_proj_replace_ty; + [$proj_vis:vis] + [$proj_ty_ident:ident] + [$make_proj_field:ident] + [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + { + $( + $variant:ident $({ + $( + $(#[$pin:ident])? + $field:ident: $field_ty:ty + ),+ + })? + ),+ + } + ) => { + #[allow(dead_code)] // This lint warns unused fields/variants. + #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. (only needed for project) + #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct. + #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 + $proj_vis enum $proj_ty_ident <$($impl_generics)*> + where + $($($where_clause)*)? + { + $( + $variant $({ + $( + $field: $crate::__pin_project_internal!(@$make_proj_field; + $(#[$pin])? $field_ty + ) + ),+ + })? + ),+ + } + }; + (@enum=>make_proj_replace_ty; + [$proj_vis:vis] + [] + [$make_proj_field:ident] + [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + $($variant:tt)* + ) => {}; + + // ============================================================================================= + (@make_proj_replace_block; + [$($proj_path: tt)+] + { + $( + $(#[$pin:ident])? + $field_vis:vis $field:ident + ),+ + } + ) => { + let result = $($proj_path)* { + $( + $field: $crate::__pin_project_internal!(@make_replace_field_proj; + $(#[$pin])? $field + ) + ),+ + }; + + { + ( $( + $crate::__pin_project_internal!(@make_unsafe_drop_in_place_guard; + $(#[$pin])? $field + ), + )* ); + } + + result + }; + (@make_proj_replace_block; + [$($proj_path: tt)+] + ) => { + $($proj_path)* + }; + // ============================================================================================= // struct:make_proj_method (@struct=>make_proj_method; @@ -803,6 +1082,54 @@ macro_rules! __pin_project_internal { $($variant)* } }; + + (@struct=>make_proj_replace_method; + [$proj_vis:vis] + [$proj_ty_ident:ident][$_proj_ty_ident:ident] + [$($ty_generics:tt)*] + { + $( + $(#[$pin:ident])? + $field_vis:vis $field:ident + ),+ + } + ) => { + $proj_vis fn project_replace( + self: $crate::__private::Pin<&mut Self>, + replacement: Self, + ) -> $proj_ty_ident <$($ty_generics)*> { + unsafe { + let __self_ptr: *mut Self = self.get_unchecked_mut(); + + // Destructors will run in reverse order, so next create a guard to overwrite + // `self` with the replacement value without calling destructors. + let __guard = $crate::__private::UnsafeOverwriteGuard { + target: __self_ptr, + value: $crate::__private::ManuallyDrop::new(replacement), + }; + + let Self { $($field),* } = &mut *__self_ptr; + + $crate::__pin_project_internal!{@make_proj_replace_block; + [$proj_ty_ident] + { + $( + $(#[$pin])? + $field + ),+ + } + } + } + } + }; + (@struct=>make_proj_replace_method; + [$proj_vis:vis] + [][$proj_ty_ident:ident] + [$($ty_generics:tt)*] + $($variant:tt)* + ) => { + }; + // ============================================================================================= // enum:make_proj_method (@enum=>make_proj_method; @@ -852,6 +1179,62 @@ macro_rules! __pin_project_internal { $($variant:tt)* ) => {}; + (@enum=>make_proj_replace_method; + [$proj_vis:vis] + [$proj_ty_ident:ident] + [$($ty_generics:tt)*] + { + $( + $variant:ident $({ + $( + $(#[$pin:ident])? + $field:ident + ),+ + })? + ),+ + } + ) => { + $proj_vis fn project_replace( + self: $crate::__private::Pin<&mut Self>, + replacement: Self, + ) -> $proj_ty_ident <$($ty_generics)*> { + unsafe { + let __self_ptr: *mut Self = self.get_unchecked_mut(); + + // Destructors will run in reverse order, so next create a guard to overwrite + // `self` with the replacement value without calling destructors. + let __guard = $crate::__private::UnsafeOverwriteGuard { + target: __self_ptr, + value: $crate::__private::ManuallyDrop::new(replacement), + }; + + match &mut *__self_ptr { + $( + Self::$variant $({ + $($field),+ + })? => { + $crate::__pin_project_internal!{@make_proj_replace_block; + [$proj_ty_ident :: $variant] + $({ + $( + $(#[$pin])? + $field + ),+ + })? + } + } + ),+ + } + } + } + }; + (@enum=>make_proj_replace_method; + [$proj_vis:vis] + [] + [$($ty_generics:tt)*] + $($variant:tt)* + ) => {}; + // ============================================================================================= // make_unpin_impl (@make_unpin_impl; @@ -954,6 +1337,35 @@ macro_rules! __pin_project_internal { }; // ============================================================================================= + // make_replace_field_proj + (@make_replace_field_proj; + #[pin] + $field:ident + ) => { + $crate::__private::PhantomData + }; + (@make_replace_field_proj; + $field:ident + ) => { + $crate::__private::ptr::read($field) + }; + + + // ============================================================================================= + // make_unsafe_drop_in_place_guard + (@make_unsafe_drop_in_place_guard; + #[pin] + $field:ident + ) => { + $crate::__private::UnsafeDropInPlaceGuard($field) + }; + (@make_unsafe_drop_in_place_guard; + $field:ident + ) => { + () + }; + + // ============================================================================================= // make_proj_field (@make_proj_field_mut; #[pin] @@ -978,12 +1390,25 @@ macro_rules! __pin_project_internal { &'__pin ($field_ty) }; + (@make_proj_field_replace; + #[pin] + $field_ty:ty + ) => { + $crate::__private::PhantomData<$field_ty> + }; + (@make_proj_field_replace; + $field_ty:ty + ) => { + $field_ty + }; + // ============================================================================================= // Parses input and determines visibility // struct ( [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] + [$($proj_replace_ident:ident)?] $(#[$attrs:meta])* pub struct $ident:ident $(< @@ -1012,6 +1437,7 @@ macro_rules! __pin_project_internal { $crate::__pin_project_internal! { @struct=>internal; [$($proj_mut_ident)?] [$($proj_ref_ident)?] + [$($proj_replace_ident)?] [pub(crate)] [$(#[$attrs])* pub struct $ident] [$(< @@ -1048,6 +1474,7 @@ macro_rules! __pin_project_internal { ( [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] + [$($proj_replace_ident:ident)?] $(#[$attrs:meta])* $vis:vis struct $ident:ident $(< @@ -1076,6 +1503,7 @@ macro_rules! __pin_project_internal { $crate::__pin_project_internal! { @struct=>internal; [$($proj_mut_ident)?] [$($proj_ref_ident)?] + [$($proj_replace_ident)?] [$vis] [$(#[$attrs])* $vis struct $ident] [$(< @@ -1113,6 +1541,7 @@ macro_rules! __pin_project_internal { ( [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] + [$($proj_replace_ident:ident)?] $(#[$attrs:meta])* pub enum $ident:ident $(< @@ -1146,6 +1575,7 @@ macro_rules! __pin_project_internal { $crate::__pin_project_internal! { @enum=>internal; [$($proj_mut_ident)?] [$($proj_ref_ident)?] + [$($proj_replace_ident)?] [pub(crate)] [$(#[$attrs])* pub enum $ident] [$(< @@ -1187,6 +1617,7 @@ macro_rules! __pin_project_internal { ( [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] + [$($proj_replace_ident:ident)?] $(#[$attrs:meta])* $vis:vis enum $ident:ident $(< @@ -1220,6 +1651,7 @@ macro_rules! __pin_project_internal { $crate::__pin_project_internal! { @enum=>internal; [$($proj_mut_ident)?] [$($proj_ref_ident)?] + [$($proj_replace_ident)?] [$vis] [$(#[$attrs])* $vis enum $ident] [$(< @@ -1266,8 +1698,10 @@ pub mod __private { #[doc(hidden)] pub use core::{ marker::{PhantomData, Unpin}, + mem::ManuallyDrop, ops::Drop, pin::Pin, + ptr, }; // This is an internal helper struct used by `pin_project!`. @@ -1275,4 +1709,32 @@ pub mod __private { pub struct AlwaysUnpin<T: ?Sized>(PhantomData<T>); impl<T: ?Sized> Unpin for AlwaysUnpin<T> {} + + // This is an internal helper used to ensure a value is dropped. + #[doc(hidden)] + pub struct UnsafeDropInPlaceGuard<T: ?Sized>(pub *mut T); + + impl<T: ?Sized> Drop for UnsafeDropInPlaceGuard<T> { + fn drop(&mut self) { + unsafe { + ptr::drop_in_place(self.0); + } + } + } + + // This is an internal helper used to ensure a value is overwritten without + // its destructor being called. + #[doc(hidden)] + pub struct UnsafeOverwriteGuard<T> { + pub value: ManuallyDrop<T>, + pub target: *mut T, + } + + impl<T> Drop for UnsafeOverwriteGuard<T> { + fn drop(&mut self) { + unsafe { + ptr::write(self.target, ptr::read(&*self.value)); + } + } + } } diff --git a/src/lib.rs.orig b/src/lib.rs.orig index 8b2283f..ff1e3bf 100644 --- a/src/lib.rs.orig +++ b/src/lib.rs.orig @@ -105,7 +105,6 @@ allow(dead_code, unused_variables) ) ))] -#![warn(unsafe_code)] #![warn(future_incompatible, rust_2018_idioms, single_use_lifetimes, unreachable_pub)] #![warn(clippy::all, clippy::default_trait_access)] @@ -154,6 +153,18 @@ /// } /// ``` /// +/// By passing the `#[project_replace = MyProjReplace]` attribute you may create an additional +/// method which allows the contents of `Pin<&mut Self>` to be replaced while simultaneously moving +/// out all unpinned fields in `Self`. +/// +/// ```rust +/// # use std::pin::Pin; +/// # type MyProjReplace = (); +/// # trait Dox { +/// fn project_replace(self: Pin<&mut Self>, replacement: Self) -> MyProjReplace; +/// # } +/// ``` +/// /// The `#[project]` (and `#[project_ref]`) attribute must precede the other /// attributes except for `#[doc]`. For example, the following code will not be compiled: /// @@ -299,10 +310,47 @@ macro_rules! pin_project { $(#[doc $($doc:tt)*])* #[project = $proj_mut_ident:ident] #[project_ref = $proj_ref_ident:ident] + #[project_replace = $proj_replace_ident:ident] + $($tt:tt)* + ) => { + $crate::__pin_project_internal! { + [$proj_mut_ident][$proj_ref_ident][$proj_replace_ident] + $(#[doc $($doc)*])* + $($tt)* + } + }; + ( + $(#[doc $($doc:tt)*])* + #[project = $proj_mut_ident:ident] + #[project_ref = $proj_ref_ident:ident] + $($tt:tt)* + ) => { + $crate::__pin_project_internal! { + [$proj_mut_ident][$proj_ref_ident][] + $(#[doc $($doc)*])* + $($tt)* + } + }; + ( + $(#[doc $($doc:tt)*])* + #[project = $proj_mut_ident:ident] + #[project_replace = $proj_replace_ident:ident] + $($tt:tt)* + ) => { + $crate::__pin_project_internal! { + [$proj_mut_ident][][$proj_replace_ident] + $(#[doc $($doc)*])* + $($tt)* + } + }; + ( + $(#[doc $($doc:tt)*])* + #[project_ref = $proj_ref_ident:ident] + #[project_replace = $proj_replace_ident:ident] $($tt:tt)* ) => { $crate::__pin_project_internal! { - [$proj_mut_ident][$proj_ref_ident] + [][$proj_ref_ident][$proj_replace_ident] $(#[doc $($doc)*])* $($tt)* } @@ -313,7 +361,7 @@ macro_rules! pin_project { $($tt:tt)* ) => { $crate::__pin_project_internal! { - [$proj_mut_ident][] + [$proj_mut_ident][][] $(#[doc $($doc)*])* $($tt)* } @@ -324,16 +372,27 @@ macro_rules! pin_project { $($tt:tt)* ) => { $crate::__pin_project_internal! { - [][$proj_ref_ident] + [][$proj_ref_ident][] $(#[doc $($doc)*])* $($tt)* } }; ( + $(#[doc $($doc:tt)*])* + #[project_replace = $proj_replace_ident:ident] $($tt:tt)* ) => { $crate::__pin_project_internal! { - [][] + [][][$proj_replace_ident] + $(#[doc $($doc)*])* + $($tt)* + } + }; + ( + $($tt:tt)* + ) => { + $crate::__pin_project_internal! { + [][][] $($tt)* } }; @@ -357,6 +416,7 @@ macro_rules! __pin_project_internal { (@struct=>internal; [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] + [$($proj_replace_ident:ident)?] [$proj_vis:vis] [$(#[$attrs:meta])* $vis:vis struct $ident:ident] [$($def_generics:tt)*] @@ -404,10 +464,26 @@ macro_rules! __pin_project_internal { ),+ } } + $crate::__pin_project_internal! { @struct=>make_proj_replace_ty=>named; + [$proj_vis] + [$($proj_replace_ident)?] + [make_proj_field_replace] + [$ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + { + $( + $(#[$pin])? + $field_vis $field: $field_ty + ),+ + } + } - #[allow(explicit_outlives_requirements)] + #[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(clippy::redundant_pub_crate)] + // This lint warns of `clippy::*` generated by external macros. + // We allow this lint for compatibility with older compilers. + #[allow(clippy::unknown_clippy_lints)] + #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct. #[allow(clippy::used_underscore_binding)] const _: () = { $crate::__pin_project_internal! { @struct=>make_proj_ty=>unnamed; @@ -436,6 +512,19 @@ macro_rules! __pin_project_internal { ),+ } } + $crate::__pin_project_internal! { @struct=>make_proj_replace_ty=>unnamed; + [$proj_vis] + [$($proj_replace_ident)?][ProjectionReplace] + [make_proj_field_replace] + [$ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + { + $( + $(#[$pin])? + $field_vis $field: $field_ty + ),+ + } + } impl <$($impl_generics)*> $ident <$($ty_generics)*> $(where @@ -465,6 +554,17 @@ macro_rules! __pin_project_internal { ),+ } } + $crate::__pin_project_internal! { @struct=>make_proj_replace_method; + [$proj_vis] + [$($proj_replace_ident)?][ProjectionReplace] + [$($ty_generics)*] + { + $( + $(#[$pin])? + $field_vis $field + ),+ + } + } } $crate::__pin_project_internal! { @make_unpin_impl; @@ -511,6 +611,7 @@ macro_rules! __pin_project_internal { (@enum=>internal; [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] + [$($proj_replace_ident:ident)?] [$proj_vis:vis] [$(#[$attrs:meta])* $vis:vis enum $ident:ident] [$($def_generics:tt)*] @@ -576,8 +677,28 @@ macro_rules! __pin_project_internal { ),+ } } + $crate::__pin_project_internal! { @enum=>make_proj_replace_ty; + [$proj_vis] + [$($proj_replace_ident)?] + [make_proj_field_replace] + [$ident] + [$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?] + { + $( + $variant $({ + $( + $(#[$pin])? + $field: $field_ty + ),+ + })? + ),+ + } + } #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + // This lint warns of `clippy::*` generated by external macros. + // We allow this lint for compatibility with older compilers. + #[allow(clippy::unknown_clippy_lints)] #[allow(clippy::used_underscore_binding)] const _: () = { impl <$($impl_generics)*> $ident <$($ty_generics)*> @@ -616,6 +737,21 @@ macro_rules! __pin_project_internal { ),+ } } + $crate::__pin_project_internal! { @enum=>make_proj_replace_method; + [$proj_vis] + [$($proj_replace_ident)?] + [$($ty_generics)*] + { + $( + $variant $({ + $( + $(#[$pin])? + $field + ),+ + })? + ),+ + } + } } $crate::__pin_project_internal! { @make_unpin_impl; @@ -684,8 +820,12 @@ macro_rules! __pin_project_internal { ) => { #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + // This lint warns of `clippy::*` generated by external macros. + // We allow this lint for compatibility with older compilers. + #[allow(clippy::unknown_clippy_lints)] #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. (only needed for project) - #[allow(clippy::redundant_pub_crate)] + #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct. + #[allow(clippy::ref_option_ref)] // This lint warns `&Option<&<ty>>`. (only needed for project_ref) #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 $proj_vis struct $proj_ty_ident <'__pin, $($impl_generics)*> where @@ -707,6 +847,61 @@ macro_rules! __pin_project_internal { [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] $($field:tt)* ) => {}; + + (@struct=>make_proj_replace_ty=>unnamed; + [$proj_vis:vis] + [$_proj_ty_ident:ident][$proj_ty_ident:ident] + [$make_proj_field:ident] + [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + $($field:tt)* + ) => {}; + (@struct=>make_proj_replace_ty=>unnamed; + [$proj_vis:vis] + [][$proj_ty_ident:ident] + [$make_proj_field:ident] + [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + $($field:tt)* + ) => { + }; + (@struct=>make_proj_replace_ty=>named; + [$proj_vis:vis] + [$proj_ty_ident:ident] + [$make_proj_field:ident] + [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + { + $( + $(#[$pin:ident])? + $field_vis:vis $field:ident: $field_ty:ty + ),+ + } + ) => { + #[allow(dead_code)] // This lint warns unused fields/variants. + #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. (only needed for project) + #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct. + #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 + $proj_vis struct $proj_ty_ident <$($impl_generics)*> + where + $($($where_clause)*)? + { + $( + $field_vis $field: $crate::__pin_project_internal!(@$make_proj_field; + $(#[$pin])? $field_ty + ) + ),+ + } + }; + (@struct=>make_proj_replace_ty=>named; + [$proj_vis:vis] + [] + [$make_proj_field:ident] + [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + $($field:tt)* + ) => {}; // ============================================================================================= // enum:make_proj_ty (@enum=>make_proj_ty; @@ -728,8 +923,12 @@ macro_rules! __pin_project_internal { ) => { #[allow(dead_code)] // This lint warns unused fields/variants. #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + // This lint warns of `clippy::*` generated by external macros. + // We allow this lint for compatibility with older compilers. + #[allow(clippy::unknown_clippy_lints)] #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. (only needed for project) - #[allow(clippy::redundant_pub_crate)] + #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct. + #[allow(clippy::ref_option_ref)] // This lint warns `&Option<&<ty>>`. (only needed for project_ref) #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 $proj_vis enum $proj_ty_ident <'__pin, $($impl_generics)*> where @@ -756,6 +955,86 @@ macro_rules! __pin_project_internal { $($variant:tt)* ) => {}; + (@enum=>make_proj_replace_ty; + [$proj_vis:vis] + [$proj_ty_ident:ident] + [$make_proj_field:ident] + [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + { + $( + $variant:ident $({ + $( + $(#[$pin:ident])? + $field:ident: $field_ty:ty + ),+ + })? + ),+ + } + ) => { + #[allow(dead_code)] // This lint warns unused fields/variants. + #[allow(single_use_lifetimes)] // https://github.com/rust-lang/rust/issues/55058 + #[allow(clippy::mut_mut)] // This lint warns `&mut &mut <ty>`. (only needed for project) + #[allow(clippy::redundant_pub_crate)] // This lint warns `pub(crate)` field in private struct. + #[allow(clippy::type_repetition_in_bounds)] // https://github.com/rust-lang/rust-clippy/issues/4326 + $proj_vis enum $proj_ty_ident <$($impl_generics)*> + where + $($($where_clause)*)? + { + $( + $variant $({ + $( + $field: $crate::__pin_project_internal!(@$make_proj_field; + $(#[$pin])? $field_ty + ) + ),+ + })? + ),+ + } + }; + (@enum=>make_proj_replace_ty; + [$proj_vis:vis] + [] + [$make_proj_field:ident] + [$ident:ident] + [$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?] + $($variant:tt)* + ) => {}; + + // ============================================================================================= + (@make_proj_replace_block; + [$($proj_path: tt)+] + { + $( + $(#[$pin:ident])? + $field_vis:vis $field:ident + ),+ + } + ) => { + let result = $($proj_path)* { + $( + $field: $crate::__pin_project_internal!(@make_replace_field_proj; + $(#[$pin])? $field + ) + ),+ + }; + + { + ( $( + $crate::__pin_project_internal!(@make_unsafe_drop_in_place_guard; + $(#[$pin])? $field + ), + )* ); + } + + result + }; + (@make_proj_replace_block; + [$($proj_path: tt)+] + ) => { + $($proj_path)* + }; + // ============================================================================================= // struct:make_proj_method (@struct=>make_proj_method; @@ -800,6 +1079,54 @@ macro_rules! __pin_project_internal { $($variant)* } }; + + (@struct=>make_proj_replace_method; + [$proj_vis:vis] + [$proj_ty_ident:ident][$_proj_ty_ident:ident] + [$($ty_generics:tt)*] + { + $( + $(#[$pin:ident])? + $field_vis:vis $field:ident + ),+ + } + ) => { + $proj_vis fn project_replace( + self: $crate::__private::Pin<&mut Self>, + replacement: Self, + ) -> $proj_ty_ident <$($ty_generics)*> { + unsafe { + let __self_ptr: *mut Self = self.get_unchecked_mut(); + + // Destructors will run in reverse order, so next create a guard to overwrite + // `self` with the replacement value without calling destructors. + let __guard = $crate::__private::UnsafeOverwriteGuard { + target: __self_ptr, + value: $crate::__private::ManuallyDrop::new(replacement), + }; + + let Self { $($field),* } = &mut *__self_ptr; + + $crate::__pin_project_internal!{@make_proj_replace_block; + [$proj_ty_ident] + { + $( + $(#[$pin])? + $field + ),+ + } + } + } + } + }; + (@struct=>make_proj_replace_method; + [$proj_vis:vis] + [][$proj_ty_ident:ident] + [$($ty_generics:tt)*] + $($variant:tt)* + ) => { + }; + // ============================================================================================= // enum:make_proj_method (@enum=>make_proj_method; @@ -849,6 +1176,62 @@ macro_rules! __pin_project_internal { $($variant:tt)* ) => {}; + (@enum=>make_proj_replace_method; + [$proj_vis:vis] + [$proj_ty_ident:ident] + [$($ty_generics:tt)*] + { + $( + $variant:ident $({ + $( + $(#[$pin:ident])? + $field:ident + ),+ + })? + ),+ + } + ) => { + $proj_vis fn project_replace( + self: $crate::__private::Pin<&mut Self>, + replacement: Self, + ) -> $proj_ty_ident <$($ty_generics)*> { + unsafe { + let __self_ptr: *mut Self = self.get_unchecked_mut(); + + // Destructors will run in reverse order, so next create a guard to overwrite + // `self` with the replacement value without calling destructors. + let __guard = $crate::__private::UnsafeOverwriteGuard { + target: __self_ptr, + value: $crate::__private::ManuallyDrop::new(replacement), + }; + + match &mut *__self_ptr { + $( + Self::$variant $({ + $($field),+ + })? => { + $crate::__pin_project_internal!{@make_proj_replace_block; + [$proj_ty_ident :: $variant] + $({ + $( + $(#[$pin])? + $field + ),+ + })? + } + } + ),+ + } + } + } + }; + (@enum=>make_proj_replace_method; + [$proj_vis:vis] + [] + [$($ty_generics:tt)*] + $($variant:tt)* + ) => {}; + // ============================================================================================= // make_unpin_impl (@make_unpin_impl; @@ -951,6 +1334,35 @@ macro_rules! __pin_project_internal { }; // ============================================================================================= + // make_replace_field_proj + (@make_replace_field_proj; + #[pin] + $field:ident + ) => { + $crate::__private::PhantomData + }; + (@make_replace_field_proj; + $field:ident + ) => { + $crate::__private::ptr::read($field) + }; + + + // ============================================================================================= + // make_unsafe_drop_in_place_guard + (@make_unsafe_drop_in_place_guard; + #[pin] + $field:ident + ) => { + $crate::__private::UnsafeDropInPlaceGuard($field) + }; + (@make_unsafe_drop_in_place_guard; + $field:ident + ) => { + () + }; + + // ============================================================================================= // make_proj_field (@make_proj_field_mut; #[pin] @@ -975,12 +1387,25 @@ macro_rules! __pin_project_internal { &'__pin ($field_ty) }; + (@make_proj_field_replace; + #[pin] + $field_ty:ty + ) => { + $crate::__private::PhantomData<$field_ty> + }; + (@make_proj_field_replace; + $field_ty:ty + ) => { + $field_ty + }; + // ============================================================================================= // Parses input and determines visibility // struct ( [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] + [$($proj_replace_ident:ident)?] $(#[$attrs:meta])* pub struct $ident:ident $(< @@ -1009,6 +1434,7 @@ macro_rules! __pin_project_internal { $crate::__pin_project_internal! { @struct=>internal; [$($proj_mut_ident)?] [$($proj_ref_ident)?] + [$($proj_replace_ident)?] [pub(crate)] [$(#[$attrs])* pub struct $ident] [$(< @@ -1045,6 +1471,7 @@ macro_rules! __pin_project_internal { ( [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] + [$($proj_replace_ident:ident)?] $(#[$attrs:meta])* $vis:vis struct $ident:ident $(< @@ -1073,6 +1500,7 @@ macro_rules! __pin_project_internal { $crate::__pin_project_internal! { @struct=>internal; [$($proj_mut_ident)?] [$($proj_ref_ident)?] + [$($proj_replace_ident)?] [$vis] [$(#[$attrs])* $vis struct $ident] [$(< @@ -1110,6 +1538,7 @@ macro_rules! __pin_project_internal { ( [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] + [$($proj_replace_ident:ident)?] $(#[$attrs:meta])* pub enum $ident:ident $(< @@ -1143,6 +1572,7 @@ macro_rules! __pin_project_internal { $crate::__pin_project_internal! { @enum=>internal; [$($proj_mut_ident)?] [$($proj_ref_ident)?] + [$($proj_replace_ident)?] [pub(crate)] [$(#[$attrs])* pub enum $ident] [$(< @@ -1184,6 +1614,7 @@ macro_rules! __pin_project_internal { ( [$($proj_mut_ident:ident)?] [$($proj_ref_ident:ident)?] + [$($proj_replace_ident:ident)?] $(#[$attrs:meta])* $vis:vis enum $ident:ident $(< @@ -1217,6 +1648,7 @@ macro_rules! __pin_project_internal { $crate::__pin_project_internal! { @enum=>internal; [$($proj_mut_ident)?] [$($proj_ref_ident)?] + [$($proj_replace_ident)?] [$vis] [$(#[$attrs])* $vis enum $ident] [$(< @@ -1263,8 +1695,10 @@ pub mod __private { #[doc(hidden)] pub use core::{ marker::{PhantomData, Unpin}, + mem::ManuallyDrop, ops::Drop, pin::Pin, + ptr, }; // This is an internal helper struct used by `pin_project!`. @@ -1272,4 +1706,32 @@ pub mod __private { pub struct AlwaysUnpin<T: ?Sized>(PhantomData<T>); impl<T: ?Sized> Unpin for AlwaysUnpin<T> {} + + // This is an internal helper used to ensure a value is dropped. + #[doc(hidden)] + pub struct UnsafeDropInPlaceGuard<T: ?Sized>(pub *mut T); + + impl<T: ?Sized> Drop for UnsafeDropInPlaceGuard<T> { + fn drop(&mut self) { + unsafe { + ptr::drop_in_place(self.0); + } + } + } + + // This is an internal helper used to ensure a value is overwritten without + // its destructor being called. + #[doc(hidden)] + pub struct UnsafeOverwriteGuard<T> { + pub value: ManuallyDrop<T>, + pub target: *mut T, + } + + impl<T> Drop for UnsafeOverwriteGuard<T> { + fn drop(&mut self) { + unsafe { + ptr::write(self.target, ptr::read(&*self.value)); + } + } + } } diff --git a/tests/compiletest.rs b/tests/compiletest.rs index af75bc5..5a91b20 100644 --- a/tests/compiletest.rs +++ b/tests/compiletest.rs @@ -1,3 +1,4 @@ +#![cfg(not(miri))] #![warn(rust_2018_idioms, single_use_lifetimes)] use std::env; diff --git a/tests/drop_order.rs b/tests/drop_order.rs new file mode 100644 index 0000000..d84c324 --- /dev/null +++ b/tests/drop_order.rs @@ -0,0 +1,168 @@ +#![warn(rust_2018_idioms, single_use_lifetimes)] + +// Refs: https://doc.rust-lang.org/reference/destructors.html + +use pin_project_lite::pin_project; +use std::{cell::Cell, panic, pin::Pin, thread}; + +struct D<'a>(&'a Cell<usize>, usize); + +impl Drop for D<'_> { + fn drop(&mut self) { + if !thread::panicking() { + let old = self.0.replace(self.1); + assert_eq!(old, self.1 - 1); + } + } +} + +pin_project! { +#[project = StructPinnedProj] +#[project_ref = StructPinnedProjRef] +#[project_replace = StructPinnedProjReplace] +struct StructPinned<'a> { + #[pin] + f1: D<'a>, + #[pin] + f2: D<'a>, +} +} + +pin_project! { +#[project = StructUnpinnedProj] +#[project_ref = StructUnpinnedProjRef] +#[project_replace = StructUnpinnedProjReplace] +struct StructUnpinned<'a> { + f1: D<'a>, + f2: D<'a>, +} +} + +pin_project! { +#[project_replace = EnumProjReplace] +enum Enum<'a> { + #[allow(dead_code)] // false positive that fixed in Rust 1.38 + StructPinned { + #[pin] + f1: D<'a>, + #[pin] + f2: D<'a>, + }, + #[allow(dead_code)] // false positive that fixed in Rust 1.38 + StructUnpinned { + f1: D<'a>, + f2: D<'a>, + }, +} +} + +#[test] +fn struct_pinned() { + { + let c = Cell::new(0); + let _x = StructPinned { f1: D(&c, 1), f2: D(&c, 2) }; + } + { + let c = Cell::new(0); + let mut x = StructPinned { f1: D(&c, 1), f2: D(&c, 2) }; + let y = Pin::new(&mut x); + let _z = y.project_replace(StructPinned { f1: D(&c, 3), f2: D(&c, 4) }); + } +} + +#[test] +fn struct_unpinned() { + { + let c = Cell::new(0); + let _x = StructUnpinned { f1: D(&c, 1), f2: D(&c, 2) }; + } + { + let c = Cell::new(0); + let mut x = StructUnpinned { f1: D(&c, 1), f2: D(&c, 2) }; + let y = Pin::new(&mut x); + let _z = y.project_replace(StructUnpinned { f1: D(&c, 3), f2: D(&c, 4) }); + } +} + +#[test] +fn enum_struct() { + { + let c = Cell::new(0); + let _x = Enum::StructPinned { f1: D(&c, 1), f2: D(&c, 2) }; + } + { + let c = Cell::new(0); + let mut x = Enum::StructPinned { f1: D(&c, 1), f2: D(&c, 2) }; + let y = Pin::new(&mut x); + let _z = y.project_replace(Enum::StructPinned { f1: D(&c, 3), f2: D(&c, 4) }); + } + + { + let c = Cell::new(0); + let _x = Enum::StructUnpinned { f1: D(&c, 1), f2: D(&c, 2) }; + } + { + let c = Cell::new(0); + let mut x = Enum::StructUnpinned { f1: D(&c, 1), f2: D(&c, 2) }; + let y = Pin::new(&mut x); + let _z = y.project_replace(Enum::StructUnpinned { f1: D(&c, 3), f2: D(&c, 4) }); + } +} + +// https://github.com/rust-lang/rust/issues/47949 +// https://github.com/taiki-e/pin-project/pull/194#discussion_r419098111 +#[allow(clippy::many_single_char_names)] +#[test] +fn project_replace_panic() { + pin_project! { + #[project_replace = SProjReplace] + struct S<T, U> { + #[pin] + pinned: T, + unpinned: U, + } + } + + struct D<'a>(&'a mut bool, bool); + impl Drop for D<'_> { + fn drop(&mut self) { + *self.0 = true; + if self.1 { + panic!() + } + } + } + + let (mut a, mut b, mut c, mut d) = (false, false, false, false); + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { + let mut x = S { pinned: D(&mut a, true), unpinned: D(&mut b, false) }; + let _y = Pin::new(&mut x) + .project_replace(S { pinned: D(&mut c, false), unpinned: D(&mut d, false) }); + // Previous `x.pinned` was dropped and panicked when `project_replace` is + // called, so this is unreachable. + unreachable!(); + })); + assert!(res.is_err()); + assert!(a); + assert!(b); + assert!(c); + assert!(d); + + let (mut a, mut b, mut c, mut d) = (false, false, false, false); + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| { + let mut x = S { pinned: D(&mut a, false), unpinned: D(&mut b, true) }; + { + let _y = Pin::new(&mut x) + .project_replace(S { pinned: D(&mut c, false), unpinned: D(&mut d, false) }); + // `_y` (previous `x.unpinned`) live to the end of this scope, so + // this is not unreachable. + // unreachable!(); + } + unreachable!(); + })); + assert!(res.is_err()); + assert!(a); + assert!(b); + assert!(c); + assert!(d); +} diff --git a/tests/lint.rs b/tests/lint.rs index bbc3033..46ec1df 100644 --- a/tests/lint.rs +++ b/tests/lint.rs @@ -40,8 +40,6 @@ // Check interoperability with rustc and clippy lints. -mod auxiliary; - pub mod basic { include!("include/basic.rs"); } @@ -238,3 +236,27 @@ pub mod clippy_used_underscore_binding { } } } + +pub mod clippy_ref_option_ref { + use pin_project_lite::pin_project; + + pin_project! { + pub struct Struct<'a> { + #[pin] + pub _pinned: Option<&'a ()>, + pub _unpinned: Option<&'a ()>, + } + } + + pin_project! { + #[project = EnumProj] + #[project_ref = EnumProjRef] + pub enum Enum<'a> { + Struct { + #[pin] + _pinned: Option<&'a ()>, + _unpinned: Option<&'a ()>, + }, + } + } +} diff --git a/tests/test.rs b/tests/test.rs index cd4f48b..f4c29ee 100644 --- a/tests/test.rs +++ b/tests/test.rs @@ -4,7 +4,10 @@ #[macro_use] mod auxiliary; -use core::{marker::PhantomPinned, pin::Pin}; +use core::{ + marker::{PhantomData, PhantomPinned}, + pin::Pin, +}; use pin_project_lite::pin_project; #[test] @@ -12,6 +15,8 @@ fn projection() { pin_project! { #[project = StructProj] #[project_ref = StructProjRef] + #[project_replace = StructProjReplace] + #[derive(Default)] struct Struct<T, U> { #[pin] f1: T, @@ -44,9 +49,19 @@ fn projection() { let _: &i32 = f2; } + { + let StructProjReplace { f1: PhantomData, f2 } = + s.as_mut().project_replace(Default::default()); + assert_eq!(f2, 2); + let StructProj { f1, f2 } = s.project(); + assert_eq!(*f1, 0); + assert_eq!(*f2, 0); + } + pin_project! { #[project = EnumProj] #[project_ref = EnumProjRef] + #[project_replace = EnumProjReplace] #[derive(Eq, PartialEq, Debug)] enum Enum<C, D> { Struct { @@ -79,6 +94,11 @@ fn projection() { let _: &mut i32 = f2; assert_eq!(*f2, 2); } + + if let EnumProjReplace::Struct { f1: PhantomData, f2 } = e.as_mut().project_replace(Enum::Unit) + { + assert_eq!(f2, 2); + } } #[test] |