sbof 1.1.1

Small Binary Object Format
Documentation
use std::io::{self, Read};

use crate::{Error, Result};

pub struct Buf<'src> {
    src: &'src [u8],
    cursor: usize,
}

impl<'src> Buf<'src> {
    pub fn new(src: &'src [u8]) -> Self {
        Buf { src, cursor: 0 }
    }

    fn handle_error<T>(res: io::Result<T>) -> Result<T> {
        if let Err(e) = res {
            match e.kind() {
                std::io::ErrorKind::UnexpectedEof => Err(Error::EOF),
                _ => Err(e)?,
            }
        } else if let Ok(v) = res {
            Ok(v)
        } else {
            unreachable!()
        }
    }

    pub fn read_u8(&mut self) -> Result<u8> {
        let res = self.peek_u8();
        self.cursor += 1;
        res
    }

    pub fn peek_u8(&mut self) -> Result<u8> {
        let mut buf = [0; 1];
        Self::handle_error(self.src[self.cursor..].as_ref().read_exact(&mut buf))?;
        Ok(u8::from_le_bytes(buf))
    }

    pub fn read_i8(&mut self) -> Result<i8> {
        let res = self.peek_i8();
        self.cursor += 1;
        res
    }

    pub fn peek_i8(&mut self) -> Result<i8> {
        let mut buf = [0; 1];
        Self::handle_error(self.src[self.cursor..].as_ref().read_exact(&mut buf))?;
        Ok(i8::from_le_bytes(buf))
    }

    pub fn read_slice(&mut self, len: usize) -> Result<&'src [u8]> {
        if self.src.len() - self.cursor < len {
            Err(Error::EOF)
        } else {
            let old = self.cursor;
            self.cursor += len;
            Ok(&self.src[old..self.cursor])
        }
    }
}

impl<'src> Read for Buf<'src> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let res = self.src[self.cursor..].as_ref().read(buf);
        if let Ok(n) = res {
            self.cursor += n;
        }
        res
    }
}