structview 1.1.0

Viewing binary data as high-level data structures, safely.
Documentation
use byteorder::{ByteOrder, BE};
use structview::{i16_be, i32_be, i64_be, u16_be, u32_be, u64_be};
use structview::{i16_le, i32_le, i64_le, u16_le, u32_le, u64_le};
use structview::{View, U16};

const DATA: &[u8] = &[0xfe, 0xed, 0xba, 0xbe, 0xc0, 0xde, 0xd0, 0x0d];

#[test]
fn view_u8() {
    let view = u8::view(DATA).unwrap();
    assert_eq!(*view, 0xfe);
}

#[test]
fn view_i8() {
    let view = i8::view(DATA).unwrap();
    assert_eq!(*view, -0x02);
}

macro_rules! int_view_tests {
    ( $($name:ident ( $view:ident => $val:expr ),)* ) => {
        $(
            #[test]
            fn $name() {
                let view = $view::view(DATA).unwrap();
                assert_eq!(view.to_int(), $val);
            }
        )*
    };
}

int_view_tests! {
    view_i16_be(i16_be => -0x113),
    view_i32_be(i32_be => -0x0112_4542),
    view_i64_be(i64_be => -0x0112_4541_3f21_2ff3),
    view_u16_be(u16_be => 0xfeed),
    view_u32_be(u32_be => 0xfeed_babe),
    view_u64_be(u64_be => 0xfeed_babe_c0de_d00d),

    view_i16_le(i16_le => -0x1202),
    view_i32_le(i32_le => -0x4145_1202),
    view_i64_le(i64_le => 0x0dd0_dec0_beba_edfe),
    view_u16_le(u16_le => 0xedfe),
    view_u32_le(u32_le => 0xbeba_edfe),
    view_u64_le(u64_le => 0x0dd0_dec0_beba_edfe),
}

#[test]
fn view_array() {
    let view = <[u16_be; 3]>::view(DATA).unwrap();
    assert_eq!(view[0].to_int(), 0xfeed);
    assert_eq!(view[1].to_int(), 0xbabe);
    assert_eq!(view[2].to_int(), 0xc0de);
}

#[derive(Debug, Clone, Copy, View)]
#[repr(C)]
struct Struct {
    foo: [u8; 4],
    bar: u16_be,
}

#[test]
fn view_struct() {
    let view = Struct::view(DATA).unwrap();
    assert_eq!(view.foo, [0xfe, 0xed, 0xba, 0xbe]);
    assert_eq!(view.bar.to_int(), 0xc0de);
}

#[derive(Debug, Clone, Copy, View)]
#[repr(C)]
struct GenericStruct<T: View> {
    field: T,
}

#[test]
fn view_generic_struct() {
    let view = GenericStruct::<u16_be>::view(DATA).unwrap();
    assert_eq!(view.field.to_int(), 0xfeed);
}

#[derive(Clone, Copy, View)]
#[repr(C)]
union Union {
    foo: [u8; 4],
    bar: u16_be,
}

#[test]
fn view_union() {
    let view = Union::view(DATA).unwrap();
    unsafe {
        assert_eq!(view.foo, [0xfe, 0xed, 0xba, 0xbe]);
        assert_eq!(view.bar.to_int(), 0xfeed);
    }
}

#[derive(Clone, Copy, View)]
#[repr(C)]
union GenericUnion<T: View> {
    field: T,
}

#[test]
fn view_generic_union() {
    let view = GenericUnion::<u16_be>::view(DATA).unwrap();
    unsafe {
        assert_eq!(view.field.to_int(), 0xfeed);
    }
}

#[derive(Debug, Clone, Copy, View)]
#[repr(C)]
struct GenericByteorder<BO: ByteOrder>(U16<BO>);

#[test]
fn view_generic_byteorder() {
    let view = GenericByteorder::<BE>::view(DATA).unwrap();
    assert_eq!(view.0.to_int(), 0xfeed);
}

#[test]
fn not_enough_data() {
    let result = <[u8; 20]>::view(DATA);
    assert!(result.is_err());
}

const VEC_DATA: [u8; 12] = [
    0xfe, 0xed, 0xba, 0xbe, 0xc0, 0xde, 
    0xd0, 0x0d, 0xde, 0xad, 0xbe, 0xef
];

#[test]
fn view_boxed_slice() {
    let view = Struct::view_boxed_slice(VEC_DATA.to_vec().into_boxed_slice())
        .unwrap();
    assert_eq!(view[0].foo, [0xfe, 0xed, 0xba, 0xbe]);
    assert_eq!(view[0].bar.to_int(), 0xc0de);
    assert_eq!(view[1].foo, [0xd0, 0x0d, 0xde, 0xad]);
    assert_eq!(view[1].bar.to_int(), 0xbeef);

    // empty vector
    assert!(Struct::view_boxed_slice(Default::default()).unwrap().is_empty());
}

#[test]
fn view_slice() {
    let view = Struct::view_slice(&VEC_DATA[..]).unwrap();
    assert_eq!(view[0].foo, [0xfe, 0xed, 0xba, 0xbe]);
    assert_eq!(view[0].bar.to_int(), 0xc0de);
    assert_eq!(view[1].foo, [0xd0, 0x0d, 0xde, 0xad]);
    assert_eq!(view[1].bar.to_int(), 0xbeef);

    // empty slice
    assert!(Struct::view_slice(Default::default()).unwrap().is_empty());
}

#[test]
fn not_a_multiple() {
    let result = Struct::view_slice(DATA);
    assert!(result.is_err());
}