buffer-trait 0.2.2

A `Buffer` trait for reading into uninitialized buffers.
Documentation
use buffer_trait::*;
use core::cmp::min;
use core::mem::MaybeUninit;
use std::io::IoSliceMut;

fn main() {
    unsafely();
    safely();
    safely_fast();
    wrap();
    borrow_and_wrap();
    println!("Ok!");
}

/// Call `unsafely_read` with various kinds of buffers.
fn unsafely() {
    let mut plain_buf = [0_u8; 10];

    let num = unsafely_read(&mut plain_buf);
    assert_eq!(num, 8);
    assert_eq!(&plain_buf, &[0, 1, 2, 3, 4, 5, 6, 7, 0, 0]);

    let mut uninit_buf = [MaybeUninit::<u8>::uninit(); 10];

    let (init, uninit) = unsafely_read(&mut uninit_buf);
    assert_eq!(init, &[0, 1, 2, 3, 4, 5, 6, 7]);
    assert_eq!(uninit.len(), 2);

    let mut vec_buf = Vec::with_capacity(10);

    let num = unsafely_read(spare_capacity(&mut vec_buf));
    assert_eq!(num, 8);
    assert_eq!(vec_buf.capacity(), 10);
    assert_eq!(vec_buf.len(), 8);
    assert_eq!(&vec_buf, &[0, 1, 2, 3, 4, 5, 6, 7]);

    let mut plain_buf = [0_u8; 10];
    let mut io_slice = IoSliceMut::new(&mut plain_buf);
    let num = unsafely_read(&mut io_slice);
    assert_eq!(num, 8);
    assert_eq!(&plain_buf, &[0, 1, 2, 3, 4, 5, 6, 7, 0, 0]);
}

/// Same as `unsafely` but call `safely_read` instead.
fn safely() {
    let mut plain_buf = [0_u8; 10];

    let num = safely_read(&mut plain_buf);
    assert_eq!(num, 8);
    assert_eq!(&plain_buf, &[0, 1, 2, 3, 4, 5, 6, 7, 0, 0]);

    let mut uninit_buf = [MaybeUninit::<u8>::uninit(); 10];

    let (init, uninit) = safely_read(&mut uninit_buf);
    assert_eq!(init, &[0, 1, 2, 3, 4, 5, 6, 7]);
    assert_eq!(uninit.len(), 2);

    let mut vec_buf = Vec::with_capacity(10);

    let num = safely_read(spare_capacity(&mut vec_buf));
    assert_eq!(num, 8);
    assert_eq!(vec_buf.capacity(), 10);
    assert_eq!(vec_buf.len(), 8);
    assert_eq!(&vec_buf, &[0, 1, 2, 3, 4, 5, 6, 7]);

    let mut plain_buf = [0_u8; 10];
    let mut io_slice = IoSliceMut::new(&mut plain_buf);
    let num = safely_read(&mut io_slice);
    assert_eq!(num, 8);
    assert_eq!(&plain_buf, &[0, 1, 2, 3, 4, 5, 6, 7, 0, 0]);
}

/// Same as `safely` but call `safely_read_fast` instead.
fn safely_fast() {
    let mut plain_buf = [0_u8; 10];

    let num = safely_read_fast(&mut plain_buf);
    assert_eq!(num, 8);
    assert_eq!(&plain_buf, &[0, 1, 2, 3, 4, 5, 6, 7, 0, 0]);

    let mut uninit_buf = [MaybeUninit::<u8>::uninit(); 10];

    let (init, uninit) = safely_read_fast(&mut uninit_buf);
    assert_eq!(init, &[0, 1, 2, 3, 4, 5, 6, 7]);
    assert_eq!(uninit.len(), 2);

    let mut vec_buf = Vec::with_capacity(10);

    let num = safely_read_fast(spare_capacity(&mut vec_buf));
    assert_eq!(num, 8);
    assert_eq!(vec_buf.capacity(), 10);
    assert_eq!(vec_buf.len(), 8);
    assert_eq!(&vec_buf, &[0, 1, 2, 3, 4, 5, 6, 7]);

    let mut plain_buf = [0_u8; 10];
    let mut io_slice = IoSliceMut::new(&mut plain_buf);
    let num = safely_read_fast(&mut io_slice);
    assert_eq!(num, 8);
    assert_eq!(&plain_buf, &[0, 1, 2, 3, 4, 5, 6, 7, 0, 0]);
}

