Skip to content

Commit

Permalink
Support custom Drop implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
taiki-e committed Apr 24, 2021
1 parent 43f8016 commit 30f66dd
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;
// FIXME: check $_ident + $_ty_generics == $self_ty
[$_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 = 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 30f66dd

Please sign in to comment.