byte 0.2.7

A low-level, zero-copy and panic-free serializer and deserializer for binary.
Documentation
#[macro_use]
extern crate quickcheck;
extern crate byte;
extern crate byteorder;

use byte::ctx::*;
use byte::*;
use byteorder::*;

#[test]
fn test_str() {
    let bytes: &[u8] = b"abcd\0efg";

    let mut offset = 0;
    assert_eq!(
        bytes
            .read_with::<&str>(&mut offset, Str::Delimiter(NULL))
            .unwrap(),
        "abcd"
    );
    assert_eq!(offset, 5);

    let bytes: &[u8] = b"abcdefghijklmnopqrstuvwxyz";
    assert_eq!(
        TryRead::try_read(bytes, Str::Len(15)).unwrap(),
        ("abcdefghijklmno", 15)
    );
    assert_eq!(
        TryRead::try_read(bytes, Str::Len(26)).unwrap(),
        ("abcdefghijklmnopqrstuvwxyz", 26)
    );

    assert!(bytes.read_with::<&str>(&mut 0, Str::Len(27)).is_err());
    assert!(bytes.read_with::<&str>(&mut 27, Str::Len(0)).is_err());
    assert!(bytes.read_with::<&str>(&mut 26, Str::Len(1)).is_err());
}

#[test]
fn test_str_delimitor() {
    let bytes: &[u8] = b"";
    assert_eq!(
        TryRead::try_read(bytes, Str::DelimiterUntil(NULL, 0)).unwrap(),
        ("", 0)
    );

    let bytes: &[u8] = b"abcdefg";
    assert_eq!(
        TryRead::try_read(bytes, Str::DelimiterUntil(NULL, 6)).unwrap(),
        ("abcdef", 6)
    );
    assert_eq!(
        TryRead::try_read(bytes, Str::DelimiterUntil(NULL, 7)).unwrap(),
        ("abcdefg", 7)
    );

    let bytes: &[u8] = b"\0abcdefg";
    assert_eq!(
        TryRead::try_read(bytes, Str::Delimiter(NULL)).unwrap(),
        ("", 1)
    );
    assert_eq!(
        TryRead::try_read(bytes, Str::DelimiterUntil(NULL, 0)).unwrap(),
        ("", 0)
    );
    assert_eq!(
        TryRead::try_read(bytes, Str::DelimiterUntil(NULL, 1)).unwrap(),
        ("", 1)
    );

    let bytes: &[u8] = b"abcd\0efg";
    assert_eq!(
        TryRead::try_read(bytes, Str::Delimiter(NULL)).unwrap(),
        ("abcd", 5)
    );
    assert_eq!(
        TryRead::try_read(bytes, Str::DelimiterUntil(NULL, 4)).unwrap(),
        ("abcd", 4)
    );
    assert_eq!(
        TryRead::try_read(bytes, Str::DelimiterUntil(NULL, 5)).unwrap(),
        ("abcd", 5)
    );
    assert_eq!(
        TryRead::try_read(bytes, Str::DelimiterUntil(NULL, 6)).unwrap(),
        ("abcd", 5)
    );

    let bytes: &[u8] = b"abcdefg\0";
    assert_eq!(
        TryRead::try_read(bytes, Str::Delimiter(NULL)).unwrap(),
        ("abcdefg", 8)
    );
    assert_eq!(
        TryRead::try_read(bytes, Str::DelimiterUntil(NULL, 8)).unwrap(),
        ("abcdefg", 8)
    );
    assert_eq!(
        TryRead::try_read(bytes, Str::DelimiterUntil(NULL, 20)).unwrap(),
        ("abcdefg", 8)
    );

    let bytes: &[u8] = b"";
    assert!(bytes
        .read_with::<&str>(&mut 0, Str::Delimiter(NULL))
        .is_err());
    assert!(bytes
        .read_with::<&str>(&mut 0, Str::DelimiterUntil(NULL, 1))
        .is_err());

    let bytes: &[u8] = b"abcdefg";
    assert!(bytes
        .read_with::<&str>(&mut 0, Str::DelimiterUntil(NULL, 8))
        .is_err());
    assert!(bytes
        .read_with::<&str>(&mut 0, Str::Delimiter(NULL))
        .is_err());
}

#[test]
fn test_str_write() {
    let mut bytes = [0; 20];
    let mut offset = 0;
    bytes.write(&mut offset, "hello world!").unwrap();
    assert_eq!(offset, 12);
    assert_eq!(&bytes[..offset], b"hello world!" as &[u8]);

    let bytes = &mut [0; 10];
    assert!(bytes.write(&mut 0, "hello world!").is_err());
}

