From acdd2452d50a3e0f177c49d37df5fbd933fdc370 Mon Sep 17 00:00:00 2001 From: Jacob Rothstein Date: Fri, 29 Mar 2024 12:15:26 -0700 Subject: [PATCH] docs: document PinnedDrop --- src/lib.rs | 76 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/src/lib.rs b/src/lib.rs index a874a86..97d905b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -42,6 +42,8 @@ impl Struct { } ``` +### Enums + To use [`pin_project!`] on enums, you need to name the projection type returned from the method. @@ -69,6 +71,30 @@ impl Enum { } ``` +### Pinned Drop + +```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; + } + } +} + +let mut was_dropped = false; +drop(Struct { was_dropped: &mut was_dropped, field: 42 }); +assert!(was_dropped); +``` + ## [pin-project] vs pin-project-lite Here are some similarities and differences compared to [pin-project]. @@ -100,7 +126,8 @@ description of the compile error. ### Different: No support for custom Unpin implementation -pin-project supports this by [`UnsafeUnpin`][unsafe-unpin]. (`!Unpin` is supported by both [pin-project][not-unpin] and [pin-project-lite][not-unpin-lite].) +pin-project supports this by [`UnsafeUnpin`][unsafe-unpin]. (`!Unpin` is supported by both +[pin-project][not-unpin] and [pin-project-lite][not-unpin-lite].) ### Different: No support for tuple structs and tuple variants @@ -329,6 +356,53 @@ pin-project supports this. /// Note that using [`PhantomPinned`] without `#[pin]` or `#[project(!Unpin)]` /// attribute has no effect. /// +/// # Pinned Drop +/// +/// In order to correctly implement pin projections, a type’s [`Drop`] impl must not move out of any +/// structurally pinned fields. Unfortunately, [`Drop::drop`] takes `&mut Self`, not `Pin<&mut +/// Self>`. +/// +/// To implement [`Drop`] for type that has pin, add an `impl PinnedDrop` block at the end of the +/// [`pin_project`] macro block. PinnedDrop has the following interface: +/// +/// ```rust +/// # use std::pin::Pin; +/// trait PinnedDrop { +/// fn drop(this: Pin<&mut Self>); +/// } +/// ``` +/// +/// Note that the argument to `PinnedDrop::drop` cannot be named `self`. +/// +/// `pin_project_lite` implements the actual [`Drop`] trait via PinnedDrop you implemented. To +/// explicitly drop a type that implements PinnedDrop, use the [drop] function just like dropping a +/// type that directly implements [Drop]. +/// +/// `PinnedDrop::drop` will never be called more than once, just like [`Drop::drop`]. +/// +/// ```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; +/// } +/// } +/// } +/// +/// let mut was_dropped = false; +/// drop(Struct { was_dropped: &mut was_dropped, field: 42 }); +/// assert!(was_dropped); +/// ``` +/// +/// /// [`PhantomPinned`]: core::marker::PhantomPinned /// [`Pin::as_mut`]: core::pin::Pin::as_mut /// [`Pin`]: core::pin::Pin