voluntary-servitude 3.0.0

Thread-safe appendable list with lock-free iterator
Documentation
#[macro_use]
extern crate voluntary_servitude;

use std::sync::{
    atomic::{AtomicBool, AtomicUsize, Ordering},
    Arc,
};
use std::{cmp::max, mem, thread::spawn};

fn setup_logger() {
    #[cfg(feature = "logs")]
    voluntary_servitude::setup_logger();
}

#[test]
fn single_thread() {
    setup_logger();
    let list = voluntary_servitude![];
    for i in 0..10000 {
        list.append(i);
    }

    for (i, el) in list.iter().enumerate() {
        assert_eq!(&i, el);
    }
}

#[test]
fn single_producer_single_consumer() {
    setup_logger();
    let count = 10000;
    let list = Arc::new(voluntary_servitude![]);
    let finished = Arc::new(AtomicBool::new(false));

    let list_clone = Arc::clone(&list);
    let finished_clone = Arc::clone(&finished);
    let _handler = spawn(move || {
        for i in 0..count {
            list_clone.append(i + 1)
        }
        finished_clone.store(true, Ordering::Relaxed);
    });

    let mut total_max = 0;
    let mut last_len = 0;
    while !finished.load(Ordering::Relaxed) {
        let mut inner_max = 0;
        let mut len = 0;
        for (i, num) in list.iter().enumerate() {
            assert_eq!(i + 1, *num);
            inner_max = max(i + 1, inner_max);
            len = i;
        }
        assert!(
            inner_max > total_max || inner_max == count || len == last_len,
            "{} > {} || {} == {} || {} == {}",
            inner_max,
            total_max,
            inner_max,
            count,
            len,
            last_len
        );
        last_len = len;
        total_max = inner_max
    }
    assert_eq!(list.iter().count(), count);
}

#[test]
fn multi_producers_single_consumer() {
    setup_logger();
    let count = 10;
    let list = Arc::new(voluntary_servitude![]);
    let num_producers = 1000;
    let mut producers = vec![];
    let finished = Arc::new(AtomicUsize::new(0));

    for _ in 0..num_producers {
        let finished = Arc::clone(&finished);
        let list = Arc::clone(&list);
        producers.push(spawn(move || {
            for i in 0..count {
                list.append(i);
            }
            finished.fetch_add(1, Ordering::Relaxed);
        }));
    }

    let mut last_len = 0;
    while finished.load(Ordering::Relaxed) < num_producers {
        let len = list.iter().count();
        assert!(len >= last_len);
        last_len = len;
    }
    let len = list.iter().count();
    assert_eq!(len, num_producers * count);
}

#[test]
fn single_producer_multi_consumer() {
    setup_logger();
    let count = 10000;
    let list = Arc::new(voluntary_servitude![]);
    let num_consumers = 1000;
    let mut consumers = vec![];
    let finished = Arc::new(AtomicBool::new(false));

    for _ in 0..num_consumers {
        let finished = Arc::clone(&finished);
        let list = Arc::clone(&list);
        consumers.push(spawn(move || {
            let mut len = 0;
            while !finished.load(Ordering::Relaxed) {
                let inner_len = list.iter().count();
                assert!(inner_len >= len);
                len = inner_len;
            }
            len = list.iter().count();
            assert_eq!(len, list.iter().count());
            assert_eq!(len, count);
        }));
    }

    for i in 0..count {
        list.append(i);
    }
    finished.store(true, Ordering::Relaxed);

    for thread in consumers {
        thread.join().unwrap();
    }
}

#[test]
fn multi_producer_multi_consumer() {
    setup_logger();
    let count = 10;
    let list = Arc::new(voluntary_servitude![]);
    let num_producers = 1000;
    let mut producers = vec![];
    let finished = Arc::new(AtomicUsize::new(0));

    let num_consumers = 1000;
    let mut consumers = vec![];

    for _ in 0..num_producers {
        let finished = Arc::clone(&finished);
        let list = Arc::clone(&list);
        producers.push(spawn(move || {
            for i in 0..count {
                list.append(i);
            }
            finished.fetch_add(1, Ordering::Relaxed);
        }));
    }

    for _ in 0..num_consumers {
        let finished = Arc::clone(&finished);
        let list = Arc::clone(&list);
        consumers.push(spawn(move || {
            let mut len = 0;
            while finished.load(Ordering::Relaxed) < num_producers {
                let inner_len = list.iter().count();
                assert!(inner_len >= len);
                len = inner_len;
            }
            len = list.iter().count();
            assert_eq!(len, list.iter().count());
            assert_eq!(len, count * num_producers);
        }));
    }

    for (consumer, producer) in consumers.into_iter().zip(producers) {
        consumer.join().unwrap();
        producer.join().unwrap();
    }
}

#[test]
fn clear() {
    setup_logger();
    let list = voluntary_servitude![1];
    assert_eq!(list.iter().count(), 1);
    list.clear();
    assert_eq!(list.iter().count(), 0);
    list.append(3);
    list.append(3);
    list.append(3);
    list.clear();
    assert_eq!(list.iter().count(), 0);
}

fn elements_n(num: usize) {
    println!("{} users", num);
    setup_logger();
    let list = voluntary_servitude![];
    for i in 0..num {
        list.append(i);
    }
    assert_eq!(list.iter().count(), num);
    assert_eq!(list.iter().next(), Some(&0));
    for (i, el) in list.iter().enumerate() {
        assert_eq!(*el, i);
    }

    let mut iter = list.iter();
    let iter_count = list.iter();
    mem::drop(list);
    assert_eq!(iter_count.count(), num);
    assert_eq!(iter.next(), Some(&0));
}

#[test]
fn elements_100k() {
    elements_n(100_000);
}

#[test]
#[ignore]
fn elements_1m() {
    elements_n(500_000);
    elements_n(1_000_000);
}

#[test]
#[ignore]
fn elements_50m() {
    elements_n(10_000_000);
    elements_n(50_000_000);
}

#[test]
#[ignore]
fn elements_500m() {
    elements_n(100_000_000);
    elements_n(500_000_000);
}

#[test]
#[ignore]
fn elements_1b() {
    elements_n(1_000_000_000);
}