buffex 0.0.1

BUFFer EXtensions: ring buffer and buffer chaining.
Documentation
use core::borrow::{Borrow, BorrowMut};

use abs_buff::utils::{ReaderAsChunkFiller, ChunkWriter};
use atomex::{
    x_deps::funty,
    TrAtomicData, TrCmpxchOrderings,
};
use core_malloc::CoreAlloc;
use mm_ptr::{Shared, Owned};
use asyncex::x_deps::{atomex, mm_ptr};
use crate::ring_buffer::*;

async fn chunk_writer_<B, P, T, D, O>(writer: Writer<B, P, T, D, O>)
where
    B: Borrow<RingBuffer<P, T, D, O>>,
    P: BorrowMut<[T]>,
    T: funty::Unsigned + TryFrom<usize> + Copy,
    D: TrAtomicData + funty::Unsigned,
    O: TrCmpxchOrderings,
{
    let capacity = writer.buffer().capacity();
    let mut copier = ChunkWriter::new(writer);
    let mut span_length = 1usize;
    let init_each = |u| {
        let Result::Ok(x) = T::try_from(u) else { panic!() };
        x
    };
    loop {
        if span_length > capacity {
            break;
        }
        let source = Owned::new_slice(
            span_length,
            init_each,
            CoreAlloc::new(),
        );
        let w = copier.write_async(&source).await;
        if let Result::Err(report) = w {
            log::error!("[chunk_::chunk_writer_] span_len({span_length}) err: {report:?}");
            break;
        };
        let Result::Ok(copy_len) = w else { unreachable!() };
        log::trace!("[chunk_::chunk_writer_] span_len({span_length}) copy len({copy_len})");
        assert!(copy_len == span_length);
        span_length += 1;
    }
    log::info!("chunk writer exits");
}

async fn reader_filler_<B, P, T, D, O>(reader: Reader<B, P, T, D, O>)
where
    B: Borrow<RingBuffer<P, T, D, O>>,
    P: BorrowMut<[T]>,
    T: funty::Unsigned + TryInto<usize> + Copy,
    D: TrAtomicData + funty::Unsigned,
    O: TrCmpxchOrderings,
{
    let capacity = reader.buffer().capacity();
    let mut filler = ReaderAsChunkFiller::new(reader);
    let mut span_length = 1usize;
    loop {
        if span_length > capacity {
            break;
        }
        let mut target = Owned::new_slice(
            span_length,
            |_| T::ZERO,
            CoreAlloc::new(),
        );
        let r = filler.fill_async(&mut target).await;
        if let Result::Err(report) = r {
            log::error!("[chunk_::reader_filler_] span_len({span_length}) err: {report:?}");
            break;
        };
        let Result::Ok(fill_len) = r else { unreachable!() };
        log::trace!("[chunk_::reader_filler_] span_len({span_length}) filled len({fill_len})");
        assert!(fill_len == span_length);
        for (u, x) in target.iter().enumerate() {
            let Result::Ok(x) = (*x).try_into() else { panic!() };
            assert_eq!(u, x, "#{span_length}: u({u}) != x({x})");
        }
        span_length += 1;
    }
    log::info!("reader filler exits");
}

#[tokio::test]
async fn u8_fill_copy_async_smoke() {
    const BUFF_SIZE: u8 = 255;

    let _ = env_logger::builder().is_test(true).try_init();

    let Result::Ok(ring_buff) = RingBuffer::<Owned<[u8], CoreAlloc>>
        ::try_new(Owned::new_slice(
            usize::from(BUFF_SIZE),
            |_| 0u8,
            CoreAlloc::new(),
        ))
    else {
        panic!("[chunk_::u8_fill_copy_async_smoke] try_new")
    };

    let ring_buff = Shared::new(ring_buff, CoreAlloc::new());
    let Result::Ok((writer, reader)) = RingBuffer
        ::try_split_from_shared(ring_buff)
    else {
        panic!("[chunk_::u8_fill_copy_async_smoke] try_split_shared");
    };
    let reader_handle = tokio::task::spawn(reader_filler_(reader));
    let writer_handle = tokio::task::spawn(chunk_writer_(writer));
    assert!(writer_handle.await.is_ok());
    assert!(reader_handle.await.is_ok());
}

#[tokio::test]
async fn u16_fill_copy_async_smoke() {
    const BUFF_SIZE: u16 = 255;

    let _ = env_logger::builder().is_test(true).try_init();

    let Result::Ok(ring_buff) = RingBuffer::<Owned<[u16], CoreAlloc>, u16>
        ::try_new(Owned::new_slice(
            usize::from(BUFF_SIZE),
            |_| 0u16,
            CoreAlloc::new(),
        ))
    else {
        panic!("[chunk_::u16_fill_copy_async_smoke] try_new")
    };

    let ring_buff = Shared::new(ring_buff, CoreAlloc::new());
    let Result::Ok((writer, reader)) = RingBuffer
        ::try_split_from_shared(ring_buff)
    else {
        panic!("[chunk_::u16_fill_copy_async_smoke] try_split_shared");
    };
    let writer_handle = tokio::task::spawn(chunk_writer_(writer));
    let reader_handle = tokio::task::spawn(reader_filler_(reader));
    assert!(writer_handle.await.is_ok());
    assert!(reader_handle.await.is_ok());
}

#[tokio::test]
async fn u32_fill_copy_async_smoke() {
    const BUFF_SIZE: u32 = 255;

    let _ = env_logger::builder().is_test(true).try_init();

    let Result::Ok(ring_buff) = RingBuffer::<Owned<[u32], CoreAlloc>, u32>
        ::try_new(Owned::new_slice(
            usize::try_from(BUFF_SIZE).unwrap(),
            |_| 0u32,
            CoreAlloc::new(),
        ))
    else {
        panic!("[chunk_::u32_fill_copy_async_smoke] try_new")
    };

    let ring_buff = Shared::new(ring_buff, CoreAlloc::new());
    let Result::Ok((writer, reader)) = RingBuffer
        ::try_split_from_shared(ring_buff)
    else {
        panic!("[chunk_::u32_fill_copy_async_smoke] try_split_shared");
    };
    let writer_handle = tokio::task::spawn(chunk_writer_(writer));
    let reader_handle = tokio::task::spawn(reader_filler_(reader));
    assert!(writer_handle.await.is_ok());
    assert!(reader_handle.await.is_ok());
}