| use crate::fmt::{self, Debug}; | |
| use crate::marker::Destruct; | |
| use crate::mem::ManuallyDrop; | |
| use crate::ops::{Deref, DerefMut}; | |
| /// Wrap a value and run a closure when dropped. | |
| /// | |
| /// This is useful for quickly creating destructors inline. | |
| /// | |
| /// # Examples | |
| /// | |
| /// ```rust | |
| /// # #![allow(unused)] | |
| /// #![feature(drop_guard)] | |
| /// | |
| /// use std::mem::DropGuard; | |
| /// | |
| /// { | |
| /// // Create a new guard around a string that will | |
| /// // print its value when dropped. | |
| /// let s = String::from("Chashu likes tuna"); | |
| /// let mut s = DropGuard::new(s, |s| println!("{s}")); | |
| /// | |
| /// // Modify the string contained in the guard. | |
| /// s.push_str("!!!"); | |
| /// | |
| /// // The guard will be dropped here, printing: | |
| /// // "Chashu likes tuna!!!" | |
| /// } | |
| /// ``` | |
| #[unstable(feature = "drop_guard", issue = "144426")] | |
| #[doc(alias = "ScopeGuard")] | |
| #[doc(alias = "defer")] | |
| pub struct DropGuard<T, F> | |
| where | |
| F: FnOnce(T), | |
| { | |
| inner: ManuallyDrop<T>, | |
| f: ManuallyDrop<F>, | |
| } | |
| impl<T, F> DropGuard<T, F> | |
| where | |
| F: FnOnce(T), | |
| { | |
| /// Create a new instance of `DropGuard`. | |
| /// | |
| /// # Example | |
| /// | |
| /// ```rust | |
| /// # #![allow(unused)] | |
| /// #![feature(drop_guard)] | |
| /// | |
| /// use std::mem::DropGuard; | |
| /// | |
| /// let value = String::from("Chashu likes tuna"); | |
| /// let guard = DropGuard::new(value, |s| println!("{s}")); | |
| /// ``` | |
| #[unstable(feature = "drop_guard", issue = "144426")] | |
| #[must_use] | |
| pub const fn new(inner: T, f: F) -> Self { | |
| Self { inner: ManuallyDrop::new(inner), f: ManuallyDrop::new(f) } | |
| } | |
| /// Consumes the `DropGuard`, returning the wrapped value. | |
| /// | |
| /// This will not execute the closure. It is typically preferred to call | |
| /// this function instead of `mem::forget` because it will return the stored | |
| /// value and drop variables captured by the closure instead of leaking their | |
| /// owned resources. | |
| /// | |
| /// # Example | |
| /// | |
| /// ```rust | |
| /// # #![allow(unused)] | |
| /// #![feature(drop_guard)] | |
| /// | |
| /// use std::mem::DropGuard; | |
| /// | |
| /// let value = String::from("Nori likes chicken"); | |
| /// let guard = DropGuard::new(value, |s| println!("{s}")); | |
| /// assert_eq!(DropGuard::dismiss(guard), "Nori likes chicken"); | |
| /// ``` | |
| #[unstable(feature = "drop_guard", issue = "144426")] | |
| #[rustc_const_unstable(feature = "const_drop_guard", issue = "none")] | |
| #[inline] | |
| pub const fn dismiss(guard: Self) -> T | |
| where | |
| F: [const] Destruct, | |
| { | |
| // First we ensure that dropping the guard will not trigger | |
| // its destructor | |
| let mut guard = ManuallyDrop::new(guard); | |
| // Next we manually read the stored value from the guard. | |
| // | |
| // SAFETY: this is safe because we've taken ownership of the guard. | |
| let value = unsafe { ManuallyDrop::take(&mut guard.inner) }; | |
| // Finally we drop the stored closure. We do this *after* having read | |
| // the value, so that even if the closure's `drop` function panics, | |
| // unwinding still tries to drop the value. | |
| // | |
| // SAFETY: this is safe because we've taken ownership of the guard. | |
| unsafe { ManuallyDrop::drop(&mut guard.f) }; | |
| value | |
| } | |
| } | |
| #[unstable(feature = "drop_guard", issue = "144426")] | |
| #[rustc_const_unstable(feature = "const_convert", issue = "143773")] | |
| const impl<T, F> Deref for DropGuard<T, F> | |
| where | |
| F: FnOnce(T), | |
| { | |
| type Target = T; | |
| fn deref(&self) -> &T { | |
| &*self.inner | |
| } | |
| } | |
| #[unstable(feature = "drop_guard", issue = "144426")] | |
| #[rustc_const_unstable(feature = "const_convert", issue = "143773")] | |
| const impl<T, F> DerefMut for DropGuard<T, F> | |
| where | |
| F: FnOnce(T), | |
| { | |
| fn deref_mut(&mut self) -> &mut T { | |
| &mut *self.inner | |
| } | |
| } | |
| #[unstable(feature = "drop_guard", issue = "144426")] | |
| #[rustc_const_unstable(feature = "const_drop_guard", issue = "none")] | |
| const impl<T, F> Drop for DropGuard<T, F> | |
| where | |
| F: [const] FnOnce(T), | |
| { | |
| fn drop(&mut self) { | |
| // SAFETY: `DropGuard` is in the process of being dropped. | |
| let inner = unsafe { ManuallyDrop::take(&mut self.inner) }; | |
| // SAFETY: `DropGuard` is in the process of being dropped. | |
| let f = unsafe { ManuallyDrop::take(&mut self.f) }; | |
| f(inner); | |
| } | |
| } | |
| #[unstable(feature = "drop_guard", issue = "144426")] | |
| impl<T, F> Debug for DropGuard<T, F> | |
| where | |
| T: Debug, | |
| F: FnOnce(T), | |
| { | |
| fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | |
| fmt::Debug::fmt(&**self, f) | |
| } | |
| } |