extern-trait 0.4.2

Opaque types for traits using static dispatch
Documentation
use std::sync::atomic::{AtomicUsize, Ordering};

use extern_trait::extern_trait;

static DROPS: AtomicUsize = AtomicUsize::new(0);

#[extern_trait(DropProxy)]
trait DropApi {
    fn new(v: usize) -> Self;
    fn value(&self) -> usize;
}

mod drop_impl {
    use super::*;

    struct DropImpl(usize);

    impl Drop for DropImpl {
        fn drop(&mut self) {
            DROPS.fetch_add(1, Ordering::SeqCst);
        }
    }

    #[extern_trait]
    impl DropApi for DropImpl {
        fn new(v: usize) -> Self {
            Self(v)
        }

        fn value(&self) -> usize {
            self.0
        }
    }
}

#[test]
fn proxy_drop_runs_impl_drop_exactly_once() {
    DROPS.store(0, Ordering::SeqCst);

    {
        let p = DropProxy::new(7);
        assert_eq!(p.value(), 7);
        assert_eq!(DROPS.load(Ordering::SeqCst), 0);
    }

    assert_eq!(DROPS.load(Ordering::SeqCst), 1);
}