inlined 0.1.1

Types for inlining small collections for avoiding unnecessary heap allocations
Documentation
use std::{
    fmt::Debug,
    ops::{Deref, DerefMut},
    sync::{atomic::AtomicBool, Arc},
};

pub struct DropChecker {
    tracked: Vec<Arc<DropCheckTracker>>,
}

impl DropChecker {
    pub const fn new() -> Self {
        Self { tracked: Vec::new() }
    }

    pub fn track<T: ToString>(&mut self, value: T) -> DC<T> {
        let tracker = Arc::new(DropCheckTracker {
            was_dropped: AtomicBool::new(false),
            name: Some(value.to_string()),
        });

        self.tracked.push(Arc::clone(&tracker));
        DC { tracker, value }
    }

    pub fn track_named<T, S: ToString>(&mut self, name: S, value: T) -> DC<T> {
        let tracker = Arc::new(DropCheckTracker {
            was_dropped: AtomicBool::new(false),
            name: Some(name.to_string()),
        });

        self.tracked.push(Arc::clone(&tracker));
        DC { tracker, value }
    }

    pub fn track_unnamed<T>(&mut self, value: T) -> DC<T> {
        let tracker = Arc::new(DropCheckTracker {
            was_dropped: AtomicBool::new(false),
            name: None,
        });

        self.tracked.push(Arc::clone(&tracker));
        DC { tracker, value }
    }

    pub fn ensure_all_dropped(&mut self) {
        for t in self.tracked.drain(..) {
            if !t.was_dropped.load(std::sync::atomic::Ordering::Relaxed) {
                match &t.name {
                    None => panic!("An unnamed value wasn't dropped"),
                    Some(name) => panic!("A value named {name} wasn't dropped"),
                }
            }
        }
    }
}

struct DropCheckTracker {
    was_dropped: AtomicBool,
    name: Option<String>,
}

impl Drop for DropChecker {
    fn drop(&mut self) {
        self.ensure_all_dropped()
    }
}

pub struct DC<T> {
    tracker: Arc<DropCheckTracker>,
    pub value: T,
}

impl<T> Deref for DC<T> {
    type Target = T;

    fn deref(&self) -> &Self::Target {
        &self.value
    }
}

impl<T> DerefMut for DC<T> {
    fn deref_mut(&mut self) -> &mut Self::Target {
        &mut self.value
    }
}

impl<T> Drop for DC<T> {
    fn drop(&mut self) {
        if self.tracker.was_dropped.swap(true, std::sync::atomic::Ordering::Relaxed) {
            match &self.tracker.name {
                None => panic!("An unnamed value was double-dropped"),
                Some(name) => panic!("A value named {name} was double-dropped"),
            }
        }
    }
}

impl<T: Debug> Debug for DC<T> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        Debug::fmt(self.deref(), f)
    }
}

impl<T: PartialEq> PartialEq for DC<T> {
    fn eq(&self, other: &Self) -> bool {
        self.value.eq(&other.value)
    }
}

impl<T: Eq> Eq for DC<T> {}