refutil 0.1.0

Various utilities for reference, lifetime and memory management
Documentation
//! Provides reference that drops the referred object.

use core::{
    mem::{ManuallyDrop, MaybeUninit},
    ops::{Deref, DerefMut},
};

/// Mutable reference that drops the referred object.
#[repr(transparent)]
pub struct DropMut<'a, T: ?Sized>(
    // INVARIANT: object will become invalid after this is dropped
    &'a mut T
);

impl<'a, T: ?Sized> DropMut<'a, T> {
    /// Converts into a dropping reference.
    /// # Safety
    /// Referred object will be [dropped](Drop) when this reference is dropped,
    /// so it must not be used before carefully reinitialized again.
    pub unsafe fn new(value: &'a mut T) -> Self {
        // INVARIANT: upheld by safety requirements
        Self(value)
    }

    /// Creates a new dropping reference by initializing a [`MaybeUninit`],
    /// which is borrowed for the entire lifetime of this reference and becomes
    /// uninitialized after.
    pub fn at_uninit(at: &'a mut MaybeUninit<T>, value: T) -> Self
    where
        T: Sized,
    {
        // INVARIANT: upheld by `MaybeUninit` allowing to store invalid objects
        Self(at.write(value))
    }

    /// Takes the referred object instead of dropping it.
    pub fn take(self) -> T
    where
        T: Sized,
    {
        // SAFETY: pointer is just created from a reference so it's valid;
        // type invariant allows the referred object to become invalid so we
        // skip our own drop by forgetting `self`.
        let value = unsafe { core::ptr::read(&raw const *self.0) };
        _ = ManuallyDrop::new(self);
        value
    }

    /// Takes the referred object instead of dropping it.
    pub fn take_ref(self) -> &'a mut T
    where
        T: Sized,
    {
        let mut value = ManuallyDrop::new(self);
        // SAFETY: erasing lifetime of local `value` here: actual reference is 
        // returned as `'a` and was given as `'a` so no problems
        unsafe { &mut *&raw mut *value.0 }
    }
}

impl<'a, T: ?Sized> Deref for DropMut<'a, T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        self.0
    }
}

impl<'a, T: ?Sized> DerefMut for DropMut<'a, T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.0
    }
}

impl<'a, T: ?Sized> Drop for DropMut<'a, T> {
    fn drop(&mut self) {
        // SAFETY: pointer is just created from a reference so it's valid;
        // type invariant allows the referred object to become invalid
        unsafe { core::ptr::drop_in_place(&raw mut *self.0) };
    }
}