|
| 1 | +use std::{ |
| 2 | + mem::ManuallyDrop, |
| 3 | + ops::{Deref, DerefMut, Drop, Fn}, |
| 4 | +}; |
| 5 | + |
| 6 | +/// A wrapper providing additional drop-logic for the contained value. |
| 7 | +/// |
| 8 | +/// When this wrapper is dropped, the contained value will be passed into the given function before |
| 9 | +/// being destructed. |
| 10 | +pub(crate) struct DropGuard<T, F: Fn(T)> { |
| 11 | + value: ManuallyDrop<T>, |
| 12 | + drop_fn: F, |
| 13 | +} |
| 14 | + |
| 15 | +impl<T, F: Fn(T)> DropGuard<T, F> { |
| 16 | + /// Create a new `DropGuard` with the given value and drop function. |
| 17 | + pub fn new(value: T, drop_fn: F) -> Self { |
| 18 | + Self { |
| 19 | + value: ManuallyDrop::new(value), |
| 20 | + drop_fn, |
| 21 | + } |
| 22 | + } |
| 23 | +} |
| 24 | + |
| 25 | +impl<T, F: Fn(T)> Deref for DropGuard<T, F> { |
| 26 | + type Target = T; |
| 27 | + |
| 28 | + fn deref(&self) -> &T { |
| 29 | + &*self.value |
| 30 | + } |
| 31 | +} |
| 32 | + |
| 33 | +impl<T, F: Fn(T)> DerefMut for DropGuard<T, F> { |
| 34 | + fn deref_mut(&mut self) -> &mut T { |
| 35 | + &mut *self.value |
| 36 | + } |
| 37 | +} |
| 38 | + |
| 39 | +impl<T, F: Fn(T)> Drop for DropGuard<T, F> { |
| 40 | + fn drop(&mut self) { |
| 41 | + // SAFETY: ManuallyDrop::take() leaves `self.value` in an uninitialized state, meaning that |
| 42 | + // it must not be accessed further. This is guaranteed since `self` is being dropped and |
| 43 | + // cannot be accessed after this function completes. Moreover, the strict ownership of |
| 44 | + // `self.value` means that it cannot be accessed by `self.drop_fn`'s drop function either. |
| 45 | + let value = unsafe { ManuallyDrop::take(&mut self.value) }; |
| 46 | + (self.drop_fn)(value); |
| 47 | + } |
| 48 | +} |
0 commit comments