#![deny(missing_docs)]
use byteorder::{ByteOrder, ReadBytesExt};
use std::{error::Error, fmt, marker::PhantomData, mem};
pub use structview_derive::*;
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
pub enum ViewError {
NotEnoughData,
}
impl fmt::Display for ViewError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
ViewError::NotEnoughData => f.write_str("not enough data"),
}
}
}
impl Error for ViewError {}
pub unsafe trait View: Copy {
fn view(data: &[u8]) -> Result<&Self, ViewError> {
if data.len() < mem::size_of::<Self>() {
return Err(ViewError::NotEnoughData);
}
let data_ptr = data.as_ptr();
let struct_ptr = data_ptr as *const Self;
let struct_ref = unsafe { &*struct_ptr };
Ok(struct_ref)
}
}
unsafe impl View for i8 {}
unsafe impl View for u8 {}
macro_rules! array_view_impls {
( $($N:expr)+ ) => {
$( unsafe impl<V: View> View for [V; $N] {} )+
};
}
array_view_impls! {
0 1 2 3 4 5 6 7 8 9
10 11 12 13 14 15 16 17 18 19
20 21 22 23 24 25 26 27 28 29
30 31 32
}
macro_rules! int_view {
( $name:ident, $int:ty, $read:ident, $le:ident, $be:ident ) => {
int_view!($name, $int, stringify!($int), $read, $le, $be);
};
( $name:ident, $int:ty, $int_name:expr, $read:ident, $le:ident, $be:ident ) => {
#[doc = "View of an `"]
#[doc = $int_name]
#[doc = "` value."]
#[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)]
pub struct $name<BO>([u8; mem::size_of::<$int>()], PhantomData<BO>);
impl<BO: ByteOrder> $name<BO> {
pub fn to_int(&self) -> $int {
(&self.0[..]).$read::<BO>().unwrap()
}
}
impl<BO: ByteOrder> fmt::Display for $name<BO> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "[{}]", self.to_int())
}
}
impl<BO: ByteOrder> From<$name<BO>> for $int {
fn from(view: $name<BO>) -> Self {
view.to_int()
}
}
unsafe impl<BO: Copy> View for $name<BO> {}
#[doc = "View of a little-endian `"]
#[doc = $int_name]
#[doc = "` value."]
#[allow(non_camel_case_types)]
pub type $le = $name<byteorder::LE>;
#[doc = "View of a big-endian `"]
#[doc = $int_name]
#[doc = "` value."]
#[allow(non_camel_case_types)]
pub type $be = $name<byteorder::BE>;
};
}
int_view!(I16, i16, read_i16, i16_le, i16_be);
int_view!(U16, u16, read_u16, u16_le, u16_be);
int_view!(I32, i32, read_i32, i32_le, i32_be);
int_view!(U32, u32, read_u32, u32_le, u32_be);
int_view!(I64, i64, read_i64, i64_le, i64_be);
int_view!(U64, u64, read_u64, u64_le, u64_be);