o3 0.36.2

shared-nothing primitives
Documentation
use std::{mem::size_of, num::NonZero};

use o3::base::{
    marker::ThreadBound,
    num::{
        Epoch, Generation,
        bounded::{Error, NonZeroU32, NonZeroUsize, Overflow, U32, U64, Usize},
    },
};

#[test]
fn u32_bounds() {
    assert!((U32::<1, 65_535>::new(0)).is_none());
    assert_eq!(U32::<1, 65_535>::new(1).map(U32::get), Some(1));
    assert_eq!(U32::<1, 65_535>::new(65_535).map(U32::get), Some(65_535));
    assert!((U32::<1, 65_535>::new(65_536)).is_none());
    assert_eq!(
        U32::<0, { u32::MAX }>::from_usize(u32::MAX as usize).map(U32::get),
        Some(u32::MAX)
    );
    assert!((U32::<0, { u32::MAX }>::from_usize(u32::MAX as usize + 1)).is_none());
    assert!((U32::<2, 1>::new(1)).is_none());
    assert!((U32::<2, 1>::new(2)).is_none());
    assert_eq!(size_of::<U32<1, 31>>(), size_of::<u32>());
}

#[test]
fn nonzero_u32_bounds() {
    const MIN: NonZeroU32<3, 7> = NonZeroU32::exact::<3>();
    assert_eq!(NonZeroU32::new(3), Some(MIN));
    assert_eq!(
        [0, 2, 7, 8].map(|value| NonZeroU32::<3, 7>::new(value).map(NonZeroU32::get)),
        [None, None, Some(7), None]
    );
    let max = NonZeroU32::<3, 7>::from_usize(7).expect("inclusive upper bound");
    assert_eq!(max.nonzero().get(), 7);
    assert_eq!(max.into_u32().get(), 7);
    assert_eq!(max.into_usize(), 7);
    assert!(NonZeroU32::<1, { u32::MAX }>::from_usize(usize::MAX).is_none());
}

#[test]
fn nonzero_usize_bounds() {
    assert_eq!(
        [0, 2, 3, 7, 8].map(|value| NonZeroUsize::<3, 7>::new(value).map(NonZeroUsize::get)),
        [None, None, Some(3), Some(7), None]
    );
    let bound = NonZeroUsize::<3, 7>::new(3).expect("inclusive lower bound");
    assert_eq!(bound.into_count().get(), 3);
    assert_eq!(bound.prior().get(), 2);
}

#[test]
fn count_preserves_bounds() {
    let one = NonZeroUsize::<1, 1>::new(1).expect("single capacity");
    assert_eq!(one.after(Usize::ZERO), Some(one));
    assert_eq!(one.after(one.into_count()), None);
    let max = NonZeroUsize::<1, { usize::MAX }>::new(usize::MAX).expect("full capacity");
    assert_eq!(max.after(max.prior()), Some(max));
    assert_eq!(max.after(max.into_count()), None);
    const EMPTY: Option<NonZeroUsize<1, 0>> = Usize::<0>::ZERO.nonzero();
    assert!(EMPTY.is_none());
    let one = Usize::<1>::ZERO.try_add(1).expect("single capacity");
    assert_eq!(one.nonzero().map(NonZeroUsize::get), Some(1));
    let full = Usize::<{ usize::MAX }>::ZERO
        .try_add(usize::MAX)
        .expect("full capacity");
    assert_eq!(full.nonzero().map(NonZeroUsize::get), Some(usize::MAX));
    assert_eq!(
        full.try_add(1),
        Err(Error {
            value: usize::MAX,
            incoming: NonZero::<usize>::MIN,
            maximum: usize::MAX,
        })
    );
}

#[test]
fn one_based_retains_bounds() {
    assert_eq!(U32::from_one(NonZero::<u32>::MIN).into_usize(), 0);
    assert_eq!(
        U32::from_one(NonZero::<u32>::MAX).into_usize(),
        u32::MAX as usize - 1
    );
    const ZERO: U32<0, 0> = NonZeroU32::<1, 1>::exact::<1>().into_index();
    const LAST: U32<0, { u32::MAX - 1 }> =
        NonZeroU32::<1, { u32::MAX }>::exact::<{ u32::MAX }>().into_index();
    assert_eq!((ZERO.get(), LAST.get()), (0, u32::MAX - 1));
    assert_eq!(NonZeroU32::<3, 7>::exact::<3>().into_index::<6>().get(), 2);
}

#[test]
fn u32_exact_overflow() {
    const ZERO: Result<U32<0, 0>, Overflow<0>> = U32::try_usize(0);
    assert_eq!(ZERO.expect("zero belongs to the zero domain").get(), 0);
    assert!(matches!(U32::<0, 0>::try_usize(1), Err(error) if error.actual() == 1));
    assert_eq!(U32::<0, 7>::try_usize(7).expect("inclusive limit").get(), 7);
    assert!(matches!(U32::<0, 7>::try_usize(8), Err(error) if error.actual() == 8));
    assert!(
        matches!(U32::<0, 7>::try_usize(usize::MAX), Err(error) if error.actual() == usize::MAX)
    );
    assert_eq!(
        U32::<0, { u32::MAX }>::try_usize(u32::MAX as usize)
            .expect("full u32 domain")
            .get(),
        u32::MAX
    );
    assert!(
        matches!(U32::<0, { u32::MAX }>::try_usize(usize::MAX), Err(error) if error.actual() == usize::MAX)
    );
}

