destruct-drop 0.2.0

Macro for dropping the fields of a struct or enum without dropping the container.
Documentation
use std::{cell::Cell, marker::PhantomData, rc::Rc};

use destruct_drop::DestructDrop;

#[derive(DestructDrop)]
struct DontDropThis {
    a: DropThis,
    b: u32,
    c: DropThis,
}

impl Drop for DontDropThis {
    fn drop(&mut self) {
        panic!("Dropped DontDropThis");
    }
}

#[derive(Default)]
struct DropThis(Rc<Cell<bool>>);

impl Drop for DropThis {
    fn drop(&mut self) {
        if self.0.get() {
            panic!("Tried to drop DropThis twice!");
        }
        self.0.set(true);
    }
}

#[test]
fn basic_struct() {
    let dropped_a = Rc::new(Cell::new(false));
    let dropped_c = Rc::new(Cell::new(false));

    let dont_drop_this = DontDropThis {
        a: DropThis(dropped_a.clone()),
        b: 0,
        c: DropThis(dropped_c.clone()),
    };

    assert!(!dropped_a.get());
    assert!(!dropped_c.get());

    dont_drop_this.destruct_drop();

    assert!(dropped_a.get());
    assert!(dropped_c.get());
}

#[derive(DestructDrop)]
struct DontDropThisTuple(DropThis, u32, DropThis);

impl Drop for DontDropThisTuple {
    fn drop(&mut self) {
        panic!("Dropped DontDropThisTuple");
    }
}

#[test]
fn basic_tuple_struct() {
    let dropped_0 = Rc::new(Cell::new(false));
    let dropped_2 = Rc::new(Cell::new(false));

    let dont_drop_this =
        DontDropThisTuple(DropThis(dropped_0.clone()), 0, DropThis(dropped_2.clone()));

    assert!(!dropped_0.get());
    assert!(!dropped_2.get());

    dont_drop_this.destruct_drop();

    assert!(dropped_0.get());
    assert!(dropped_2.get());
}

#[derive(DestructDrop)]
struct DontDropThisUnit;

impl Drop for DontDropThisUnit {
    fn drop(&mut self) {
        panic!("Dropped DontDropThisUnit");
    }
}

#[test]
fn basic_unit_struct() {
    let dont_drop_this = DontDropThisUnit;
    dont_drop_this.destruct_drop();
}

#[derive(DestructDrop)]
enum DontDropThisEnum {
    A,
    B { v: DropThis },
    C(DropThis),
}

impl Drop for DontDropThisEnum {
    fn drop(&mut self) {
        panic!("Dropped DontDropThisEnum");
    }
}

#[test]
fn basic_unit_enum() {
    let dont_drop_this_a = DontDropThisEnum::A;
    dont_drop_this_a.destruct_drop();

    let dropped_b = Rc::new(Cell::new(false));
    let dont_drop_this_b = DontDropThisEnum::B {
        v: DropThis(dropped_b.clone()),
    };
    assert!(!dropped_b.get());
    dont_drop_this_b.destruct_drop();
    assert!(dropped_b.get());

    let dropped_c = Rc::new(Cell::new(false));
    let dont_drop_this_c = DontDropThisEnum::C(DropThis(dropped_c.clone()));
    assert!(!dropped_c.get());
    dont_drop_this_c.destruct_drop();
    assert!(dropped_c.get());
}

#[derive(DestructDrop)]
struct DontDropThisGeneric<'a, T>(T, PhantomData<&'a T>);

impl <'a, T> Drop for DontDropThisGeneric<'a, T> {
    fn drop(&mut self) {
        panic!("Dropped DontDropThisGeneric");
    }
}

#[test]
fn basic_struct_generic() {
    let dropped_inner = Rc::new(Cell::new(false));
    let dont_drop_this = DontDropThisGeneric(DropThis(dropped_inner.clone()), PhantomData);
    
    assert!(!dropped_inner.get());
    DestructDrop::destruct_drop(dont_drop_this);
    assert!(dropped_inner.get());
}