terrazzo 0.2.5

The Terrazzo library to build dynamic web pages in Rust
Documentation
use std::sync::Arc;
use std::sync::Mutex;

#[derive(Default)]
pub struct DropList(Vec<Box<dyn FnOnce() + Send>>);

#[derive(Clone, Default)]
pub struct DropListPtr(Arc<Mutex<DropList>>);

impl DropList {
    pub fn reset(&mut self) {
        *self = Self::default()
    }

    pub fn add<F>(&mut self, f: F)
    where
        F: FnOnce() + Send + 'static,
    {
        self.0.push(Box::new(f));
    }

    pub fn track<D>(&mut self, d: D)
    where
        D: Drop + Send + 'static,
    {
        self.add(move || drop(d));
    }
}

impl Drop for DropList {
    fn drop(&mut self) {
        for d in std::mem::take(&mut self.0) {
            d()
        }
    }
}

impl DropListPtr {
    pub fn reset(&self) {
        self.0.lock().expect("drop_list").reset();
    }

    pub fn add<F>(&self, f: F)
    where
        F: FnOnce() + Send + 'static,
    {
        self.0.lock().expect("drop_list").add(f);
    }

    pub fn track<D>(&self, d: D)
    where
        D: Drop + Send + 'static,
    {
        self.add(move || drop(d));
    }
}

#[cfg(test)]
mod tests {
    use std::sync::Arc;
    use std::sync::atomic::AtomicI32;
    use std::sync::atomic::Ordering::SeqCst;

    use autoclone::autoclone;

    #[autoclone]
    #[test]
    fn drop_list() {
        let counter = Arc::new(AtomicI32::new(0));
        let mut drop_list = super::DropList::default();
        drop_list.add(move || {
            autoclone!(counter);
            counter.fetch_add(1, SeqCst);
        });
        drop_list.track(scopeguard::guard(counter.clone(), |c| {
            c.fetch_add(1, SeqCst);
        }));
        drop_list.reset();
        assert_eq!(2, counter.load(SeqCst));

        drop_list.add(move || {
            autoclone!(counter);
            counter.fetch_add(1, SeqCst);
        });
        drop_list.track(scopeguard::guard(counter.clone(), |c| {
            c.fetch_add(1, SeqCst);
        }));
        drop(drop_list);
        assert_eq!(4, counter.load(SeqCst));
    }

    #[autoclone]
    #[test]
    fn drop_list_ptr() {
        let counter = Arc::new(AtomicI32::new(0));
        let drop_list = super::DropListPtr::default();
        drop_list.add(move || {
            autoclone!(counter);
            counter.fetch_add(1, SeqCst);
        });
        drop_list.track(scopeguard::guard(counter.clone(), |c| {
            c.fetch_add(1, SeqCst);
        }));
        drop_list.reset();
        assert_eq!(2, counter.load(SeqCst));

        drop_list.add(move || {
            autoclone!(counter);
            counter.fetch_add(1, SeqCst);
        });
        drop_list.track(scopeguard::guard(counter.clone(), |c| {
            c.fetch_add(1, SeqCst);
        }));
        drop(drop_list);
        assert_eq!(4, counter.load(SeqCst));
    }
}