use std::io::{Read, Result};

pub trait NumRead: Read {
    #[inline]
    fn read_i8(&mut self) -> Result<i8> {
        let mut buf = [0u8; 1];
        self.read_exact(&mut buf)?;
        Ok(buf[0] as i8)
    }

    #[inline]
    fn read_u8(&mut self) -> Result<u8> {
        let mut buf = [0u8; 1];
        self.read_exact(&mut buf)?;
        Ok(buf[0])
    }

    #[inline]
    fn read_be_i16(&mut self) -> Result<i16> {
        let mut buf = [0u8; 2];
        self.read_exact(&mut buf)?;
        Ok(i16::from_be_bytes(buf))
    }

    #[inline]
    fn read_be_u16(&mut self) -> Result<u16> {
        let mut buf = [0u8; 2];
        self.read_exact(&mut buf)?;
        Ok(u16::from_be_bytes(buf))
    }

    #[inline]
    fn read_be_u32(&mut self) -> Result<u32> {
        let mut buf = [0u8; 4];
        self.read_exact(&mut buf)?;
        Ok(u32::from_be_bytes(buf))
    }

    #[inline]
    fn read_be_u16_array<const N: usize>(&mut self) -> Result<[u16; N]> {
        let mut array = [0u16; N];
        for i in 0..N {
            array[i] = self.read_be_u16()?;
        }
        Ok(array)
    }
}

pub struct NumReader<R: ?Sized> {
    inner: R,
}

impl<R: Read> NumReader<R> {
    pub fn new(inner: R) -> NumReader<R> {
        NumReader { inner }
    }
}

impl<R: Read> NumRead for NumReader<R> {}

impl<R: Read> Read for NumReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
        self.inner.read(buf)
    }
}
