immeta 0.4.0

An image metadata parsing library
Documentation
use std::io::{self, Read, BufRead, ErrorKind};

use byteorder::{ReadBytesExt, LittleEndian, BigEndian};
use byteorder::ByteOrder as ByteOrderTrait;

pub trait ReadExt: Read {
    fn read_exact_0(&mut self, mut buf: &mut [u8]) -> io::Result<usize> {
        let orig_len = buf.len() as u64;
        io::copy(&mut self.take(orig_len), &mut buf).map(|r| r as usize)
    }

    fn skip_exact_0(&mut self, n: u64) -> io::Result<u64> {
        io::copy(&mut self.take(n), &mut io::sink())
    }

    fn read_to_vec(&mut self) -> io::Result<Vec<u8>> {
        let mut buf = Vec::new();
        try!(self.read_to_end(&mut buf));
        Ok(buf)
    }
}

impl<R: ?Sized + Read> ReadExt for R {}

pub trait BufReadExt: BufRead {
    fn skip_exact(&mut self, n: u64) -> io::Result<u64> {
        let mut skipped = 0;
        loop {
            let available = match self.fill_buf() {
                Ok(n) => n.len(),
                Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
                Err(e) => return Err(e)
            } as u64;
            let total = skipped + available;
            if total >= n {
                let extra = total - n;
                let to_skip = available - extra;
                skipped += to_skip;
                self.consume(to_skip as usize);
                break;
            }
            self.consume(available as usize);
            skipped += available;
            if available == 0 {
                break;
            }
        }
        Ok(skipped)
    }

    fn skip_until(&mut self, delim: u8) -> io::Result<usize> {
        let mut read = 0;
        loop {
            let (done, used) = {
                let available = match self.fill_buf() {
                    Ok(n) => n,
                    Err(ref e) if e.kind() == ErrorKind::Interrupted => continue,
                    Err(e) => return Err(e)
                };
                match available.iter().position(|&b| b == delim) {
                    Some(i) => (true, i + 1),
                    None => (false, available.len()),
                }
            };
            self.consume(used);
            read += used;
            if done || used == 0 {
                return Ok(read);
            }
        }
    }
}

impl<R: ?Sized + BufRead> BufReadExt for R {}

#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum ByteOrder {
    Little,
    Big,
}

macro_rules! gen_byte_order_ops {
    ($($read_name:ident, $write_name:ident -> $tpe:ty),+) => {
        impl ByteOrder {
            $(
            #[inline]
            pub fn $read_name(self, source: &[u8]) -> $tpe {
                match self {
                    ByteOrder::Little => LittleEndian::$read_name(source),
                    ByteOrder::Big => BigEndian::$read_name(source),
                }
            }

            pub fn $write_name(self, target: &mut [u8], n: $tpe) {
                match self {
                    ByteOrder::Little => LittleEndian::$write_name(target, n),
                    ByteOrder::Big => BigEndian::$write_name(target, n),
                }
            }
            )+
        }
    }
}

gen_byte_order_ops! {
    read_u16, write_u16 -> u16,
    read_u32, write_u32 -> u32,
    read_u64, write_u64 -> u64,
    read_i16, write_i16 -> i16,
    read_i32, write_i32 -> i32,
    read_i64, write_i64 -> i64,
    read_f32, write_f32 -> f32,
    read_f64, write_f64 -> f64
}


macro_rules! gen_read_byte_order_ext {
    ($tr:ident, $($name:ident -> $tpe:ty),+) => {
        pub trait $tr: Read {
            $(
            #[inline]
            fn $name(&mut self, byte_order: ByteOrder) -> io::Result<$tpe> {
                match byte_order {
                    ByteOrder::Little => ReadBytesExt::$name::<LittleEndian>(self),
                    ByteOrder::Big => ReadBytesExt::$name::<BigEndian>(self),
                }
            }
            )+
        }
    }
}

gen_read_byte_order_ext! {
    ByteOrderReadExt,
    read_u16 -> u16,
    read_u32 -> u32,
    read_u64 -> u64,
    read_i16 -> i16,
    read_i32 -> i32,
    read_i64 -> i64,
    read_f32 -> f32,
    read_f64 -> f64
}

impl<R: Read> ByteOrderReadExt for R {}