#[test]
fn u32_clamps() {
    assert_eq!(U32::<3, 7>::clamp(2).get(), 3);
    assert_eq!(U32::<3, 7>::clamp(5).get(), 5);
    assert_eq!(U32::<3, 7>::clamp(8).get(), 7);
    assert_eq!(U32::<3, 7>::new(5).map(U32::into_usize), Some(5));
}

#[test]
fn u32_reuses_bounds() {
    const LOW: U32<0, 9> = U32::<3, 7>::exact::<3>().widen();
    const HIGH: U32<0, 9> = U32::<3, 7>::exact::<7>().widen();
    const SAME: U32<3, 7> = U32::<3, 7>::exact::<7>().widen();
    assert_eq!((LOW.get(), HIGH.get(), SAME.get()), (3, 7, 7));
}

#[test]
fn u32_derived_bounds() {
    const LOW: U32<3, 7> = U32::exact::<3>();
    const HIGH: U32<3, 7> = U32::exact::<7>();
    const DIFFERENCE: U32<0, 7> = LOW.abs_diff(HIGH);
    assert_eq!(
        (
            DIFFERENCE.get(),
            HIGH.abs_diff(LOW).get(),
            LOW.abs_diff(LOW).get()
        ),
        (4, 4, 0)
    );
    assert_eq!(
        U32::<0, { u32::MAX }>::exact::<0>()
            .abs_diff(U32::exact::<{ u32::MAX }>())
            .get(),
        u32::MAX
    );
    assert_eq!(U32::<0, 7>::prefix(usize::MAX, U32::exact::<0>()).get(), 0);
    assert_eq!(
        [0, 3, usize::MAX].map(|value| U32::<0, 7>::prefix(value, U32::exact::<7>()).get()),
        [0, 3, 7]
    );
}

#[test]
fn u64_keeps_domain_layout() {
    assert_eq!(
        U64::<0, { (1 << 62) - 1 }>::clamp(u64::MAX).get(),
        (1 << 62) - 1
    );
    assert_eq!(U64::<3, 7>::clamp(2).get(), 3);
    assert_eq!(U64::<0, { (1 << 62) - 1 }>::new(0).map(U64::get), Some(0));
    assert_eq!(
        U64::<0, { (1 << 62) - 1 }>::new((1 << 62) - 1).map(U64::get),
        Some((1 << 62) - 1)
    );
    assert!((U64::<0, { (1 << 62) - 1 }>::new(1 << 62)).is_none());
    assert_eq!(
        U64::<0, { (1 << 62) - 1 }>::from_usize(63).map(U64::get),
        Some(63)
    );
    assert!((U64::<2, 1>::new(1)).is_none());
    assert_eq!(
        [0, 0b1100, u64::MAX].map(|value| U64::<0, 0b1010>::mask(value).get()),
        [0, 0b1000, 0b1010]
    );
    assert_eq!(
        (
            U64::<0, 0>::mask(u64::MAX).get(),
            U64::<0, { u64::MAX }>::mask(u64::MAX).get()
        ),
        (0, u64::MAX)
    );
    assert_eq!(size_of::<U64<0, { (1 << 62) - 1 }>>(), size_of::<u64>());
}

#[test]
fn u64_subtraction_preserves_bounds() {
    const BOUND: U64<0, 7> = U64::mask(7);
    const BEFORE: Option<U64<0, 7>> = BOUND.checked_sub(1);
    assert_eq!(BEFORE.map(U64::get), Some(6));
    assert_eq!(
        [0, 7, 8].map(|value| BOUND.checked_sub(value).map(U64::get)),
        [Some(7), Some(0), None]
    );
    assert_eq!(U64::<0, 0>::mask(0).checked_sub(0).map(U64::get), Some(0));
    assert_eq!(
        U64::<0, { u64::MAX }>::mask(u64::MAX)
            .checked_sub(0)
            .map(U64::get),
        Some(u64::MAX)
    );
}

#[test]
fn stops_at_last_identity() {
    let before = Generation::from_raw(u32::MAX - 1);
    let last = (before.next()).expect("the final generation must remain representable");
    assert_eq!(last.get(), u32::MAX);
    assert!((last.next()).is_none());
    assert!((Generation::<0>::INITIAL.next()).is_none());
    let before = Epoch::new(
        NonZero::new(u64::MAX - 1).expect("nonzero identity"),
        ThreadBound::NEW,
    );
    let last = before.checked_add(1).expect("final epoch");
    assert_eq!(last.get().get(), u64::MAX);
    assert!(last.checked_add(1).is_none());
}