#[test]
fn test_bytes() {
    let bytes: &[u8] = &[0xde, 0xad, 0xbe, 0xef];
    assert_eq!(
        TryRead::try_read(&bytes, Bytes::Len(4)).unwrap(),
        (&bytes[..], 4)
    );

    assert!(bytes.read_with::<&[u8]>(&mut 5, Bytes::Len(0)).is_err());

    let mut write = [0; 5];
    assert_eq!(TryWrite::try_write(bytes, &mut write, ()).unwrap(), 4);
    assert_eq!(&write[..4], bytes);

    assert!([0u8; 3].write(&mut 0, bytes).is_err());
}

#[test]
fn test_bytes_pattern() {
    let bytes: &[u8] = b"abcdefghijk";

    assert_eq!(
        TryRead::try_read(bytes, Bytes::Pattern(b"abc")).unwrap(),
        (&b"abc"[..], 3)
    );
    assert_eq!(
        TryRead::try_read(bytes, Bytes::Pattern(b"cde")).unwrap(),
        (&b"abcde"[..], 5)
    );
    assert_eq!(
        TryRead::try_read(bytes, Bytes::Pattern(b"jk")).unwrap(),
        (&b"abcdefghijk"[..], 11)
    );
    assert_eq!(
        TryRead::try_read(bytes, Bytes::PatternUntil(b"abc", 3)).unwrap(),
        (&b"abc"[..], 3)
    );
    assert_eq!(
        TryRead::try_read(bytes, Bytes::PatternUntil(b"abc", 4)).unwrap(),
        (&b"abc"[..], 3)
    );
    assert_eq!(
        TryRead::try_read(bytes, Bytes::PatternUntil(b"cde", 3)).unwrap(),
        (&b"abc"[..], 3)
    );
    assert_eq!(
        TryRead::try_read(bytes, Bytes::PatternUntil(b"cde", 4)).unwrap(),
        (&b"abcd"[..], 4)
    );
    assert_eq!(
        TryRead::try_read(bytes, Bytes::PatternUntil(b"cde", 5)).unwrap(),
        (&b"abcde"[..], 5)
    );
    assert_eq!(
        TryRead::try_read(bytes, Bytes::PatternUntil(b"cde", 6)).unwrap(),
        (&b"abcde"[..], 5)
    );
    assert_eq!(
        TryRead::try_read(bytes, Bytes::PatternUntil(b"xyz", 5)).unwrap(),
        (&b"abcde"[..], 5)
    );
    assert!(bytes
        .read_with::<&[u8]>(&mut 0, Bytes::Pattern(b"xyz"))
        .is_err());
    assert!(bytes
        .read_with::<&[u8]>(&mut 0, Bytes::Pattern(b""))
        .is_err());
    assert!(bytes
        .read_with::<&[u8]>(&mut 0, Bytes::PatternUntil(b"", 3))
        .is_err());
    assert!(bytes
        .read_with::<&[u8]>(&mut 0, Bytes::PatternUntil(b"abcd", 3))
        .is_err());
    assert!(bytes
        .read_with::<&[u8]>(&mut 0, Bytes::PatternUntil(b"xyz", 20))
        .is_err());

    let bytes: &[u8] = b"";
    assert!(bytes
        .read_with::<&[u8]>(&mut 0, Bytes::Pattern(b"xyz"))
        .is_err());
    assert!(bytes
        .read_with::<&[u8]>(&mut 0, Bytes::PatternUntil(b"abc", 3))
        .is_err());
    assert!(bytes
        .read_with::<&[u8]>(&mut 0, Bytes::PatternUntil(b"abc", 4))
        .is_err());
}

#[test]
fn test_bool() {
    let bytes = [0x00, 0x01, 0x80, 0xff];
    assert_eq!(bytes.read::<bool>(&mut 0).unwrap(), false);
    assert_eq!(bytes.read::<bool>(&mut 1).unwrap(), true);
    assert_eq!(bytes.read::<bool>(&mut 2).unwrap(), true);
    assert_eq!(bytes.read::<bool>(&mut 3).unwrap(), true);

    let mut bytes = [0u8; 2];
    bytes.write(&mut 0, false).unwrap();
    bytes.write(&mut 1, true).unwrap();
    assert!(bytes[0] == 0);
    assert!(bytes[1] != 0);
}

#[test]
fn test_iter() {
    let bytes: &[u8] = b"hello\0world\0dead\0beef\0more";
    let mut offset = 0;
    {
        let mut iter = bytes.read_iter(&mut offset, Str::Delimiter(NULL));
        assert_eq!(iter.next(), Some("hello"));
        assert_eq!(iter.next(), Some("world"));
        assert_eq!(iter.next(), Some("dead"));
        assert_eq!(iter.next(), Some("beef"));
        assert_eq!(iter.next(), None);
    }
    assert_eq!(offset, 22);
}

