drop_with_owned_fields/
_lib.rs

1//! [`ManuallyDrop`]: `::core::mem::ManuallyDrop`
2//! [`ManuallyDrop::drop()`]: `::core::mem::ManuallyDrop::drop()`
3//! [`ManuallyDrop::take()`]: `::core::mem::ManuallyDrop::take()`
4//! [`drop_with_owned_fields`]: `drop_with_owned_fields`
5//! [`DestructureFields`]: `DestructureFields`
6//! [DestructureFields]: `DestructureFields`
7//! [`Fields`]: `DestructureFields::Fields`
8//! [Fields]: `DestructureFields::Fields`
9//! [`DestructuredFieldsOf`]: `DestructuredFieldsOf`
10//! [DestructuredFieldsOf]: `DestructuredFieldsOf`
11//! [`DropWithOwnedFields`]: `DropWithOwnedFields`
12//! [DropWithOwnedFields]: `DropWithOwnedFields`
13#![doc = include_str!("../README.md")]
14#![no_std]
15#![allow(unused_braces)]
16
17/// The crate's prelude.
18pub
19mod prelude {
20    #[doc(no_inline)]
21    pub use crate::{
22        drop_with_owned_fields,
23        DropWithOwnedFields,
24        DestructuredFieldsOf,
25    };
26}
27
28mod seal {
29    #[diagnostic::on_unimplemented(
30        message = "missing `#[drop_with_owned_fields]` annotation on this type",
31    )]
32    #[allow(drop_bounds, nonstandard_style)]
33    pub trait drop_with_owned_fields_annotation : Drop {}
34}
35
36/// Trait introducing the `Foo -> FooඞFields` association.
37///
38/// Automatically and exclusively implemented for
39/// [`#[drop_with_owned_fields]`][drop_with_owned_fields]-annotated `struct` definitions.
40///
41/// Read [the relevant section of the crate docs](
42/// `crate`#the-companion-struct-fooඞfields) for more info about it.
43pub
44trait DestructureFields : Sized + seal::drop_with_owned_fields_annotation {
45    /// The `…ඞFields` for `Self`, guaranteed to be a field-destructurable `struct` (with
46    /// no [`Drop`] `impl`, thus).
47    type Fields;
48
49    /// "Defuse" the `impl Drop` on `Self` and return a field-destructurable `struct` witness of it.
50    ///
51    /// Note that "the `impl Drop`" on a type is rather "the optional [`ExtraDropGlue`]" of such a
52    /// type; in other words, calling this method **only disables the shallowmost layer of custom
53    /// drop glue**, the one having been added in the <code>impl [DropWithOwnedFields]</code> block.
54    ///
55    /// The _transitive_, _structural_, _drop glue_, of each and every field thereof is very much
56    /// not disabled, and is what gets returned in that [`Self::Fields`] return type.
57    ///
58    ///   - That's how you shall get owned access to the pattern-bound variables;
59    ///
60    ///   - and the ones not explicitly bound in such a pattern, _e.g._, covered by a `, ..`
61    ///     trailing pattern, or explicitly `: _`-discarded, shall get dropped at the end of that
62    ///     very destructuring statement.
63    ///
64    /// [`ExtraDropGlue`]: `Drop`
65    ///
66    /// # Example
67    ///
68    /// This can be useful in situations such as [the `CommitOnDrop` example of the crate
69    /// docs][`crate`#example-transactioncommit-in-drop], when wanting to add `.roll_back()`
70    /// functionality.
71    ///
72    /// ```rust
73    /// use ::drop_with_owned_fields::prelude::*;
74    ///
75    /// use example_lib::Transaction;
76    /// // where:
77    /// mod example_lib {
78    ///     pub struct Transaction {
79    ///         // …
80    ///     }
81    ///
82    ///     impl Transaction {
83    ///         /// Owned access required for stronger type-safety 👌
84    ///         pub fn commit(self) {
85    ///             // …
86    ///         }
87    ///         /// Owned access required for stronger type-safety 👌
88    ///         pub fn roll_back(self) {
89    ///             // …
90    ///         }
91    ///     }
92    /// }
93    ///
94    /// #[drop_with_owned_fields(as struct CommitOnDropFields)]
95    /// struct CommitOnDrop {
96    ///     txn: Transaction,
97    ///     // …
98    /// }
99    ///
100    /// impl DropWithOwnedFields for CommitOnDrop {
101    ///     fn drop(CommitOnDropFields { txn, .. }: CommitOnDropFields) {
102    ///         txn.commit(); // ✅
103    ///     }
104    /// }
105    ///
106    /// impl CommitOnDrop {
107    ///     fn roll_back(self) {
108    ///         //                                       👇
109    ///         let CommitOnDropFields { txn, .. } = self.destructure_fields_disabling_impl_drop();
110    ///         txn.roll_back(); // ✅
111    ///     }
112    /// }
113    /// #
114    /// # fn main() {}
115    /// ```
116    ///
117    /// ## Remarks
118    ///
119    /// This function shall be available on every
120    /// [`#[drop_with_owned_fields]`][drop_with_owned_fields]-annotated type, actually, **but as an
121    /// _inherent_ `pub(crate) const fn` method; _not_ as a trait method!** ⚠️
122    ///
123    /// The reason for this is so as to never be `pub`, to avoid soundness footguns with contrived
124    /// APIs.
125    ///
126    /// If you do want to expose similar functionality `pub`licly, simply redefine your own `pub fn`
127    /// with your own `fn` name, and call this method in it.
128    #[cfg(doc)]
129    fn destructure_fields_disabling_impl_drop(self)
130      -> Self::Fields
131    {
132        const { panic! {"\
133            not really implemented here, but rather, by the macro, as non-`pub` inherent `fn`.\
134        "}}
135    }
136}
137
138/// The whole objective of this crate: to allow one to write an `impl Drop`-looking block, _but
139/// with owned access to the fields_.
140///
141/// That is, an `impl Drop`-looking block, but wherein the argument to that function is "a
142/// destructuring `Self { fields… }` pattern" rather than the usual, severely limited, `&mut self`.
143///
144/// This trait:
145///   - _can_ only be implemented on a [`#[drop_with_owned_fields]`]-annotated type,
146///   - at which point it even _has to_ be implemented on such a type (since the actual `impl Drop`
147///     produced by the macro attribute requires it so as to delegate to it).
148///
149/// See the [main `crate` docs for more info][`crate`].
150#[diagnostic::on_unimplemented(
151    note = "\
152        The `#[drop_with_owned_fields]` annotation expects 🫵 you to provide \
153        a companion `impl` of `DropWithOwnedFields` (the whole point!).\n\
154        \n\
155        If you have enabled the `\"drop-sugar\"` Cargo feature, you can even write \
156        a direct `impl` of `Drop` instead, but with a `#[drop_with_owned_fields]` \
157        annotation on top of it.\n\
158    ",
159)]
160pub
161trait DropWithOwnedFields : DestructureFields {
162    fn drop(owned_fields: DestructuredFieldsOf<Self>);
163}
164
165/// Convenience alias to easily refer to "the `FooඞFields`", even when this type is
166/// "private"/sealed.
167///
168/// See the [main `crate` docs for more info][`crate`].
169#[allow(type_alias_bounds)]
170pub
171type DestructuredFieldsOf<T : ?Sized + DestructureFields> = T::Fields;
172
173/// Annotation required on a type in order for [`DropWithOwnedFields`] to be `impl`ementable for it.
174///
175/// The attribute shall then define a
176/// [companion `struct …ඞFields`][`crate`#the-companion-struct-fooඞfields],
177///
178///   - either as an "anonymous"/"private" (sealed) type, then only nameable through the
179///     convenience <code>DestructuredFieldsOf\<Self\></code> type alias and naming abstraction
180///     layer;
181///
182///     This is the case when feeding it an attribute arg of `as _`.
183///
184///     The following, for instance, fails to compile:
185///
186///     ```rust ,compile_fail
187///     use ::drop_with_owned_fields::drop_with_owned_fields;
188///
189///     #[drop_with_owned_fields(as _)]
190///     struct Foo {
191///         // …
192///     }
193///
194///     fn main() {
195///         let _: FooFields; // Error
196///     }
197///     ```
198///
199///     with:
200///
201///     <span class="code_with_line_wrap">
202///
203///     ```rust ,ignore
204///     # /*
205///     error[E0412]: cannot find type `FooFields` in this scope
206///       --> src/_lib.rs:114:12
207///        |
208///     10 |     let _: FooFields; // Error
209///        |            ^^^^^^^^^^ not found in this scope
210///        |
211///     # */
212///     ```
213///
214///     </span>
215///
216///   - or, when feeding it an attribute arg of `as $($pub:vis)? struct $FooFieldsName:ident`,
217///     as a properly `$FooFieldsName`-named, and `$pub`-visible, type.
218///
219///     ```rust
220///     use ::drop_with_owned_fields::drop_with_owned_fields;
221///
222///     #[drop_with_owned_fields(as pub(crate) struct FooFields)]
223///     pub struct Foo {
224///         // …
225///     }
226///
227///     # #[::drop_with_owned_fields::drop_with_owned_fields]
228///     # impl Drop for Foo { fn drop(Self {}: _) {}}
229///     fn main() {
230///         let _: FooFields; // ✅
231///     }
232///     ```
233///
234/// See the [main `crate` docs for more info][`crate`].
235pub use ::drop_with_owned_fields_proc_macros::drop_with_owned_fields;
236
237// macro internals
238#[doc(hidden)] /** Not part of the public API */ pub
239mod ඞ {
240    pub use ::core; // or `std`
241    pub use ::drop_with_owned_fields_proc_macros::ඞannihilate as annihilate;
242    pub use crate::seal::drop_with_owned_fields_annotation;
243
244    pub union ConstTransmuteUnchecked<Src, Dst> {
245        pub src: ::core::mem::ManuallyDrop<Src>,
246        pub dst: ::core::mem::ManuallyDrop<Dst>,
247    }
248}
249
250#[doc = include_str!("compile_fail_tests.md")]
251mod _compile_fail_tests {}