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); } }