macro_rules! test_num {
    ($test_name: tt, $ty: ty, $byteorder_read_fn: tt, $byteorder_write_fn: tt) => {
        quickcheck! {
            fn $test_name (num: $ty) -> () {
                let mut bytes = [0u8; 8];
                bytes.write_with(&mut 0, num, LE).unwrap();
                let result = LittleEndian::$byteorder_read_fn(&bytes);
                assert_eq!(result, num);

                let mut bytes = [0u8; 8];
                LittleEndian::$byteorder_write_fn(&mut bytes, num);
                let result: $ty = bytes.read_with(&mut 0, LE).unwrap();
                assert_eq!(result, num);

                let mut bytes = [0u8; 8];
                bytes.write_with(&mut 0, num, BE).unwrap();
                let result = BigEndian::$byteorder_read_fn(&bytes);
                assert_eq!(result, num);

                let mut bytes = [0u8; 8];
                BigEndian::$byteorder_write_fn(&mut bytes, num);
                let result: $ty = bytes.read_with(&mut 0, BE).unwrap();
                assert_eq!(result, num);
            }
        }
    };
}

test_num!(test_u16, u16, read_u16, write_u16);
test_num!(test_u32, u32, read_u32, write_u32);
test_num!(test_u64, u64, read_u64, write_u64);
test_num!(test_i16, i16, read_i16, write_i16);
test_num!(test_i32, i32, read_i32, write_i32);
test_num!(test_i64, i64, read_i64, write_i64);
test_num!(test_f32, f32, read_f32, write_f32);
test_num!(test_f64, f64, read_f64, write_f64);

struct Header<'a> {
    name: &'a str,
    enabled: bool,
}

impl<'a> TryRead<'a, Endian> for Header<'a> {
    fn try_read(bytes: &'a [u8], endian: Endian) -> Result<(Self, usize)> {
        let offset = &mut 0;

        let name_len = bytes.read_with::<u16>(offset, endian)? as usize;
        let header = Header {
            name: bytes.read_with::<&str>(offset, Str::Len(name_len))?,
            enabled: bytes.read(offset)?,
        };

        Ok((header, *offset))
    }
}

impl<'a> TryWrite<Endian> for Header<'a> {
    fn try_write(self, bytes: &mut [u8], endian: Endian) -> Result<usize> {
        let offset = &mut 0;

        bytes.write_with(offset, self.name.len() as u16, endian)?;
        bytes.write(offset, self.name)?;
        bytes.write(offset, self.enabled)?;

        Ok(*offset)
    }
}

#[test]
fn test_api() {
    let bytes = [0, 5, b"H"[0], b"E"[0], b"L"[0], b"L"[0], b"O"[0], 0];

    let header: Header = bytes.read_with(&mut 0, BE).unwrap();
    assert_eq!(header.name, "HELLO");
    assert_eq!(header.enabled, false);

    let mut write = [0u8; 8];
    write.write_with(&mut 0, header, BE).unwrap();
    assert_eq!(write, bytes);
}

#[derive(Debug, Clone, PartialEq, Eq)]
struct Empty;

impl<'a> TryRead<'a, ()> for Empty {
    fn try_read(bytes: &'a [u8], _ctx: ()) -> Result<(Self, usize)> {
        Ok((Self, 0))
    }
}

impl TryWrite<()> for Empty {
    fn try_write(self, bytes: &mut [u8], _ctx: ()) -> Result<usize> {
        Ok(0)
    }
}

#[test]
fn test_empty() {
    let empty_bytes: [u8; 0] = [];
    let mut offset = 0;
    let empty: Empty = empty_bytes.read(&mut offset).unwrap();
    assert_eq!(empty, Empty);
    assert_eq!(offset, 0);

    let zero_bytes = [0; 8];
    let mut offset = 0;
    let empty: Empty = zero_bytes.read(&mut offset).unwrap();
    assert_eq!(empty, Empty);
    assert_eq!(offset, 0);

    let mut write_empty_bytes: [u8; 0] = [];
    let mut offset = 0;
    write_empty_bytes.write(&mut offset, Empty).unwrap();
    assert_eq!(write_empty_bytes, empty_bytes);
    assert_eq!(offset, 0);

    let mut write_zero_bytes = [0u8; 4];
    let mut offset = 0;
    write_zero_bytes.write(&mut offset, Empty).unwrap();
    assert_eq!(write_zero_bytes, [0u8; 4]);
    assert_eq!(offset, 0);
}