diff options
Diffstat (limited to '')
-rw-r--r-- | library/core/src/mem/manually_drop.rs | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs new file mode 100644 index 000000000..3d719afe4 --- /dev/null +++ b/library/core/src/mem/manually_drop.rs @@ -0,0 +1,165 @@ +use crate::ops::{Deref, DerefMut}; +use crate::ptr; + +/// A wrapper to inhibit compiler from automatically calling `T`’s destructor. +/// This wrapper is 0-cost. +/// +/// `ManuallyDrop<T>` is guaranteed to have the same layout as `T`, and is subject +/// to the same layout optimizations as `T`. As a consequence, it has *no effect* +/// on the assumptions that the compiler makes about its contents. For example, +/// initializing a `ManuallyDrop<&mut T>` with [`mem::zeroed`] is undefined +/// behavior. If you need to handle uninitialized data, use [`MaybeUninit<T>`] +/// instead. +/// +/// Note that accessing the value inside a `ManuallyDrop<T>` is safe. +/// This means that a `ManuallyDrop<T>` whose content has been dropped must not +/// be exposed through a public safe API. +/// Correspondingly, `ManuallyDrop::drop` is unsafe. +/// +/// # `ManuallyDrop` and drop order. +/// +/// Rust has a well-defined [drop order] of values. To make sure that fields or +/// locals are dropped in a specific order, reorder the declarations such that +/// the implicit drop order is the correct one. +/// +/// It is possible to use `ManuallyDrop` to control the drop order, but this +/// requires unsafe code and is hard to do correctly in the presence of +/// unwinding. +/// +/// For example, if you want to make sure that a specific field is dropped after +/// the others, make it the last field of a struct: +/// +/// ``` +/// struct Context; +/// +/// struct Widget { +/// children: Vec<Widget>, +/// // `context` will be dropped after `children`. +/// // Rust guarantees that fields are dropped in the order of declaration. +/// context: Context, +/// } +/// ``` +/// +/// [drop order]: https://doc.rust-lang.org/reference/destructors.html +/// [`mem::zeroed`]: crate::mem::zeroed +/// [`MaybeUninit<T>`]: crate::mem::MaybeUninit +#[stable(feature = "manually_drop", since = "1.20.0")] +#[lang = "manually_drop"] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[repr(transparent)] +pub struct ManuallyDrop<T: ?Sized> { + value: T, +} + +impl<T> ManuallyDrop<T> { + /// Wrap a value to be manually dropped. + /// + /// # Examples + /// + /// ```rust + /// use std::mem::ManuallyDrop; + /// let mut x = ManuallyDrop::new(String::from("Hello World!")); + /// x.truncate(5); // You can still safely operate on the value + /// assert_eq!(*x, "Hello"); + /// // But `Drop` will not be run here + /// ``` + #[must_use = "if you don't need the wrapper, you can use `mem::forget` instead"] + #[stable(feature = "manually_drop", since = "1.20.0")] + #[rustc_const_stable(feature = "const_manually_drop", since = "1.32.0")] + #[inline(always)] + pub const fn new(value: T) -> ManuallyDrop<T> { + ManuallyDrop { value } + } + + /// Extracts the value from the `ManuallyDrop` container. + /// + /// This allows the value to be dropped again. + /// + /// # Examples + /// + /// ```rust + /// use std::mem::ManuallyDrop; + /// let x = ManuallyDrop::new(Box::new(())); + /// let _: Box<()> = ManuallyDrop::into_inner(x); // This drops the `Box`. + /// ``` + #[stable(feature = "manually_drop", since = "1.20.0")] + #[rustc_const_stable(feature = "const_manually_drop", since = "1.32.0")] + #[inline(always)] + pub const fn into_inner(slot: ManuallyDrop<T>) -> T { + slot.value + } + + /// Takes the value from the `ManuallyDrop<T>` container out. + /// + /// This method is primarily intended for moving out values in drop. + /// Instead of using [`ManuallyDrop::drop`] to manually drop the value, + /// you can use this method to take the value and use it however desired. + /// + /// Whenever possible, it is preferable to use [`into_inner`][`ManuallyDrop::into_inner`] + /// instead, which prevents duplicating the content of the `ManuallyDrop<T>`. + /// + /// # Safety + /// + /// This function semantically moves out the contained value without preventing further usage, + /// leaving the state of this container unchanged. + /// It is your responsibility to ensure that this `ManuallyDrop` is not used again. + /// + #[must_use = "if you don't need the value, you can use `ManuallyDrop::drop` instead"] + #[stable(feature = "manually_drop_take", since = "1.42.0")] + #[inline] + pub unsafe fn take(slot: &mut ManuallyDrop<T>) -> T { + // SAFETY: we are reading from a reference, which is guaranteed + // to be valid for reads. + unsafe { ptr::read(&slot.value) } + } +} + +impl<T: ?Sized> ManuallyDrop<T> { + /// Manually drops the contained value. This is exactly equivalent to calling + /// [`ptr::drop_in_place`] with a pointer to the contained value. As such, unless + /// the contained value is a packed struct, the destructor will be called in-place + /// without moving the value, and thus can be used to safely drop [pinned] data. + /// + /// If you have ownership of the value, you can use [`ManuallyDrop::into_inner`] instead. + /// + /// # Safety + /// + /// This function runs the destructor of the contained value. Other than changes made by + /// the destructor itself, the memory is left unchanged, and so as far as the compiler is + /// concerned still holds a bit-pattern which is valid for the type `T`. + /// + /// However, this "zombie" value should not be exposed to safe code, and this function + /// should not be called more than once. To use a value after it's been dropped, or drop + /// a value multiple times, can cause Undefined Behavior (depending on what `drop` does). + /// This is normally prevented by the type system, but users of `ManuallyDrop` must + /// uphold those guarantees without assistance from the compiler. + /// + /// [pinned]: crate::pin + #[stable(feature = "manually_drop", since = "1.20.0")] + #[inline] + pub unsafe fn drop(slot: &mut ManuallyDrop<T>) { + // SAFETY: we are dropping the value pointed to by a mutable reference + // which is guaranteed to be valid for writes. + // It is up to the caller to make sure that `slot` isn't dropped again. + unsafe { ptr::drop_in_place(&mut slot.value) } + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +impl<T: ?Sized> const Deref for ManuallyDrop<T> { + type Target = T; + #[inline(always)] + fn deref(&self) -> &T { + &self.value + } +} + +#[stable(feature = "manually_drop", since = "1.20.0")] +#[rustc_const_unstable(feature = "const_deref", issue = "88955")] +impl<T: ?Sized> const DerefMut for ManuallyDrop<T> { + #[inline(always)] + fn deref_mut(&mut self) -> &mut T { + &mut self.value + } +} |