maybe_dangling/
manually_drop.rs

1use ::core::{
2    cmp::*,
3    fmt::{self, Debug},
4    hash::{self, Hash},
5    mem::MaybeUninit as MU,
6    ops::{Deref, DerefMut},
7};
8
9/// A wrapper to inhibit compiler from automatically calling `T`’s destructor.
10/// This wrapper is 0-cost.
11///
12/// See [`::core::mem::ManuallyDrop`] for more info.
13///
14/// # Differences with [`::core::mem::ManuallyDrop`]
15///
16///   - **No niches**
17///
18///     The current implementation uses [`::core::mem::MaybeUninit`] to make
19///     sure the aliasing and `dereferenceable`ity properties of the inner `T`
20///     are properly disabled.
21///
22///     The main side-effect of this implementation is that it disables
23///     niches, thereby preventing **discriminant elision**.
24///
25///     For instance, an <code>[Option]<[ManuallyDrop]<[bool]>></code> will
26///     occupy _two_ bytes rather than _one_.
27///
28///   - It does not implement
29///     [`Structural{Partial,}Eq`][::core::marker::StructuralEq].
30///
31///   - Note that once stdlib's own [`::core::mem::ManuallyDrop`] properly gets
32///     its aliasing/`dereferenceable`ity properties removed, this crate shall
33///     be updated to just reëxport it (using a `build.rs` to prevent MSRV
34///     breakage).
35///
36///     This means that the _lack of discriminant elision_ cannot be relied upon
37///     either!
38///
39///   - Other than that, this is a `#[repr(transparent)]` wrapper around `T`,
40///     thereby having:
41///       - equal [`Layout`][::core::alloc::Layout];
42///       - equal calling-convention ABI[^1]
43///
44/// [^1]: this is assuming `MaybeUninit<T>` has the same ABI as `T`, as it
45/// currently advertises, despite that probably being a bad idea for
46/// a "bag of bytes" `T`-ish wrapper, since it means that padding bytes
47/// inside of `T` won't be preserved when working with a
48/// `MaybeUninit<T>`. So, if the stdlib were to break the current
49/// ABI promise of `MaybeUninit` to cater to that problem, then this crate would
50/// probably do so well, unless the `maybe_dangling` changes were to make it to
51/// the stdlib first.
52#[derive(Copy)]
53#[repr(transparent)]
54pub struct ManuallyDrop<T> {
55    /// Until stdlib guarantees `MaybeDangling` semantics for its `ManuallyDrop`,
56    /// we have to polyfill it ourselves using `MaybeUninit`, the only type
57    /// known to date to feature such semantics.
58    ///
59    /// So doing, quite unfortunately, disables niche optimizations.
60    ///
61    /// # SAFETY INVARIANT: the value must always be init `MU`-wise.
62    value: MU<T>,
63}
64
65// SAFETY: as per the safety invariant above.
66#[allow(unsafe_code)]
67impl<T> ManuallyDrop<T> {
68    /// Wrap a value to be manually dropped.
69    ///
70    /// See [`::core::mem::ManuallyDrop::new()`] for more info.
71    #[inline]
72    pub const fn new(value: T) -> ManuallyDrop<T> {
73        Self {
74            value: MU::new(value),
75        }
76    }
77
78    /// Extracts the value from the `ManuallyDrop` container.
79    ///
80    /// See [`::core::mem::ManuallyDrop::into_inner()`] for more info.
81    #[inline]
82    pub const fn into_inner(slot: ManuallyDrop<T>) -> T {
83        unsafe { MU::assume_init(slot.value) }
84    }
85
86    /// Takes the value from the `ManuallyDrop<T>` container out.
87    ///
88    /// See [`::core::mem::ManuallyDrop::take()`] for more info.
89    #[must_use = "if you don't need the value, you can use `ManuallyDrop::drop` instead"]
90    #[inline]
91    pub unsafe fn take(slot: &mut ManuallyDrop<T>) -> T {
92        unsafe { slot.value.as_ptr().read() }
93    }
94
95    /// Manually drops the contained value.
96    ///
97    /// See [`::core::mem::ManuallyDrop::drop()`] for more info.
98    #[inline]
99    pub unsafe fn drop(slot: &mut ManuallyDrop<T>) {
100        unsafe { slot.value.as_mut_ptr().drop_in_place() }
101    }
102}
103
104// Safety: as per the invariant mentioned above.
105#[allow(unsafe_code)]
106impl<T> DerefMut for ManuallyDrop<T> {
107    /// See [`::core::mem::ManuallyDrop::deref_mut()`] for more info.
108    #[inline]
109    fn deref_mut(&mut self) -> &mut T {
110        impl<T> Deref for ManuallyDrop<T> {
111            type Target = T;
112
113            #[inline]
114            /// See [`::core::mem::ManuallyDrop::deref()`] for more info.
115            fn deref(self: &Self) -> &T {
116                unsafe { self.value.assume_init_ref() }
117            }
118        }
119
120        unsafe { self.value.assume_init_mut() }
121    }
122}
123
124impl<T: Default> Default for ManuallyDrop<T> {
125    /// See [`::core::mem::ManuallyDrop::default()`] for more info.
126    #[inline]
127    fn default() -> Self {
128        Self::new(T::default())
129    }
130}
131
132impl<T: Clone> Clone for ManuallyDrop<T> {
133    /// See [`::core::mem::ManuallyDrop::clone()`] for more info.
134    fn clone(self: &Self) -> Self {
135        Self::new(T::clone(self))
136    }
137
138    JustDerefTM! {
139        fn clone_from(self: &mut Self, source: &Self);
140    }
141}
142
143JustDerefTM! {
144    impl<T: Debug> Debug for ManuallyDrop<T> {
145        fn fmt(self: &Self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
146    }
147
148    impl<T: Hash> Hash for ManuallyDrop<T> {
149        fn hash<__H: hash::Hasher>(self: &Self, state: &mut __H);
150    }
151
152    impl<T: Ord> Ord for ManuallyDrop<T> {
153        fn cmp(self: &Self, other: &Self) -> Ordering;
154    }
155
156    impl<T: PartialOrd> PartialOrd for ManuallyDrop<T> {
157        fn partial_cmp(self: &Self, other: &Self) -> Option<Ordering>;
158    }
159
160    impl<T: PartialEq> PartialEq for ManuallyDrop<T> {
161        fn eq(self: &Self, other: &Self) -> bool;
162    }
163
164    impl<T: Eq> Eq for ManuallyDrop<T> {}
165}
166
167macro_rules! JustDerefTM {
168    (
169        $(
170            $(#$attr:tt)*
171            $($(@$if_unsafe:tt)?
172                unsafe
173            )?
174            impl<T $(: $Bound:path)?>
175                $($($Trait:ident)::+ for)?
176                ManuallyDrop<T>
177            {
178                $($inner:tt)*
179            }
180        )*
181    ) => (
182        $(
183            $(#$attr)*
184            $($($if_unsafe)?
185                unsafe
186            )?
187            impl<T $(: $Bound)?>
188                $($($Trait)::+ for)?
189                ManuallyDrop<T>
190            {
191                JustDerefTM! {
192                    $($inner)*
193                }
194            }
195        )*
196        $(
197            $(#$attr)*
198            $($($if_unsafe)?
199                unsafe
200            )?
201            impl<T $(: $Bound)?>
202                $($($Trait)::+ for)?
203                crate::MaybeDangling<T>
204            {
205                JustDerefTM! {
206                    $($inner)*
207                }
208            }
209        )*
210    );
211
212    (
213        $(
214            $(#$attr:tt)*
215            $pub:vis
216            fn $fname:ident
217                $(<$H:ident $(: $Bound:path)?>)?
218            (
219                $(
220                    $arg_name:ident : $ArgTy:ty
221                ),* $(,)?
222            ) $(-> $Ret:ty)? ;
223        )*
224    ) => (
225        $(
226            #[inline]
227            $(#$attr)*
228            #[doc = concat!(
229                "\nSee [`::core::mem::ManuallyDrop::", stringify!($fname), "()`] for more info."
230            )]
231            $pub
232            fn $fname
233                $(<$H $(: $Bound)?>)?
234            (
235                $(
236                    $arg_name : $ArgTy
237                ),*
238            ) $(-> $Ret)?
239            {
240                T::$fname($($arg_name),*)
241            }
242        )*
243    );
244}
245use JustDerefTM;