Skip to content

Commit 574ccbb

Browse files
committed
Support custom Drop implementation
1 parent 87eb119 commit 574ccbb

File tree

11 files changed

+464
-12
lines changed

11 files changed

+464
-12
lines changed

README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,6 @@ be useful in most cases. If you do need useful error messages, then upon
100100
error you can pass the same input to [pin-project] to receive a helpful
101101
description of the compile error.
102102

103-
### Different: No support for custom Drop implementation
104-
105-
pin-project supports this by [`#[pinned_drop]`][pinned-drop].
106-
107103
### Different: No support for custom Unpin implementation
108104

109105
pin-project supports this by [`UnsafeUnpin`][unsafe-unpin] and [`!Unpin`][not-unpin].
@@ -115,7 +111,6 @@ pin-project supports this.
115111
[`pin_project!`]: https://docs.rs/pin-project-lite/0.2/pin_project_lite/macro.pin_project.html
116112
[not-unpin]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#unpin
117113
[pin-project]: https://github.com/taiki-e/pin-project
118-
[pinned-drop]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#pinned_drop
119114
[unsafe-unpin]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#unsafeunpin
120115

121116
## License

src/lib.rs

Lines changed: 106 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,6 @@
8282
//! error you can pass the same input to [pin-project] to receive a helpful
8383
//! description of the compile error.
8484
//!
85-
//! ## Different: No support for custom Drop implementation
86-
//!
87-
//! pin-project supports this by [`#[pinned_drop]`][pinned-drop].
88-
//!
8985
//! ## Different: No support for custom Unpin implementation
9086
//!
9187
//! pin-project supports this by [`UnsafeUnpin`][unsafe-unpin] and [`!Unpin`][not-unpin].
@@ -96,7 +92,6 @@
9692
//!
9793
//! [not-unpin]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#unpin
9894
//! [pin-project]: https://github.com/taiki-e/pin-project
99-
//! [pinned-drop]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#pinned_drop
10095
//! [unsafe-unpin]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#unsafeunpin
10196
10297
#![no_std]
@@ -331,6 +326,7 @@ macro_rules! __pin_project_internal {
331326
$field_vis:vis $field:ident: $field_ty:ty
332327
),+
333328
}
329+
$(impl $($pinned_drop:tt)*)?
334330
) => {
335331
$(#[$attrs])*
336332
$vis struct $ident $($def_generics)*
@@ -374,6 +370,7 @@ macro_rules! __pin_project_internal {
374370
[make_proj_field_replace]
375371
[$ident]
376372
[$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
373+
[$(impl $($pinned_drop)*)?]
377374
{
378375
$(
379376
$(#[$pin])?
@@ -422,6 +419,7 @@ macro_rules! __pin_project_internal {
422419
[make_proj_field_replace]
423420
[$ident]
424421
[$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
422+
[$(impl $($pinned_drop)*)?]
425423
{
426424
$(
427425
$(#[$pin])?
@@ -484,6 +482,7 @@ macro_rules! __pin_project_internal {
484482
$crate::__pin_project_internal! { @make_drop_impl;
485483
[$ident]
486484
[$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
485+
$(impl $($pinned_drop)*)?
487486
}
488487

489488
// Ensure that it's impossible to use pin projections on a #[repr(packed)] struct.
@@ -538,6 +537,7 @@ macro_rules! __pin_project_internal {
538537
})?
539538
),+
540539
}
540+
$(impl $($pinned_drop:tt)*)?
541541
) => {
542542
$(#[$attrs])*
543543
$vis enum $ident $($def_generics)*
@@ -594,6 +594,7 @@ macro_rules! __pin_project_internal {
594594
[make_proj_field_replace]
595595
[$ident]
596596
[$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
597+
[$(impl $($pinned_drop)*)?]
597598
{
598599
$(
599600
$variant $({
@@ -682,6 +683,7 @@ macro_rules! __pin_project_internal {
682683
$crate::__pin_project_internal! { @make_drop_impl;
683684
[$ident]
684685
[$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
686+
$(impl $($pinned_drop)*)?
685687
}
686688

687689
// We don't need to check for '#[repr(packed)]',
@@ -765,6 +767,7 @@ macro_rules! __pin_project_internal {
765767
[$make_proj_field:ident]
766768
[$ident:ident]
767769
[$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
770+
[$(impl $($pinned_drop:tt)*)?]
768771
$($field:tt)*
769772
) => {};
770773
(@struct=>make_proj_replace_ty=>unnamed;
@@ -773,15 +776,16 @@ macro_rules! __pin_project_internal {
773776
[$make_proj_field:ident]
774777
[$ident:ident]
775778
[$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
779+
[$(impl $($pinned_drop:tt)*)?]
776780
$($field:tt)*
777-
) => {
778-
};
781+
) => {};
779782
(@struct=>make_proj_replace_ty=>named;
780783
[$proj_vis:vis]
781784
[$proj_ty_ident:ident]
782785
[$make_proj_field:ident]
783786
[$ident:ident]
784787
[$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
788+
[]
785789
{
786790
$(
787791
$(#[$pin:ident])?
@@ -811,6 +815,7 @@ macro_rules! __pin_project_internal {
811815
[$make_proj_field:ident]
812816
[$ident:ident]
813817
[$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
818+
[$(impl $($pinned_drop:tt)*)?]
814819
$($field:tt)*
815820
) => {};
816821
// =============================================================================================
@@ -872,6 +877,7 @@ macro_rules! __pin_project_internal {
872877
[$make_proj_field:ident]
873878
[$ident:ident]
874879
[$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
880+
[]
875881
{
876882
$(
877883
$variant:ident $({
@@ -909,6 +915,7 @@ macro_rules! __pin_project_internal {
909915
[$make_proj_field:ident]
910916
[$ident:ident]
911917
[$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
918+
[$(impl $($pinned_drop:tt)*)?]
912919
$($variant:tt)*
913920
) => {};
914921

@@ -1193,6 +1200,90 @@ macro_rules! __pin_project_internal {
11931200

11941201
// =============================================================================================
11951202
// make_drop_impl
1203+
(@make_drop_impl;
1204+
[$_ident:ident]
1205+
[$($_impl_generics:tt)*] [$($_ty_generics:tt)*] [$(where $($_where_clause:tt)* )?]
1206+
impl $(<
1207+
$( $lifetime:lifetime $(: $lifetime_bound:lifetime)? ),* $(,)?
1208+
$( $generics:ident
1209+
$(: $generics_bound:path)?
1210+
$(: ?$generics_unsized_bound:path)?
1211+
$(: $generics_lifetime_bound:lifetime)?
1212+
),*
1213+
>)? PinnedDrop for $self_ty:ty
1214+
$(where
1215+
$( $where_clause_ty:ty
1216+
$(: $where_clause_bound:path)?
1217+
$(: ?$where_clause_unsized_bound:path)?
1218+
$(: $where_clause_lifetime_bound:lifetime)?
1219+
),*
1220+
)?
1221+
{
1222+
fn drop($($arg:ident)+: Pin<&mut Self>) {
1223+
$($tt:tt)*
1224+
}
1225+
}
1226+
) => {
1227+
impl $(<
1228+
$( $lifetime $(: $lifetime_bound)? ,)*
1229+
$( $generics
1230+
$(: $generics_bound)?
1231+
$(: ?$generics_unsized_bound)?
1232+
$(: $generics_lifetime_bound)?
1233+
),*
1234+
>)? $crate::__private::Drop for $self_ty
1235+
$(where
1236+
$( $where_clause_ty
1237+
$(: $where_clause_bound)?
1238+
$(: ?$where_clause_unsized_bound)?
1239+
$(: $where_clause_lifetime_bound)?
1240+
),*
1241+
)?
1242+
{
1243+
fn drop(&mut self) {
1244+
// Implementing `__DropInner::__drop_inner` is safe, but calling it is not safe.
1245+
// This is because destructors can be called multiple times in safe code and
1246+
// [double dropping is unsound](https://github.com/rust-lang/rust/pull/62360).
1247+
//
1248+
// `__drop_inner` is defined as a safe method, but this is fine since
1249+
// `__drop_inner` is not accessible by the users and we call `__drop_inner` only
1250+
// once.
1251+
//
1252+
// Users can implement [`Drop`] safely using `pin_project!` and can drop a
1253+
// type that implements `PinnedDrop` using the [`drop`] function safely.
1254+
fn __drop_inner $(<
1255+
$( $lifetime $(: $lifetime_bound)? ,)*
1256+
$( $generics
1257+
$(: $generics_bound)?
1258+
$(: ?$generics_unsized_bound)?
1259+
$(: $generics_lifetime_bound)?
1260+
),*
1261+
>)? (
1262+
$($arg)+: $crate::__private::Pin<&mut $self_ty>,
1263+
)
1264+
$(where
1265+
$( $where_clause_ty
1266+
$(: $where_clause_bound)?
1267+
$(: ?$where_clause_unsized_bound)?
1268+
$(: $where_clause_lifetime_bound)?
1269+
),*
1270+
)?
1271+
{
1272+
// A dummy `__drop_inner` function to prevent users call outer `__drop_inner`.
1273+
fn __drop_inner() {}
1274+
$($tt)*
1275+
}
1276+
1277+
// Safety - we're in 'drop', so we know that 'self' will
1278+
// never move again.
1279+
let pinned_self: $crate::__private::Pin<&mut Self>
1280+
= unsafe { $crate::__private::Pin::new_unchecked(self) };
1281+
// We call `__drop_inner` only once. Since `__DropInner::__drop_inner`
1282+
// is not accessible by the users, it is never called again.
1283+
__drop_inner(pinned_self);
1284+
}
1285+
}
1286+
};
11961287
(@make_drop_impl;
11971288
[$ident:ident]
11981289
[$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
@@ -1414,6 +1505,7 @@ macro_rules! __pin_project_internal {
14141505
$field_vis:vis $field:ident: $field_ty:ty
14151506
),+ $(,)?
14161507
}
1508+
$(impl $($pinned_drop:tt)*)?
14171509
) => {
14181510
$crate::__pin_project_internal! { @struct=>internal;
14191511
[$($proj_mut_ident)?]
@@ -1450,6 +1542,7 @@ macro_rules! __pin_project_internal {
14501542
$field_vis $field: $field_ty
14511543
),+
14521544
}
1545+
$(impl $($pinned_drop)*)?
14531546
}
14541547
};
14551548
(
@@ -1480,6 +1573,7 @@ macro_rules! __pin_project_internal {
14801573
$field_vis:vis $field:ident: $field_ty:ty
14811574
),+ $(,)?
14821575
}
1576+
$(impl $($pinned_drop:tt)*)?
14831577
) => {
14841578
$crate::__pin_project_internal! { @struct=>internal;
14851579
[$($proj_mut_ident)?]
@@ -1516,6 +1610,7 @@ macro_rules! __pin_project_internal {
15161610
$field_vis $field: $field_ty
15171611
),+
15181612
}
1613+
$(impl $($pinned_drop)*)?
15191614
}
15201615
};
15211616
// enum
@@ -1552,6 +1647,7 @@ macro_rules! __pin_project_internal {
15521647
})?
15531648
),+ $(,)?
15541649
}
1650+
$(impl $($pinned_drop:tt)*)?
15551651
) => {
15561652
$crate::__pin_project_internal! { @enum=>internal;
15571653
[$($proj_mut_ident)?]
@@ -1593,6 +1689,7 @@ macro_rules! __pin_project_internal {
15931689
})?
15941690
),+
15951691
}
1692+
$(impl $($pinned_drop)*)?
15961693
}
15971694
};
15981695
(
@@ -1628,6 +1725,7 @@ macro_rules! __pin_project_internal {
16281725
})?
16291726
),+ $(,)?
16301727
}
1728+
$(impl $($pinned_drop:tt)*)?
16311729
) => {
16321730
$crate::__pin_project_internal! { @enum=>internal;
16331731
[$($proj_mut_ident)?]
@@ -1669,6 +1767,7 @@ macro_rules! __pin_project_internal {
16691767
})?
16701768
),+
16711769
}
1770+
$(impl $($pinned_drop)*)?
16721771
}
16731772
};
16741773
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
use pin_project_lite::pin_project;
2+
use std::pin::Pin;
3+
enum Enum<T, U> {
4+
Struct { pinned: T, unpinned: U },
5+
Unit,
6+
}
7+
#[allow(dead_code)]
8+
#[allow(single_use_lifetimes)]
9+
#[allow(clippy::unknown_clippy_lints)]
10+
#[allow(clippy::mut_mut)]
11+
#[allow(clippy::redundant_pub_crate)]
12+
#[allow(clippy::ref_option_ref)]
13+
#[allow(clippy::type_repetition_in_bounds)]
14+
enum EnumProj<'__pin, T, U>
15+
where
16+
Enum<T, U>: '__pin,
17+
{
18+
Struct {
19+
pinned: ::pin_project_lite::__private::Pin<&'__pin mut (T)>,
20+
unpinned: &'__pin mut (U),
21+
},
22+
Unit,
23+
}
24+
#[allow(dead_code)]
25+
#[allow(single_use_lifetimes)]
26+
#[allow(clippy::unknown_clippy_lints)]
27+
#[allow(clippy::mut_mut)]
28+
#[allow(clippy::redundant_pub_crate)]
29+
#[allow(clippy::ref_option_ref)]
30+
#[allow(clippy::type_repetition_in_bounds)]
31+
enum EnumProjRef<'__pin, T, U>
32+
where
33+
Enum<T, U>: '__pin,
34+
{
35+
Struct {
36+
pinned: ::pin_project_lite::__private::Pin<&'__pin (T)>,
37+
unpinned: &'__pin (U),
38+
},
39+
Unit,
40+
}
41+
#[allow(single_use_lifetimes)]
42+
#[allow(clippy::unknown_clippy_lints)]
43+
#[allow(clippy::used_underscore_binding)]
44+
const _: () = {
45+
impl<T, U> Enum<T, U> {
46+
fn project<'__pin>(
47+
self: ::pin_project_lite::__private::Pin<&'__pin mut Self>,
48+
) -> EnumProj<'__pin, T, U> {
49+
unsafe {
50+
match self.get_unchecked_mut() {
51+
Self::Struct { pinned, unpinned } => EnumProj::Struct {
52+
pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned),
53+
unpinned: unpinned,
54+
},
55+
Self::Unit => EnumProj::Unit,
56+
}
57+
}
58+
}
59+
fn project_ref<'__pin>(
60+
self: ::pin_project_lite::__private::Pin<&'__pin Self>,
61+
) -> EnumProjRef<'__pin, T, U> {
62+
unsafe {
63+
match self.get_ref() {
64+
Self::Struct { pinned, unpinned } => EnumProjRef::Struct {
65+
pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned),
66+
unpinned: unpinned,
67+
},
68+
Self::Unit => EnumProjRef::Unit,
69+
}
70+
}
71+
}
72+
}
73+
#[allow(non_snake_case)]
74+
struct __Origin<'__pin, T, U> {
75+
__dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>,
76+
Struct: (T, ::pin_project_lite::__private::AlwaysUnpin<U>),
77+
Unit: (),
78+
}
79+
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum<T, U> where
80+
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin
81+
{
82+
}
83+
impl<T, U> ::pin_project_lite::__private::Drop for Enum<T, U> {
84+
fn drop(&mut self) {
85+
fn __drop_inner<T, U>(this: ::pin_project_lite::__private::Pin<&mut Enum<T, U>>) {
86+
fn __drop_inner() {}
87+
let _ = this;
88+
}
89+
let pinned_self = unsafe { ::pin_project_lite::__private::Pin::new_unchecked(self) };
90+
__drop_inner(pinned_self);
91+
}
92+
}
93+
};
94+
fn main() {}

0 commit comments

Comments
 (0)