prefix-varint 0.0.1-alpha.6

PrefixVarint encoding for u64 integers.
use std::{iter, mem::size_of};

use rand::{thread_rng, Rng as _};

use super::*;

struct AssertEofCursor<T>
where
    T: AsRef<[u8]>,
{
    cursor: io::Cursor<T>,
}

impl<T> AssertEofCursor<T>
where
    T: AsRef<[u8]>,
{
    fn new(inner: T) -> Self {
        Self {
            cursor: io::Cursor::new(inner),
        }
    }
}

impl<T> Read for AssertEofCursor<T>
where
    T: AsRef<[u8]>,
{
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        self.cursor.read(buf)
    }
}

impl<T> Drop for AssertEofCursor<T>
where
    T: AsRef<[u8]>,
{
    fn drop(&mut self) {
        assert_eq!(
            self.cursor.position(),
            self.cursor.get_ref().as_ref().len() as u64,
            "read cursor not fully consumed"
        );
    }
}

#[test]
fn test_read_prefix() {
    assert_eq!(read_prefix(0b1010_1011), (0b101_0101, 0));
    assert_eq!(read_prefix(0b1010_1010), (0b10_1010, 1));
    assert_eq!(read_prefix(0b1010_1100), (0b1_0101, 2));
    assert_eq!(read_prefix(0b1011_1000), (0b1011, 3));
    assert_eq!(read_prefix(0b1011_0000), (0b101, 4));
    assert_eq!(read_prefix(0b1010_0000), (0b10, 5));
    assert_eq!(read_prefix(0b1100_0000), (0b1, 6));
    assert_eq!(read_prefix(0b1000_0000), (0b0, 7));
    assert_eq!(read_prefix(0b0000_0000), (0b0, 8));
}

#[test]
fn test_read_varint() -> io::Result<()> {
    macro_rules! test_varint_read {
        ($bytes:expr, ok = $expected:expr) => {
            assert_eq!(read_varint(AssertEofCursor::new($bytes))?, $expected);

            let mut cursor = io::Cursor::new($bytes.to_vec());
            cursor.get_mut().splice(0..0, iter::repeat(0).take(5));
            cursor.set_position(5);

            assert_eq!(read_varint(&mut cursor)?, $expected);
            assert_eq!(cursor.position(), $bytes.len() as u64 + 5);
        };
        ($bytes:expr, error_kind = $error_kind:expr) => {
            assert_eq!(
                read_varint(AssertEofCursor::new($bytes))
                    .unwrap_err()
                    .kind(),
                $error_kind
            );
            assert_eq!(
                read_varint(&mut io::Cursor::new($bytes))
                    .unwrap_err()
                    .kind(),
                $error_kind
            );
        };
    }

    test_varint_read!([0b1010_1011], ok = 0b101_0101);

    test_varint_read!([0b1010_1010, 0b1010_1010], ok = 0b10_1010_1010_1010);

    test_varint_read!([0b1010_1010], error_kind = io::ErrorKind::UnexpectedEof);

    test_varint_read!(
        [0b1010_1100, 0b1010_1010, 0b1010_1010,],
        ok = 0b1_0101_0101_0101_0101_0101
    );
    test_varint_read!(
        [0b1010_1100, 0b1010_1010],
        error_kind = io::ErrorKind::UnexpectedEof
    );

    test_varint_read!(
        [0b1010_1000, 0b1010_1010, 0b1010_1010, 0b1010_1010],
        ok = 0b1010_1010_1010_1010_1010_1010_1010
    );
    test_varint_read!(
        [0b1010_1000, 0b1010_1010, 0b1010_1010],
        error_kind = io::ErrorKind::UnexpectedEof
    );

    test_varint_read!(
        [
            0b1011_0000,
            0b1010_1010,
            0b1010_1010,
            0b1010_1010,
            0b1010_1010
        ],
        ok = 0b101_0101_0101_0101_0101_0101_0101_0101_0101
    );
    test_varint_read!(
        [0b1011_0000, 0b1010_1010, 0b1010_1010, 0b1010_1010],
        error_kind = io::ErrorKind::UnexpectedEof
    );

    test_varint_read!(
        [
            0,
            u8::MAX,
            u8::MAX,
            u8::MAX,
            u8::MAX,
            u8::MAX,
            u8::MAX,
            u8::MAX,
            u8::MAX,
        ],
        ok = u64::MAX
    );

    test_varint_read!(
        [
            0b1000_0000,
            u8::MAX,
            u8::MAX,
            u8::MAX,
            u8::MAX,
            u8::MAX,
            u8::MAX,
            u8::MAX,
        ],
        ok = 2_u64.pow(56) - 1
    );

    Ok(())
}

#[test]
fn test_calc_varint_size() {
    assert_eq!(calc_varint_size(u64::MIN), 1);

    assert_eq!(calc_varint_size((2_u64.pow(7)) - 1), 1);
    assert_eq!(calc_varint_size(2_u64.pow(7)), 2);

    assert_eq!(calc_varint_size(u64::MAX), size_of::<u64>() + 1);
}

#[test]
fn test_roundtrip() -> io::Result<()> {
    let mut buf = vec![];

    let mut rng = thread_rng();

    for n in vec![u64::MIN, u64::MAX]
        .into_iter()
        .chain(iter::from_fn(move || rng.gen()).take(150_000))
    {
        write_varint(n, &mut buf)?;
        assert_eq!(read_varint(AssertEofCursor::new(&buf)).unwrap(), n);
        buf.clear();
    }

    Ok(())
}