Skip to content

Commit

Permalink
Merge #25
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
bors[bot] and taiki-e authored Jun 14, 2021
2 parents 87eb119 + 574ccbb commit 2135ed4
Show file tree
Hide file tree
Showing 11 changed files with 464 additions and 12 deletions.
5 changes: 0 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,6 @@ be useful in most cases. If you do need useful error messages, then upon
error you can pass the same input to [pin-project] to receive a helpful
description of the compile error.

### Different: No support for custom Drop implementation

pin-project supports this by [`#[pinned_drop]`][pinned-drop].

### Different: No support for custom Unpin implementation

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

## License
Expand Down
113 changes: 106 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,6 @@
//! error you can pass the same input to [pin-project] to receive a helpful
//! description of the compile error.
//!
//! ## Different: No support for custom Drop implementation
//!
//! pin-project supports this by [`#[pinned_drop]`][pinned-drop].
//!
//! ## Different: No support for custom Unpin implementation
//!
//! pin-project supports this by [`UnsafeUnpin`][unsafe-unpin] and [`!Unpin`][not-unpin].
Expand All @@ -96,7 +92,6 @@
//!
//! [not-unpin]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#unpin
//! [pin-project]: https://github.com/taiki-e/pin-project
//! [pinned-drop]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#pinned_drop
//! [unsafe-unpin]: https://docs.rs/pin-project/1/pin_project/attr.pin_project.html#unsafeunpin
#![no_std]
Expand Down Expand Up @@ -331,6 +326,7 @@ macro_rules! __pin_project_internal {
$field_vis:vis $field:ident: $field_ty:ty
),+
}
$(impl $($pinned_drop:tt)*)?
) => {
$(#[$attrs])*
$vis struct $ident $($def_generics)*
Expand Down Expand Up @@ -374,6 +370,7 @@ macro_rules! __pin_project_internal {
[make_proj_field_replace]
[$ident]
[$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
[$(impl $($pinned_drop)*)?]
{
$(
$(#[$pin])?
Expand Down Expand Up @@ -422,6 +419,7 @@ macro_rules! __pin_project_internal {
[make_proj_field_replace]
[$ident]
[$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
[$(impl $($pinned_drop)*)?]
{
$(
$(#[$pin])?
Expand Down Expand Up @@ -484,6 +482,7 @@ macro_rules! __pin_project_internal {
$crate::__pin_project_internal! { @make_drop_impl;
[$ident]
[$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
$(impl $($pinned_drop)*)?
}

// Ensure that it's impossible to use pin projections on a #[repr(packed)] struct.
Expand Down Expand Up @@ -538,6 +537,7 @@ macro_rules! __pin_project_internal {
})?
),+
}
$(impl $($pinned_drop:tt)*)?
) => {
$(#[$attrs])*
$vis enum $ident $($def_generics)*
Expand Down Expand Up @@ -594,6 +594,7 @@ macro_rules! __pin_project_internal {
[make_proj_field_replace]
[$ident]
[$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
[$(impl $($pinned_drop)*)?]
{
$(
$variant $({
Expand Down Expand Up @@ -682,6 +683,7 @@ macro_rules! __pin_project_internal {
$crate::__pin_project_internal! { @make_drop_impl;
[$ident]
[$($impl_generics)*] [$($ty_generics)*] [$(where $($where_clause)*)?]
$(impl $($pinned_drop)*)?
}

// We don't need to check for '#[repr(packed)]',
Expand Down Expand Up @@ -765,6 +767,7 @@ macro_rules! __pin_project_internal {
[$make_proj_field:ident]
[$ident:ident]
[$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
[$(impl $($pinned_drop:tt)*)?]
$($field:tt)*
) => {};
(@struct=>make_proj_replace_ty=>unnamed;
Expand All @@ -773,15 +776,16 @@ macro_rules! __pin_project_internal {
[$make_proj_field:ident]
[$ident:ident]
[$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
[$(impl $($pinned_drop: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])?
Expand Down Expand Up @@ -811,6 +815,7 @@ macro_rules! __pin_project_internal {
[$make_proj_field:ident]
[$ident:ident]
[$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
[$(impl $($pinned_drop:tt)*)?]
$($field:tt)*
) => {};
// =============================================================================================
Expand Down Expand Up @@ -872,6 +877,7 @@ macro_rules! __pin_project_internal {
[$make_proj_field:ident]
[$ident:ident]
[$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
[]
{
$(
$variant:ident $({
Expand Down Expand Up @@ -909,6 +915,7 @@ macro_rules! __pin_project_internal {
[$make_proj_field:ident]
[$ident:ident]
[$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
[$(impl $($pinned_drop:tt)*)?]
$($variant:tt)*
) => {};

Expand Down Expand Up @@ -1193,6 +1200,90 @@ macro_rules! __pin_project_internal {

// =============================================================================================
// make_drop_impl
(@make_drop_impl;
[$_ident:ident]
[$($_impl_generics:tt)*] [$($_ty_generics:tt)*] [$(where $($_where_clause:tt)* )?]
impl $(<
$( $lifetime:lifetime $(: $lifetime_bound:lifetime)? ),* $(,)?
$( $generics:ident
$(: $generics_bound:path)?
$(: ?$generics_unsized_bound:path)?
$(: $generics_lifetime_bound:lifetime)?
),*
>)? PinnedDrop for $self_ty:ty
$(where
$( $where_clause_ty:ty
$(: $where_clause_bound:path)?
$(: ?$where_clause_unsized_bound:path)?
$(: $where_clause_lifetime_bound:lifetime)?
),*
)?
{
fn drop($($arg:ident)+: Pin<&mut Self>) {
$($tt:tt)*
}
}
) => {
impl $(<
$( $lifetime $(: $lifetime_bound)? ,)*
$( $generics
$(: $generics_bound)?
$(: ?$generics_unsized_bound)?
$(: $generics_lifetime_bound)?
),*
>)? $crate::__private::Drop for $self_ty
$(where
$( $where_clause_ty
$(: $where_clause_bound)?
$(: ?$where_clause_unsized_bound)?
$(: $where_clause_lifetime_bound)?
),*
)?
{
fn drop(&mut self) {
// Implementing `__DropInner::__drop_inner` is safe, but calling it is not safe.
// This is because destructors can be called multiple times in safe code and
// [double dropping is unsound](https://github.com/rust-lang/rust/pull/62360).
//
// `__drop_inner` is defined as a safe method, but this is fine since
// `__drop_inner` is not accessible by the users and we call `__drop_inner` only
// once.
//
// Users can implement [`Drop`] safely using `pin_project!` and can drop a
// type that implements `PinnedDrop` using the [`drop`] function safely.
fn __drop_inner $(<
$( $lifetime $(: $lifetime_bound)? ,)*
$( $generics
$(: $generics_bound)?
$(: ?$generics_unsized_bound)?
$(: $generics_lifetime_bound)?
),*
>)? (
$($arg)+: $crate::__private::Pin<&mut $self_ty>,
)
$(where
$( $where_clause_ty
$(: $where_clause_bound)?
$(: ?$where_clause_unsized_bound)?
$(: $where_clause_lifetime_bound)?
),*
)?
{
// A dummy `__drop_inner` function to prevent users call outer `__drop_inner`.
fn __drop_inner() {}
$($tt)*
}

// Safety - we're in 'drop', so we know that 'self' will
// never move again.
let pinned_self: $crate::__private::Pin<&mut Self>
= unsafe { $crate::__private::Pin::new_unchecked(self) };
// We call `__drop_inner` only once. Since `__DropInner::__drop_inner`
// is not accessible by the users, it is never called again.
__drop_inner(pinned_self);
}
}
};
(@make_drop_impl;
[$ident:ident]
[$($impl_generics:tt)*] [$($ty_generics:tt)*] [$(where $($where_clause:tt)* )?]
Expand Down Expand Up @@ -1414,6 +1505,7 @@ macro_rules! __pin_project_internal {
$field_vis:vis $field:ident: $field_ty:ty
),+ $(,)?
}
$(impl $($pinned_drop:tt)*)?
) => {
$crate::__pin_project_internal! { @struct=>internal;
[$($proj_mut_ident)?]
Expand Down Expand Up @@ -1450,6 +1542,7 @@ macro_rules! __pin_project_internal {
$field_vis $field: $field_ty
),+
}
$(impl $($pinned_drop)*)?
}
};
(
Expand Down Expand Up @@ -1480,6 +1573,7 @@ macro_rules! __pin_project_internal {
$field_vis:vis $field:ident: $field_ty:ty
),+ $(,)?
}
$(impl $($pinned_drop:tt)*)?
) => {
$crate::__pin_project_internal! { @struct=>internal;
[$($proj_mut_ident)?]
Expand Down Expand Up @@ -1516,6 +1610,7 @@ macro_rules! __pin_project_internal {
$field_vis $field: $field_ty
),+
}
$(impl $($pinned_drop)*)?
}
};
// enum
Expand Down Expand Up @@ -1552,6 +1647,7 @@ macro_rules! __pin_project_internal {
})?
),+ $(,)?
}
$(impl $($pinned_drop:tt)*)?
) => {
$crate::__pin_project_internal! { @enum=>internal;
[$($proj_mut_ident)?]
Expand Down Expand Up @@ -1593,6 +1689,7 @@ macro_rules! __pin_project_internal {
})?
),+
}
$(impl $($pinned_drop)*)?
}
};
(
Expand Down Expand Up @@ -1628,6 +1725,7 @@ macro_rules! __pin_project_internal {
})?
),+ $(,)?
}
$(impl $($pinned_drop:tt)*)?
) => {
$crate::__pin_project_internal! { @enum=>internal;
[$($proj_mut_ident)?]
Expand Down Expand Up @@ -1669,6 +1767,7 @@ macro_rules! __pin_project_internal {
})?
),+
}
$(impl $($pinned_drop)*)?
}
};
}
Expand Down
94 changes: 94 additions & 0 deletions tests/expand/pinned_drop/enum.expanded.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
use pin_project_lite::pin_project;
use std::pin::Pin;
enum Enum<T, U> {
Struct { pinned: T, unpinned: U },
Unit,
}
#[allow(dead_code)]
#[allow(single_use_lifetimes)]
#[allow(clippy::unknown_clippy_lints)]
#[allow(clippy::mut_mut)]
#[allow(clippy::redundant_pub_crate)]
#[allow(clippy::ref_option_ref)]
#[allow(clippy::type_repetition_in_bounds)]
enum EnumProj<'__pin, T, U>
where
Enum<T, U>: '__pin,
{
Struct {
pinned: ::pin_project_lite::__private::Pin<&'__pin mut (T)>,
unpinned: &'__pin mut (U),
},
Unit,
}
#[allow(dead_code)]
#[allow(single_use_lifetimes)]
#[allow(clippy::unknown_clippy_lints)]
#[allow(clippy::mut_mut)]
#[allow(clippy::redundant_pub_crate)]
#[allow(clippy::ref_option_ref)]
#[allow(clippy::type_repetition_in_bounds)]
enum EnumProjRef<'__pin, T, U>
where
Enum<T, U>: '__pin,
{
Struct {
pinned: ::pin_project_lite::__private::Pin<&'__pin (T)>,
unpinned: &'__pin (U),
},
Unit,
}
#[allow(single_use_lifetimes)]
#[allow(clippy::unknown_clippy_lints)]
#[allow(clippy::used_underscore_binding)]
const _: () = {
impl<T, U> Enum<T, U> {
fn project<'__pin>(
self: ::pin_project_lite::__private::Pin<&'__pin mut Self>,
) -> EnumProj<'__pin, T, U> {
unsafe {
match self.get_unchecked_mut() {
Self::Struct { pinned, unpinned } => EnumProj::Struct {
pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned),
unpinned: unpinned,
},
Self::Unit => EnumProj::Unit,
}
}
}
fn project_ref<'__pin>(
self: ::pin_project_lite::__private::Pin<&'__pin Self>,
) -> EnumProjRef<'__pin, T, U> {
unsafe {
match self.get_ref() {
Self::Struct { pinned, unpinned } => EnumProjRef::Struct {
pinned: ::pin_project_lite::__private::Pin::new_unchecked(pinned),
unpinned: unpinned,
},
Self::Unit => EnumProjRef::Unit,
}
}
}
}
#[allow(non_snake_case)]
struct __Origin<'__pin, T, U> {
__dummy_lifetime: ::pin_project_lite::__private::PhantomData<&'__pin ()>,
Struct: (T, ::pin_project_lite::__private::AlwaysUnpin<U>),
Unit: (),
}
impl<'__pin, T, U> ::pin_project_lite::__private::Unpin for Enum<T, U> where
__Origin<'__pin, T, U>: ::pin_project_lite::__private::Unpin
{
}
impl<T, U> ::pin_project_lite::__private::Drop for Enum<T, U> {
fn drop(&mut self) {
fn __drop_inner<T, U>(this: ::pin_project_lite::__private::Pin<&mut Enum<T, U>>) {
fn __drop_inner() {}
let _ = this;
}
let pinned_self = unsafe { ::pin_project_lite::__private::Pin::new_unchecked(self) };
__drop_inner(pinned_self);
}
}
};
fn main() {}
Loading

0 comments on commit 2135ed4

Please sign in to comment.