"drop-move": a crate to support moving out of drop

One ugly feature of Rust is that Drop::drop's signature is drop(&mut self), not drop(self). This means that it requires unsafe code to e.g. call a FnOnce from drop, or for a struct to add a Box it holds to a free list, rather than dropping it. They did it this way because otherwise drop would have to be special cased so that it wouldn't recursively drop itself in an infinite loop when it reaches the end of the function. drop-move resolve this by treating dropping as destructuring. Instead, of drop(&mut self), drop_move is given an object that can either be dereferenced to &mut Self or destructured into its members. If it is not destructured by the end, it will automatically destructure into its members and drop them. drop-move also support destructuring in other context, not just when dropping, solving the related problem that Drop types are not allowed to be destructured.

A simple example:

use drop_move::{drop_move_wrap, DropMove, DropHandle};

drop_move_wrap! {
    /// Runs a function when dropped.
    #[derive(Clone)]
    pub struct DropGuard<F: FnOnce()>(DropGuardInner {
        func: F,
    });
}

impl<F: FnOnce()> DropMove for DropGuardInner<F> {
    fn drop_move(self_: DropHandle<Self>) {
        (DropHandle::into_inner(self_).func)()
    }
}

impl<F: FnOnce()> DropGuard<F> {
    pub fn new(f: F) -> Self {
        DropGuardInner { func: f }.into()
    }
}

let mut x: u32 = 0;
{
    let y = Box::new(&mut x); // Box is not Copy, so the closure will only be FnOnce.
    let guard = DropGuard::new(move || **y += 1);
}

assert_eq!(x, 1);

Check out the docs for more.

3 Likes