aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaibo Huang <hhb@google.com>2021-01-12 12:42:47 +0000
committerAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>2021-01-12 12:42:47 +0000
commit706307e81bd30f3603b2af6280e475cc85fb1c0b (patch)
treeb8994b238055e12f5341f5a786ef9823e51d6491
parentf307beb3ec3abce3be485d39a07912f2f78df48a (diff)
parent209c5ede38dde24c6d38b8e6286504337b8b7b60 (diff)
downloadpin-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.json2
-rw-r--r--CHANGELOG.md58
-rw-r--r--Cargo.toml2
-rw-r--r--Cargo.toml.orig2
-rw-r--r--METADATA6
-rw-r--r--src/lib.rs480
-rw-r--r--src/lib.rs.orig480
-rw-r--r--tests/compiletest.rs1
-rw-r--r--tests/drop_order.rs168
-rw-r--r--tests/lint.rs26
-rw-r--r--tests/test.rs22
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
diff --git a/Cargo.toml b/Cargo.toml
index 7538f02..92774c9 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -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"
diff --git a/METADATA b/METADATA
index 4d7b0bc..24edb01 100644
--- a/METADATA
+++ b/METADATA
@@ -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
}
}
diff --git a/src/lib.rs b/src/lib.rs
index b56c71f..3e3ef70 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -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]