once-list 0.1.1

an append-only per-item list
Documentation
use std::sync::OnceLock;

/// ```
/// use std::sync::{atomic::{AtomicU32, Ordering}};
/// use std::thread;
/// use once_list::OnceList;
///
/// // Let's exercise this new Sync append-only list by doing a little counting
/// static LIST: OnceList<u32> = OnceList::new();
/// static COUNTER: AtomicU32 = AtomicU32::new(0);
///
/// let vec = (0..thread::available_parallelism().unwrap().get()).map(|_| thread::spawn(|| {
///     while let i @ 0..1000 = COUNTER.fetch_add(1, Ordering::Relaxed) {
///         LIST.push(i);
///     }
/// })).collect::<Vec<thread::JoinHandle<_>>>();
/// vec.into_iter().for_each(|handle| handle.join().unwrap());
///
/// for i in 0..1000 {
///     assert!(LIST.contains(&i));
/// }
/// ```
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OnceList<T> {
    data: OnceLock<T>,
    next: OnceLock<Box<OnceList<T>>>,
}
impl<T> Default for OnceList<T> {
    fn default() -> Self {
        OnceList::new()
    }
}
impl<T> OnceList<T> {
    pub const fn new() -> OnceList<T> {
        OnceList { data: OnceLock::new(), next: OnceLock::new() }
    }
    pub fn push(&self, value: T) {
        // FIXME: this impl is concise, but is also slow for long lists or many threads.
        // as an exercise, consider how you might improve on it while preserving the behavior
        if let Err(value) = self.data.set(value) {
            let next = self.next.get_or_init(|| Box::new(OnceList::new()));
            next.push(value)
        };
    }
    pub fn contains(&self, example: &T) -> bool
    where
        T: PartialEq,
    {
        self.data
            .get()
            .and_then(|item| (item == example).then_some(true))
            .unwrap_or_else(|| self.next.get().map(|next| next.contains(example)).unwrap_or(false))
    }
}