/// Same as `safely` but call `wrap_read` instead.
fn wrap() {
    let mut plain_buf = [0_u8; 10];

    let num = wrap_read(&mut plain_buf);
    assert_eq!(num, 8);
    assert_eq!(&plain_buf, &[0, 1, 2, 3, 4, 5, 6, 7, 0, 0]);

    let mut uninit_buf = [MaybeUninit::<u8>::uninit(); 10];

    let (init, uninit) = wrap_read(&mut uninit_buf);
    assert_eq!(init, &[0, 1, 2, 3, 4, 5, 6, 7]);
    assert_eq!(uninit.len(), 2);

    let mut vec_buf = Vec::with_capacity(10);

    let num = wrap_read(spare_capacity(&mut vec_buf));
    assert_eq!(num, 8);
    assert_eq!(vec_buf.capacity(), 10);
    assert_eq!(vec_buf.len(), 8);
    assert_eq!(&vec_buf, &[0, 1, 2, 3, 4, 5, 6, 7]);

    let mut plain_buf = [0_u8; 10];
    let mut io_slice = IoSliceMut::new(&mut plain_buf);
    let num = wrap_read(&mut io_slice);
    assert_eq!(num, 8);
    assert_eq!(&plain_buf, &[0, 1, 2, 3, 4, 5, 6, 7, 0, 0]);
}

/// Same as `safely` but call `borrow_and_wrap_read` instead.
fn borrow_and_wrap() {
    let mut plain_buf = [0_u8; 10];

    let num = borrow_and_wrap_read(&mut plain_buf);
    assert_eq!(num, 8);
    assert_eq!(&plain_buf, &[0, 1, 2, 3, 4, 5, 6, 7, 0, 0]);

    let mut uninit_buf = [MaybeUninit::<u8>::uninit(); 10];

    let (init, uninit) = borrow_and_wrap_read(&mut uninit_buf);
    assert_eq!(init, &[0, 1, 2, 3, 4, 5, 6, 7]);
    assert_eq!(uninit.len(), 2);

    let mut vec_buf = Vec::with_capacity(10);

    let num = borrow_and_wrap_read(spare_capacity(&mut vec_buf));
    assert_eq!(num, 8);
    assert_eq!(vec_buf.capacity(), 10);
    assert_eq!(vec_buf.len(), 8);
    assert_eq!(&vec_buf, &[0, 1, 2, 3, 4, 5, 6, 7]);

    let mut plain_buf = [0_u8; 10];
    let mut io_slice = IoSliceMut::new(&mut plain_buf);
    let num = borrow_and_wrap_read(&mut io_slice);
    assert_eq!(num, 8);
    assert_eq!(&plain_buf, &[0, 1, 2, 3, 4, 5, 6, 7, 0, 0]);
}

/// "read" data into `b`, using `unsafe` code.
pub fn unsafely_read<B: Buffer<u8>>(mut b: B) -> B::Output {
    let ptr = b.buffer_ptr();
    let len = b.buffer_len();

    let num = min(len, 8);

    // Here we go!
    unsafe {
        // In practice, code in a `read` function like this would be passing
        // the raw pointer to an FFI routine. To keep this example simple, just
        // do a simple thing here.
        for i in 0..num {
            ptr.add(i).write(i as u8);
        }

        // Ok, we just wrote `num` elements.
        b.assume_init(num)
    }
}

/// Same signature as `unsafely_read`, but this time, don't use any unsafe.
#[forbid(unsafe_code)]
pub fn safely_read<B: Buffer<u8>>(b: B) -> B::Output {
    let mut cursor = b.cursor();

    let num = min(cursor.remaining(), 8);

    // No unsafe code here!
    for i in 0..num {
        cursor.write(i as u8);
    }

    cursor.finish()
}

/// Same signature as `safely_read`, but this time, don't use any unsafe.
#[forbid(unsafe_code)]
pub fn safely_read_fast<B: Buffer<u8>>(b: B) -> B::Output {
    let mut cursor = b.cursor();

    let num = min(cursor.remaining(), 8);

    // Heh so ignore that allocating a `Vec` isn't "fast"; the point here is
    // just to exercise `write_slice`.
    let mut v = Vec::with_capacity(num);
    for i in 0..num {
        v.push(i as u8);
    }

    // So fast ^_^.
    cursor.write_slice(&v);

    cursor.finish()
}

/// A wrapper around `safely_read`, to test composability.
#[forbid(unsafe_code)]
pub fn wrap_read<B: Buffer<u8>>(b: B) -> B::Output {
    let cursor = b.cursor();

    safely_read(cursor)
}

/// A wrapper around `safely_read` that doesn't consume the cursor, to test
/// composability.
#[forbid(unsafe_code)]
pub fn borrow_and_wrap_read<B: Buffer<u8>>(b: B) -> B::Output {
    let mut cursor = b.cursor();

    safely_read(&mut cursor);

    cursor.finish()
}