use byteorder;
use parser::{Error, Result};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::ops::{Deref, Index, Range, RangeFrom, RangeTo};
pub trait Endianity
: byteorder::ByteOrder + Debug + Default + Clone + Copy + PartialEq + Eq {
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LittleEndian {}
impl Default for LittleEndian {
fn default() -> LittleEndian {
unreachable!()
}
}
impl byteorder::ByteOrder for LittleEndian {
fn read_u16(buf: &[u8]) -> u16 {
byteorder::LittleEndian::read_u16(buf)
}
fn read_u32(buf: &[u8]) -> u32 {
byteorder::LittleEndian::read_u32(buf)
}
fn read_u64(buf: &[u8]) -> u64 {
byteorder::LittleEndian::read_u64(buf)
}
fn read_uint(buf: &[u8], nbytes: usize) -> u64 {
byteorder::LittleEndian::read_uint(buf, nbytes)
}
fn write_u16(buf: &mut [u8], n: u16) {
byteorder::LittleEndian::write_u16(buf, n)
}
fn write_u32(buf: &mut [u8], n: u32) {
byteorder::LittleEndian::write_u32(buf, n)
}
fn write_u64(buf: &mut [u8], n: u64) {
byteorder::LittleEndian::write_u64(buf, n)
}
fn write_uint(buf: &mut [u8], n: u64, nbytes: usize) {
byteorder::LittleEndian::write_uint(buf, n, nbytes)
}
}
impl Endianity for LittleEndian {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BigEndian {}
impl Default for BigEndian {
fn default() -> BigEndian {
unreachable!()
}
}
impl byteorder::ByteOrder for BigEndian {
fn read_u16(buf: &[u8]) -> u16 {
byteorder::BigEndian::read_u16(buf)
}
fn read_u32(buf: &[u8]) -> u32 {
byteorder::BigEndian::read_u32(buf)
}
fn read_u64(buf: &[u8]) -> u64 {
byteorder::BigEndian::read_u64(buf)
}
fn read_uint(buf: &[u8], nbytes: usize) -> u64 {
byteorder::BigEndian::read_uint(buf, nbytes)
}
fn write_u16(buf: &mut [u8], n: u16) {
byteorder::BigEndian::write_u16(buf, n)
}
fn write_u32(buf: &mut [u8], n: u32) {
byteorder::BigEndian::write_u32(buf, n)
}
fn write_u64(buf: &mut [u8], n: u64) {
byteorder::BigEndian::write_u64(buf, n)
}
fn write_uint(buf: &mut [u8], n: u64, nbytes: usize) {
byteorder::BigEndian::write_uint(buf, n, nbytes)
}
}
impl Endianity for BigEndian {}
#[cfg(target_endian = "little")]
pub type NativeEndian = LittleEndian;
#[cfg(target_endian = "big")]
pub type NativeEndian = BigEndian;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EndianBuf<'input, Endian>(pub &'input [u8], pub PhantomData<Endian>)
where Endian: Endianity;
impl<'input, Endian> EndianBuf<'input, Endian>
where Endian: Endianity
{
pub fn new(buf: &'input [u8]) -> EndianBuf<'input, Endian> {
EndianBuf(buf, PhantomData)
}
#[inline]
pub fn split_at(&self, idx: usize) -> (EndianBuf<'input, Endian>, EndianBuf<'input, Endian>) {
(self.range_to(..idx), self.range_from(idx..))
}
#[inline]
pub fn try_split_at(&self,
idx: usize)
-> Result<(EndianBuf<'input, Endian>, EndianBuf<'input, Endian>)> {
if idx > self.len() {
Err(Error::BadLength)
} else {
Ok(self.split_at(idx))
}
}
}
impl<'input, Endian> EndianBuf<'input, Endian>
where Endian: Endianity
{
pub fn range(&self, idx: Range<usize>) -> EndianBuf<'input, Endian> {
EndianBuf(&self.0[idx], self.1)
}
pub fn range_from(&self, idx: RangeFrom<usize>) -> EndianBuf<'input, Endian> {
EndianBuf(&self.0[idx], self.1)
}
pub fn range_to(&self, idx: RangeTo<usize>) -> EndianBuf<'input, Endian> {
EndianBuf(&self.0[idx], self.1)
}
}
impl<'input, Endian> Index<usize> for EndianBuf<'input, Endian>
where Endian: Endianity
{
type Output = u8;
fn index(&self, idx: usize) -> &Self::Output {
&self.0[idx]
}
}
impl<'input, Endian> Index<RangeFrom<usize>> for EndianBuf<'input, Endian>
where Endian: Endianity
{
type Output = [u8];
fn index(&self, idx: RangeFrom<usize>) -> &Self::Output {
&self.0[idx]
}
}
impl<'input, Endian> Deref for EndianBuf<'input, Endian>
where Endian: Endianity
{
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.0
}
}
impl<'input, Endian> Into<&'input [u8]> for EndianBuf<'input, Endian>
where Endian: Endianity
{
fn into(self) -> &'input [u8] {
self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
use parser::Error;
#[test]
fn test_endian_buf_split_at() {
let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
let eb = EndianBuf::<NativeEndian>::new(&buf);
assert_eq!(eb.split_at(3),
(EndianBuf::new(&buf[..3]), EndianBuf::new(&buf[3..])));
}
#[test]
#[should_panic]
fn test_endian_buf_split_at_out_of_bounds() {
let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
let eb = EndianBuf::<NativeEndian>::new(&buf);
eb.split_at(30);
}
#[test]
fn test_endian_buf_try_split_at() {
let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
let eb = EndianBuf::<NativeEndian>::new(&buf);
assert_eq!(eb.try_split_at(3),
Ok((EndianBuf::new(&buf[..3]), EndianBuf::new(&buf[3..]))));
}
#[test]
fn test_endian_buf_try_split_at_out_of_bounds() {
let buf = [1, 2, 3, 4, 5, 6, 7, 8, 9, 0];
let eb = EndianBuf::<NativeEndian>::new(&buf);
assert_eq!(Err(Error::BadLength), eb.try_split_at(30));
}
}