o3 0.36.2

shared-nothing primitives
Documentation
pub mod common;

#[global_allocator]
static ALLOCATOR: Tracker = Tracker;

use std::cell::Cell;

use common::{alloc::system::Tracker, buffer::scatter::Source};
use o3::buffer::{
    pool,
    storage::{self, Owned},
    write::{self, Sink as _, SpareExt as _, consume, edit},
};

#[test]
fn keeps_bounded_group() {
    let mut owner = (Owned::try_with(7)).expect("the seven-byte staged owner must allocate");
    let mut writer = owner.spare();
    write::Sink::write_slice(&mut writer, b"ab")
        .as_ref()
        .expect("required fixture outcome");
    let mut bounded = writer.bounded();
    append(&mut bounded);
    bounded.commit();
    writer.commit();
    assert_eq!(owner.as_slice(), b"abcdefg");
}

#[test]
fn nests_prefix_edits() {
    let mut owner = Owned::try_with(8).expect("nested prefixes and body");
    let mut outer = edit::Edit::try_new(owner.spare(), b"??").expect("outer prefix");
    {
        let mut inner = edit::Edit::try_new(outer.spare(), b"??").expect("inner prefix");
        inner.write_slice(b"tail").expect("nested body");
        *inner.prefix() = *b"IN";
        inner.commit();
    }
    *outer.prefix() = *b"OU";
    outer.commit();
    assert_eq!(owner.as_slice(), b"OUINtail");
}

#[test]
fn keeps_prefixed_edit() {
    let mut owner = Owned::try_with(7).expect("prefix and tail storage");
    let mut writer = owner.spare();
    writer.write_slice(b"ab").expect("staged prefix");
    let Err(error) = edit::Edit::try_new(writer, b"longer") else {
        panic!("prefix shortfall");
    };
    let error = error.into_parts();
    assert_eq!((error.0.get(), error.1), (6, 5));
    assert!(owner.is_empty());
    {
        let mut output = edit::Edit::try_new(owner.spare(), b"??").expect("discarded prefix");
        let mut body = output.bounded();
        body.write_slice(b"lost").expect("discarded tail");
        body.commit();
        *output.prefix() = *b"NO";
    }
    assert!(owner.is_empty());

    let mut writer = owner.spare();
    writer.write_slice(b"ab").expect("staged prefix");
    let mut output = edit::Edit::try_new(writer, b"??").expect("admitted prefix");
    let mut body = output.bounded();
    body.write_slice(b"efg").expect("disjoint tail");
    body.commit();
    assert_eq!(output.len(), 7);
    *output.prefix() = *b"CD";
    output.commit();
    assert_eq!(owner.as_slice(), b"abCDefg");

    let mut empty = Owned::new();
    let mut output = edit::Edit::try_new(empty.spare(), &[]).expect("empty prefix");
    assert!(output.prefix().is_empty());
    assert!(output.is_empty());
    output.bounded().commit();
    output.commit();
    assert!(empty.is_empty());
}

#[test]
fn keeps_spare_group() {
    let mut owner = (Owned::try_with(7)).expect("the seven-byte staged owner must allocate");
    let mut writer = owner.spare();
    assert_eq!(writer.write(b"ab"), 2);
    append(&mut writer);
    assert_eq!(writer.as_mut_slice(), b"abcdefg");
    writer.commit();
    assert_eq!(owner.as_slice(), b"abcdefg");
}

#[test]
fn keeps_edit_group() {
    let mut lease = (pool::Span::try_new(7)).expect("the seven-byte edit fixture must allocate");
    lease
        .try_append(b"ab")
        .expect("required fixture outcome")
        .commit();
    let mut edit = (lease.try_prefix::<2>(0)).expect("the initialized prefix must be editable");
    edit.prefix().copy_from_slice(b"AB");
    append(&mut edit);
    edit.commit();
    assert_eq!(lease.as_slice(), b"ABcdefg");
}

#[test]
fn rollback_keeps_frames() {
    let mut bytes = Vec::with_capacity(64);
    bytes.extend_from_slice(b"header");
    let pointer = bytes.as_ptr();
    let (_, activity) = Tracker::measure(|| {
        let mut payload = write::Append::new(&mut bytes);
        assert!(payload.is_empty());
        payload.write_slice(b"first").expect("first frame");
        {
            let mut frame = payload.append();
            frame.write_byte(0xff).expect("frame type");
            frame.write_slice(&[0x11, 0x22]).expect("frame body");
            frame.try_fill(4, 0).expect("padding");
            assert_eq!(frame.len(), 7);
            frame.rollback();
        }
        assert_eq!(payload.as_ref(), b"first");
        payload.write_slice(b"second").expect("second frame");
        assert_eq!(payload.len(), 11);
    });
    assert_eq!(activity, [0; 4]);
    assert_eq!(bytes, b"headerfirstsecond");
    assert_eq!(bytes.as_ptr(), pointer);
}

#[test]
fn rejects_vector_growth() {
    let mut bytes = b"header".to_vec();
    let pointer = bytes.as_ptr();
    let source = vec![0; bytes.capacity() + 1];
    let error = Tracker::fail_after(0, || bytes.write_slices([b"prefix", &source]));
    assert_eq!(error, Err(o3::alloc::Error::Exhausted));
    let mut append = write::Append::new(&mut bytes);
    assert_eq!(
        append.try_fill(usize::MAX, 0),
        Err(o3::alloc::Error::Overflow)
    );
    assert!(append.is_empty());
    assert_eq!(bytes, b"header");
    assert_eq!(bytes.as_ptr(), pointer);
}

fn append(out: &mut impl write::Sink<Error = consume::Error>) {
    out.write_slice(b"c")
        .as_ref()
        .expect("required fixture outcome");
    out.write_slices([])
        .as_ref()
        .expect("required fixture outcome");
    let cause = out
        .write_slices([b"de".as_slice(), b"fgh".as_slice()])
        .expect_err("the second slice must exceed the reserved span");
    let (required, room) = cause.into_parts();
    assert_eq!((required.get(), room), (3, 2));
    out.write_byte(b'd')
        .as_ref()
        .expect("required fixture outcome");
    out.write_slices([b"ef".as_slice(), b"g".as_slice()])
        .as_ref()
        .expect("required fixture outcome");
}

#[test]
fn admission_then_init() {
    let calls = Cell::new(Some(0));
    let source = Source(b"body", &calls);
    let mut owner = storage::Owned::try_with(6).expect("admitted");
    let mut spare = owner.spare();
    spare.write_slice(b"hi").expect("admitted");
    {
        let mut short = spare.bounded();
        short.write_byte(0).expect("staged prefix");
        let error = short.try_init(&source).expect_err("shortfall").into_parts();
        assert_eq!((error.0.get(), error.1), (4, 3));
        assert_eq!(calls.get(), Some(0));
    }
    let mut writer = spare.bounded();
    writer.try_init(&source).expect("admitted");
    writer.commit();
    spare.try_complete().expect("admitted");
    assert_eq!(calls.get(), Some(1));
    assert_eq!(owner.as_slice(), b"hibody");
}