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<AtomicI32>,
}
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<T: com::production::Class>(c: &com::production::ClassAllocation<T>) -> u32 {
unsafe {
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);
println!("calling zap()");
unsafe {
f.zap(100);
}
assert_eq!(cell.load(SeqCst), 100);
println!("cloning server");
let server2 = server.clone();
assert_eq!(get_refcount(&server), 3);
drop(server2);
assert_eq!(get_refcount(&server), 2);
println!("cloning interface");
let f2 = f.clone();
assert_eq!(get_refcount(&server), 3);
drop(f2);
assert_eq!(get_refcount(&server), 2);
println!("dropping server ref");
drop(server);
assert_eq!(cell.load(SeqCst), 100);
println!("calling zap() again");
unsafe {
f.zap(200);
}
assert_eq!(cell.load(SeqCst), 200);
drop(f);
assert_eq!(cell.load(SeqCst), NUM_DROPPED);
}