use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::Arc;
#[derive(Debug, Clone, Default)]
pub struct Viewer(Arc<AtomicUsize>);
impl Viewer {
pub fn get(&self) -> usize {
self.0.load(Ordering::Relaxed)
}
fn inc(&self) {
let prev = self.0.fetch_add(1, Ordering::Relaxed);
assert!(prev < usize::MAX);
}
}
#[derive(Debug)]
pub struct Counter(Viewer);
impl Counter {
pub fn get(&self) -> usize {
self.0.get()
}
pub fn new() -> Self {
new().0
}
}
impl Default for Counter {
fn default() -> Self {
Self::new()
}
}
impl Drop for Counter {
fn drop(&mut self) {
self.0.inc();
}
}
pub fn new() -> (Counter, Viewer) {
let arc = Arc::new(AtomicUsize::new(0));
let viewer = Viewer(arc.clone());
let counter = Counter(viewer.clone());
(counter, viewer)
}
pub fn new_vec(size: usize) -> (Vec<Counter>, Vec<Viewer>) {
(0..size).map(|_| new()).unzip()
}
#[cfg(test)]
mod tests {
use crate::dropcount;
#[test]
fn new() {
let (counter, viewer) = dropcount::new();
assert_eq!(viewer.get(), 0);
assert_eq!(counter.get(), 0);
drop(counter);
assert_eq!(viewer.get(), 1);
}
#[test]
fn new_vec() {
let (counters, viewers) = dropcount::new_vec(5);
assert_eq!(viewers.len(), 5);
assert_eq!(counters.len(), 5);
assert_eq!(viewers[0].get(), 0);
assert_eq!(viewers[1].get(), 0);
assert_eq!(viewers[2].get(), 0);
assert_eq!(viewers[3].get(), 0);
assert_eq!(viewers[4].get(), 0);
assert_eq!(counters[0].get(), 0);
assert_eq!(counters[1].get(), 0);
assert_eq!(counters[2].get(), 0);
assert_eq!(counters[3].get(), 0);
assert_eq!(counters[4].get(), 0);
drop(counters);
assert_eq!(viewers[0].get(), 1);
assert_eq!(viewers[1].get(), 1);
assert_eq!(viewers[2].get(), 1);
assert_eq!(viewers[3].get(), 1);
assert_eq!(viewers[4].get(), 1);
}
#[test]
fn vec_pop() {
let (mut counters, viewers) = dropcount::new_vec(5);
assert_eq!(viewers.len(), 5);
assert_eq!(counters.len(), 5);
assert_eq!(viewers[0].get(), 0);
assert_eq!(viewers[1].get(), 0);
assert_eq!(viewers[2].get(), 0);
assert_eq!(viewers[3].get(), 0);
assert_eq!(viewers[4].get(), 0);
assert_eq!(counters[0].get(), 0);
assert_eq!(counters[1].get(), 0);
assert_eq!(counters[2].get(), 0);
assert_eq!(counters[3].get(), 0);
assert_eq!(counters[4].get(), 0);
counters.pop();
assert_eq!(viewers[0].get(), 0);
assert_eq!(viewers[1].get(), 0);
assert_eq!(viewers[2].get(), 0);
assert_eq!(viewers[3].get(), 0);
assert_eq!(viewers[4].get(), 1);
assert_eq!(counters[0].get(), 0);
assert_eq!(counters[1].get(), 0);
assert_eq!(counters[2].get(), 0);
assert_eq!(counters[3].get(), 0);
counters.pop();
assert_eq!(viewers[0].get(), 0);
assert_eq!(viewers[1].get(), 0);
assert_eq!(viewers[2].get(), 0);
assert_eq!(viewers[3].get(), 1);
assert_eq!(viewers[4].get(), 1);
assert_eq!(counters[0].get(), 0);
assert_eq!(counters[1].get(), 0);
assert_eq!(counters[2].get(), 0);
}
#[test]
fn vec_drain() {
let (mut counters, viewers) = dropcount::new_vec(5);
assert_eq!(viewers.len(), 5);
assert_eq!(counters.len(), 5);
assert_eq!(viewers[0].get(), 0);
assert_eq!(viewers[1].get(), 0);
assert_eq!(viewers[2].get(), 0);
assert_eq!(viewers[3].get(), 0);
assert_eq!(viewers[4].get(), 0);
assert_eq!(counters[0].get(), 0);
assert_eq!(counters[1].get(), 0);
assert_eq!(counters[2].get(), 0);
assert_eq!(counters[3].get(), 0);
assert_eq!(counters[4].get(), 0);
counters.drain(1..3);
assert_eq!(viewers[0].get(), 0);
assert_eq!(viewers[1].get(), 1);
assert_eq!(viewers[2].get(), 1);
assert_eq!(viewers[3].get(), 0);
assert_eq!(viewers[4].get(), 0);
assert_eq!(counters[0].get(), 0);
assert_eq!(counters[1].get(), 0);
assert_eq!(counters[2].get(), 0);
counters.drain(..);
assert_eq!(viewers[0].get(), 1);
assert_eq!(viewers[1].get(), 1);
assert_eq!(viewers[2].get(), 1);
assert_eq!(viewers[3].get(), 1);
assert_eq!(viewers[4].get(), 1);
}
#[test]
fn vec_push() {
let (mut counters, viewers) = dropcount::new_vec(5);
assert_eq!(viewers.len(), 5);
assert_eq!(counters.len(), 5);
assert_eq!(viewers[0].get(), 0);
assert_eq!(viewers[1].get(), 0);
assert_eq!(viewers[2].get(), 0);
assert_eq!(viewers[3].get(), 0);
assert_eq!(viewers[4].get(), 0);
assert_eq!(counters[0].get(), 0);
assert_eq!(counters[1].get(), 0);
assert_eq!(counters[2].get(), 0);
assert_eq!(counters[3].get(), 0);
assert_eq!(counters[4].get(), 0);
counters.push(dropcount::Counter::new());
counters.push(dropcount::Counter::new());
counters.push(dropcount::Counter::new());
assert_eq!(viewers[0].get(), 0);
assert_eq!(viewers[1].get(), 0);
assert_eq!(viewers[2].get(), 0);
assert_eq!(viewers[3].get(), 0);
assert_eq!(viewers[4].get(), 0);
assert_eq!(counters[0].get(), 0);
assert_eq!(counters[1].get(), 0);
assert_eq!(counters[2].get(), 0);
assert_eq!(counters[3].get(), 0);
assert_eq!(counters[4].get(), 0);
assert_eq!(counters[5].get(), 0);
assert_eq!(counters[6].get(), 0);
assert_eq!(counters[7].get(), 0);
counters.drain(3..7);
assert_eq!(viewers[0].get(), 0);
assert_eq!(viewers[1].get(), 0);
assert_eq!(viewers[2].get(), 0);
assert_eq!(viewers[3].get(), 1);
assert_eq!(viewers[4].get(), 1);
assert_eq!(counters[0].get(), 0);
assert_eq!(counters[1].get(), 0);
assert_eq!(counters[2].get(), 0);
assert_eq!(counters[3].get(), 0);
}
#[test]
fn new_counter() {
let counter = dropcount::Counter::new();
assert_eq!(counter.get(), 0);
}
#[test]
fn default_counter() {
let counter = dropcount::Counter::default();
assert_eq!(counter.get(), 0);
}
#[test]
fn do_drop() {
let (counter, viewer) = dropcount::new();
assert_eq!(viewer.get(), 0);
assert_eq!(counter.get(), 0);
drop(counter);
assert_eq!(viewer.get(), 1);
}
#[test]
fn drop_in_place() {
let (mut counter, viewer) = dropcount::new();
assert_eq!(viewer.get(), 0);
assert_eq!(counter.get(), 0);
unsafe {
std::ptr::drop_in_place(&mut counter as *mut _);
}
assert_eq!(viewer.get(), 1);
assert_eq!(counter.get(), 1);
std::mem::forget(counter);
}
#[test]
fn drop_after_forget() {
let ptr: *mut crate::dropcount::Counter;
{
let (mut counter, viewer) = dropcount::new();
ptr = &mut counter as *mut _;
assert_eq!(viewer.get(), 0);
assert_eq!(counter.get(), 0);
std::mem::forget(counter);
}
unsafe {
std::ptr::drop_in_place(ptr);
assert_eq!(ptr.as_ref().unwrap().get(), 1);
}
}
}