use com::interfaces::IUnknown; use std::sync::atomic::{AtomicI32, Ordering::SeqCst}; use std::sync::Arc; const NUM_DROPPED: i32 = -1; const NUM_INIT: i32 = 0; com::interfaces! { #[uuid("9004239b-61ee-4737-bdc1-f0c2cc42b2e4")] pub unsafe interface IFoo : IUnknown { fn zap(&self, i: i32); } } com::class! { #[no_class_factory] pub class FooServer : IFoo { number: Arc, } impl IFoo for FooServer { fn zap(&self, x: i32) { println!("FooServer::zap: x = {}", x); self.number.store(x, SeqCst); } } } impl Drop for FooServer { fn drop(&mut self) { println!("FooServer::drop"); self.number.store(NUM_DROPPED, SeqCst); } } fn get_refcount(c: &com::production::ClassAllocation) -> u32 { unsafe { // barbaric, but effective let _ = c.add_ref(); c.dec_ref_count() } } fn main() { let cell = Arc::new(AtomicI32::new(NUM_INIT)); let server = FooServer::allocate(cell.clone()); assert_eq!(get_refcount(&server), 1); assert_eq!(cell.load(SeqCst), NUM_INIT); let f = IFoo::from(&**server); assert_eq!(get_refcount(&server), 2); // make a call into server println!("calling zap()"); unsafe { f.zap(100); } assert_eq!(cell.load(SeqCst), 100); // clone the ref to the server println!("cloning server"); let server2 = server.clone(); // verify that cloning the server affected the refcount of the original assert_eq!(get_refcount(&server), 3); drop(server2); assert_eq!(get_refcount(&server), 2); // test cloning an interface println!("cloning interface"); let f2 = f.clone(); assert_eq!(get_refcount(&server), 3); drop(f2); assert_eq!(get_refcount(&server), 2); // drop the server println!("dropping server ref"); drop(server); // server.refcount is now 1, but we can't check it any more // observe that cell is still alive assert_eq!(cell.load(SeqCst), 100); // make another server call println!("calling zap() again"); unsafe { f.zap(200); } assert_eq!(cell.load(SeqCst), 200); // drop interface drop(f); assert_eq!(cell.load(SeqCst), NUM_DROPPED); }