Skip to content

Commit 2135ed4

Browse files
bors[bot]taiki-e
andauthored
Merge #25
25: Support custom Drop implementation r=taiki-e a=taiki-e ```rust use pin_project_lite::pin_project; pin_project! { pub struct Struct<'a> { was_dropped: &'a mut bool, #[pin] field: u8, } impl PinnedDrop for Struct<'_> { fn drop(this: Pin<&mut Self>) { // <----- NOTE: this is not `self` **this.project().was_dropped = true; } } } fn main() { let mut was_dropped = false; drop(Struct { was_dropped: &mut was_dropped, field: 42 }); assert!(was_dropped); } ``` It's clear how to pass options(=arguments in `#[pin_project]`), and we don't have to think about how to pass options. So, this is easiest to implement compared to other options. For all other options, we have to start by deciding how to pass the options, which can be a hard task, whether simple or complex to implement. Co-authored-by: Taiki Endo <[email protected]>
2 parents 87eb119 + 574ccbb commit 2135ed4

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)