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 {}