selfstack 0.3.0

A macro to generate self-referential structs
Documentation
struct A<'a> {
    drop_count: &'a mut u32,
}
struct B<'a> {
    a: &'a A<'a>,
    drop_count: &'a mut u32,
}
struct C<'a> {
    b: &'a B<'a>,
    drop_count: &'a mut u32,
}

impl Drop for A<'_> {
    fn drop(&mut self) {
        *self.drop_count += 1
    }
}
impl Drop for B<'_> {
    fn drop(&mut self) {
        assert_eq!(
            *self.a.drop_count, 0,
            "A was dropped {} times before B",
            *self.a.drop_count
        );
        *self.drop_count += 1
    }
}
impl Drop for C<'_> {
    fn drop(&mut self) {
        assert_eq!(
            *self.b.a.drop_count, 0,
            "A was dropped {} times before C",
            *self.b.a.drop_count
        );
        assert_eq!(
            *self.b.drop_count, 0,
            "B was dropped {} times before C",
            &self.b.drop_count
        );
        *self.drop_count += 1
    }
}

selfstack::selfstack! {
    mod store {
        use super::*;
        pub(super) struct Store<'x> {
            a: A<'x>,
            b: B<'a>,
            c: C<'b>,
        }
    }
}

use store::Store;

#[test]
fn test_drop_counts() {
    let mut a_drops = 0;
    let mut b_drops = 0;
    let mut c_drops = 0;
    let mut store: Store = Store::new();
    {
        let a = store.set_a(A {
            drop_count: &mut a_drops,
        });
        let b = a.build_b(|a: &A| B {
            a: a,
            drop_count: &mut b_drops,
        });
        let c = b.build_c(|_a: &A, b: &B| C {
            b: b,
            drop_count: &mut c_drops,
        });
        assert_eq!(*c.ref_a().drop_count, 0);
        assert_eq!(*c.ref_b().drop_count, 0);
        assert_eq!(*c.ref_c().drop_count, 0);
        assert_eq!(*c.ref_c().b.drop_count, 0);
        assert_eq!(*c.ref_c().b.a.drop_count, 0);
        std::mem::drop(c);
        assert_eq!(a_drops, 1);
        assert_eq!(b_drops, 1);
        assert_eq!(c_drops, 1);
    }
    a_drops = 0;
    b_drops = 0;
    c_drops = 0;
    {
        let a = store.set_a(A {
            drop_count: &mut a_drops,
        });
        let b = a.build_b(|a: &A| B {
            a: a,
            drop_count: &mut b_drops,
        });
        assert_eq!(*b.ref_a().drop_count, 0);
        assert_eq!(*b.ref_b().drop_count, 0);
        std::mem::drop(b);
        assert_eq!(a_drops, 1);
        assert_eq!(b_drops, 1);
        assert_eq!(c_drops, 0);
    }
    a_drops = 0;
    b_drops = 0;
    c_drops = 0;
    {
        let a = store.set_a(A {
            drop_count: &mut a_drops,
        });
        assert_eq!(*a.ref_a().drop_count, 0);
        std::mem::drop(a);
        assert_eq!(a_drops, 1);
        assert_eq!(b_drops, 0);
        assert_eq!(c_drops, 0);
    }
    a_drops = 0;
    b_drops = 0;
    c_drops = 0;
    {
        let a = store.set_a(A {
            drop_count: &mut a_drops,
        });
        let b = a
            .try_build_b(|a: &A| -> Result<_, ()> {
                Ok(B {
                    a: a,
                    drop_count: &mut b_drops,
                })
            })
            .unwrap();
        assert_eq!(*b.ref_a().drop_count, 0);
        assert_eq!(*b.ref_b().drop_count, 0);
        std::mem::drop(b);
        assert_eq!(a_drops, 1);
        assert_eq!(b_drops, 1);
        assert_eq!(c_drops, 0);
    }
}