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;