potential-well 2.0.0

Atomic boxes.
Documentation
use core::{marker::PhantomPinned, pin::Pin, sync::atomic::Ordering::Relaxed};
use std::sync::{Arc, Weak, atomic::AtomicUsize};

use crate::{Atomic, AtomicOption, PotentialAtomicOption, PotentialWell};

#[test]
fn drop_empty() {
    let atomic = <AtomicOption<Box<&str>>>::none();
    drop(atomic);
}

#[test]
fn drop_emptied() {
    let atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    atomic.take(Relaxed).unwrap();
    drop(atomic);
}

#[test]
fn drop_filled() {
    let atomic = <AtomicOption<Box<&str>>>::none();
    assert_eq!(
        atomic.insert(Box::new("hello world"), Relaxed, Relaxed),
        Ok(())
    );
    drop(atomic);
}

#[test]
fn drop_nonempty() {
    let atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    drop(atomic);
}

#[test]
fn drop_nonoptional() {
    let atomic = <Atomic<Box<&str>>>::new(Box::new("hello world"));
    drop(atomic);
}

#[test]
fn drop_nonoptional_swapped() {
    let atomic = <Atomic<Box<&str>>>::new(Box::new("hello world"));
    atomic.swap(Box::new("hallo whirl"), Relaxed);
    drop(atomic);
}

#[test]
fn drop_swapped() {
    let atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    atomic.swap(Box::new("hallo whirl"), Relaxed);
    drop(atomic);
}

#[test]
fn insert_failure() {
    let atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    assert_eq!(
        atomic.insert(Box::new("hallo whirl"), Relaxed, Relaxed),
        Err(Box::new("hallo whirl"))
    );
    drop(atomic);
}

#[test]
fn load_empty() {
    let atomic = <AtomicOption<Box<&str>>>::none();
    assert_eq!(atomic.load(Relaxed), None);
    drop(atomic);
}

#[test]
fn load_nonempty() {
    let atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    assert_eq!(atomic.load(Relaxed), Some(&"hello world"));
    drop(atomic);
}

#[test]
fn load_empty_mut() {
    let mut atomic = <AtomicOption<Box<&str>>>::none();
    assert_eq!(atomic.load_mut(), None);
    drop(atomic);
}

#[test]
fn load_nonempty_mut() {
    let mut atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    *atomic.load_mut().unwrap() = "good bye, world!";
    assert_eq!(atomic.load(Relaxed), Some(&"good bye, world!"));
    drop(atomic);
}

#[test]
fn load() {
    let atomic = <Atomic<Box<&str>>>::new(Box::new("hello world"));
    assert_eq!(atomic.load(Relaxed), &"hello world");
    drop(atomic);
}

#[test]
fn load_mut() {
    let mut atomic = <Atomic<Box<&str>>>::new(Box::new("hello world"));
    *atomic.load_mut() = "good bye, world!";
    assert_eq!(atomic.load(Relaxed), &"good bye, world!");
    drop(atomic);
}

#[test]
fn take_failure() {
    let atomic = <AtomicOption<Box<&str>>>::none();
    assert_eq!(atomic.take(Relaxed), None);
    drop(atomic);
}

#[test]
fn clone_empty() {
    let atomic = <AtomicOption<Box<&str>>>::none();
    assert_eq!(atomic.load_clone(Relaxed), None);
    drop(atomic);
}

#[test]
fn clone_nonempty() {
    let atomic = <AtomicOption<Box<&str>>>::some(Box::new("hello world"));
    assert_eq!(atomic.load_clone(Relaxed), Some(Box::new("hello world")));
    drop(atomic);
}

#[test]
fn clone() {
    let atomic = <Atomic<Box<&str>>>::new(Box::new("hello world"));
    assert_eq!(atomic.load_clone(Relaxed), Box::new("hello world"));
    drop(atomic);
}

struct Pinned {
    marker: PhantomPinned,
    data: &'static str,
}
impl Pinned {
    fn new(data: &'static str) -> Pinned {
        Pinned {
            marker: PhantomPinned,
            data,
        }
    }
}

#[test]
fn pinned() {
    let mut atomic = <Atomic<Pin<Box<Pinned>>>>::new(Box::pin(Pinned::new("hello, world!")));
    assert_eq!(
        atomic.load_mut_pinned().into_ref().get_ref().data,
        "hello, world!"
    );
    drop(atomic);
}

#[test]
fn pinned_empty() {
    let mut atomic = <AtomicOption<Pin<Box<Pinned>>>>::none();
    assert!(atomic.load_mut_pinned().is_none());
    drop(atomic);
}

#[test]
fn pinned_nonempty() {
    let mut atomic = <AtomicOption<Pin<Box<Pinned>>>>::some(Box::pin(Pinned::new("hello, world!")));
    assert_eq!(
        atomic.load_mut_pinned().unwrap().into_ref().get_ref().data,
        "hello, world!"
    );
    drop(atomic);
}

#[allow(unused)]
struct BasicLink<T, W: PotentialWell> {
    data: T,
    next: PotentialAtomicOption<BasicLink<T, W>, W>,
}

#[allow(unused)]
struct AdvancedLink<T> {
    data: T,
    next: PotentialAtomicOption<AdvancedLink<T>, Arc<()>>,
    prev: PotentialAtomicOption<AdvancedLink<T>, Weak<()>>,
}

struct DropCheck<'a> {
    idx: usize,
    check: &'a AtomicUsize,
}
impl Drop for DropCheck<'_> {
    fn drop(&mut self) {
        assert_eq!(self.check.fetch_add(1, Relaxed), self.idx);
    }
}

#[test]
fn basic_linked_list() {
    let check = AtomicUsize::new(0);
    let list: BasicLink<DropCheck<'_>, Box<()>> = BasicLink {
        data: DropCheck {
            idx: 0,
            check: &check,
        },
        next: PotentialAtomicOption::some(Box::new(BasicLink {
            data: DropCheck {
                idx: 1,
                check: &check,
            },
            next: PotentialAtomicOption::some(Box::new(BasicLink {
                data: DropCheck {
                    idx: 2,
                    check: &check,
                },
                next: PotentialAtomicOption::none(),
            })),
        })),
    };
    drop(list);
}

#[test]
fn advanced_linked_list() {
    let check = AtomicUsize::new(0);

    let first = Arc::new(AdvancedLink {
        data: DropCheck {
            idx: 0,
            check: &check,
        },
        next: PotentialAtomicOption::none(),
        prev: PotentialAtomicOption::none(),
    });
    let middle = Arc::new(AdvancedLink {
        data: DropCheck {
            idx: 1,
            check: &check,
        },
        next: PotentialAtomicOption::none(),
        prev: PotentialAtomicOption::none(),
    });
    let last = Arc::new(AdvancedLink {
        data: DropCheck {
            idx: 2,
            check: &check,
        },
        next: PotentialAtomicOption::none(),
        prev: PotentialAtomicOption::none(),
    });

    let Ok(()) = last.prev.insert(Arc::downgrade(&middle), Relaxed, Relaxed) else {
        unreachable!()
    };
    let Ok(()) = middle.prev.insert(Arc::downgrade(&first), Relaxed, Relaxed) else {
        unreachable!()
    };
    let Ok(()) = middle.next.insert(last, Relaxed, Relaxed) else {
        unreachable!()
    };
    let Ok(()) = first.next.insert(middle, Relaxed, Relaxed) else {
        unreachable!()
    };

    let list: Arc<AdvancedLink<DropCheck<'_>>> = first;
    drop(list);
}