Documentation
use crate::bin_decode::ParseError;
use byteorder::{BigEndian, ByteOrder};

pub trait NbtParse<'a>: Sized {
    fn read(reader: &mut Reader<'a>) -> Result<Self, ParseError>;
}

macro_rules! primitive_impl {
    ($ty:ty, $size:expr, $func:ident) => {
        impl<'a> NbtParse<'a> for $ty {
            fn read(reader: &mut Reader<'a>) -> Result<Self, ParseError> {
                Ok(BigEndian::$func(reader.advance($size)?))
            }
        }
    };
}

primitive_impl!(i16, 2, read_i16);
primitive_impl!(i32, 4, read_i32);
primitive_impl!(i64, 8, read_i64);
primitive_impl!(f32, 4, read_f32);
primitive_impl!(f64, 8, read_f64);

impl<'a> NbtParse<'a> for &'a [u8] {
    fn read(reader: &mut Reader<'a>) -> Result<Self, ParseError> {
        let length = BigEndian::read_u32(reader.advance(4)?);
        Ok(reader.advance(length as usize)?)
    }
}

pub struct Reader<'a> {
    buffer: &'a [u8],
    pub position: usize,
}

impl<'a> Reader<'a> {
    pub(crate) fn new(buffer: &'a [u8]) -> Reader<'a> {
        Reader {
            buffer,
            position: 0,
        }
    }

    pub(crate) fn advance(&mut self, n: usize) -> Result<&'a [u8], ParseError> {
        if self.buffer.len() < self.position + n {
            Err(ParseError::EOF)
        } else {
            let slice = &self.buffer[self.position..self.position + n];
            self.position += n;
            Ok(slice)
        }
    }
}