o3 0.16.2

shared-nothing primitives
Documentation
use std::{cell::Cell, mem};

use o3::collections::fixed::array::{CopyInline, Inline};

#[test]
fn array_vec_keeps_values_inline_and_in_order() {
    let values: Inline<_, 4> = Inline::from_fn(3, |index| index + 1);
    assert_eq!(
        mem::size_of::<Inline<u64, 4>>(),
        5 * mem::size_of::<usize>()
    );
    assert_eq!(values.into_iter().collect::<Vec<_>>(), vec![1, 2, 3]);
}

#[test]
fn copy_array_clone_preserves_the_initialized_prefix() {
    #[repr(C)]
    struct CompactBytes {
        entries: [u8; 65],
        len: u32,
    }

    let mut values = CopyInline::<_, 4>::new();
    values.push(3).unwrap();
    values.push(5).unwrap();

    assert_eq!(values.clone().as_slice(), [3, 5]);
    assert!(!mem::needs_drop::<CopyInline<u64, 4>>());
    assert_eq!(
        mem::size_of::<CopyInline<u64, 4>>(),
        mem::size_of::<[u64; 4]>() + mem::size_of::<usize>()
    );
    assert_eq!(
        mem::size_of::<CopyInline<u8, 65>>(),
        mem::size_of::<CompactBytes>()
    );
}

#[test]
fn copy_array_mutation_is_bounded_and_atomic() {
    let mut values = CopyInline::<_, 4>::new();
    values.push(3).unwrap();
    values.push(7).unwrap();
    values.insert(1, 5).unwrap();
    assert_eq!(values.as_slice(), [3, 5, 7]);

    assert_eq!(values.try_extend_from_slice(&[9, 11]), Err(&[9, 11][..]));
    assert_eq!(values.as_slice(), [3, 5, 7]);

    assert_eq!(values.insert(4, 13), Err(13));
    assert_eq!(values.as_slice(), [3, 5, 7]);

    values.as_mut_slice()[1] = 6;
    assert_eq!(values.pop(), Some(7));
    assert_eq!(values.as_slice(), [3, 6]);
}

#[test]
fn array_vec_releases_every_value_when_drop_panics() {
    struct PanicDrop<'a> {
        drops: &'a Cell<usize>,
        panic_once: &'a Cell<bool>,
    }

    impl Drop for PanicDrop<'_> {
        fn drop(&mut self) {
            self.drops.set(self.drops.get() + 1);
            if self.panic_once.replace(false) {
                panic!("drop panic");
            }
        }
    }

    let drops = Cell::new(0);
    let panic_once = Cell::new(true);
    let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
        drop(Inline::<_, 2>::from_fn(2, |_| PanicDrop {
            drops: &drops,
            panic_once: &panic_once,
        }));
    }));
    assert!(result.is_err());
    assert_eq!(drops.get(), 2);
}

#[test]
fn owned_array_truncation_releases_the_exact_suffix_after_a_drop_panic() {
    struct PanicDrop<'a> {
        drops: &'a Cell<usize>,
        panic_once: &'a Cell<bool>,
    }

    impl Drop for PanicDrop<'_> {
        fn drop(&mut self) {
            self.drops.set(self.drops.get() + 1);
            if self.panic_once.replace(false) {
                panic!("drop panic");
            }
        }
    }

    let drops = Cell::new(0);
    let panic_once = Cell::new(true);
    let mut values = Inline::<_, 3>::from_fn(3, |_| PanicDrop {
        drops: &drops,
        panic_once: &panic_once,
    });
    let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
        values.truncate(0);
    }));
    assert!(result.is_err());
    assert_eq!(drops.get(), 3);
    assert!(values.is_empty());
}