use crate::error::IoError;
use core::usize;
type Result<T> = core::result::Result<T, IoError>;
#[derive(Clone, Copy)]
pub enum SeekFrom {
Start(usize),
End(isize),
Current(isize),
}
pub struct BufferCursor<T: AsRef<[u8]>> {
data: T,
pos: usize,
}
impl<T: AsRef<[u8]>> BufferCursor<T> {
pub fn into_inner(self) -> T {
self.data
}
}
impl<T: AsRef<[u8]>> BufferCursor<T> {
pub fn new(data: T) -> Self {
Self { data, pos: 0 }
}
}
impl<T: AsRef<[u8]>> SeekableAsset for BufferCursor<T> {
fn seek(&mut self, pos: SeekFrom) -> Result<usize> {
let new_pos = match pos {
SeekFrom::Start(pos) => pos as isize,
SeekFrom::End(pos) => self.data.as_ref().len() as isize + pos,
SeekFrom::Current(pos) => self.pos as isize + pos,
};
if new_pos < 0 {
return Err(IoError::SeekBeforeStart);
}
self.pos = new_pos as usize;
Ok(self.pos)
}
}
impl<T: AsRef<[u8]>> LoadableAsset for BufferCursor<T> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let data = self.data.as_ref();
if self.pos >= data.len() {
return Err(IoError::UnexpectedEof);
}
let bytes_to_read = buf.len().min(data.len() - self.pos);
buf[0..bytes_to_read].copy_from_slice(&data[self.pos..self.pos + bytes_to_read]);
self.pos += bytes_to_read;
Ok(bytes_to_read)
}
}
pub trait SeekableAsset {
fn seek(&mut self, pos: SeekFrom) -> Result<usize>;
}
pub trait LoadableAsset {
fn read(&mut self, buf: &mut [u8]) -> Result<usize>;
fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<()> {
while !buf.is_empty() {
match self.read(buf)? {
0 => {
break;
}
n => {
let tmp = buf;
buf = &mut tmp[n..];
}
}
}
if !buf.is_empty() {
return Err(IoError::UnexpectedEof);
}
Ok(())
}
}
pub trait DataRecorder {
fn write(&mut self, buf: &[u8]) -> Result<usize>;
fn write_all(&mut self, mut buf: &[u8]) -> Result<()> {
while !buf.is_empty() {
match self.write(buf)? {
0 => return Err(IoError::WriteZero),
n => buf = &buf[n..],
}
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn buffer_cursor_seek_works() {
const BUFFER: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let mut cursor = BufferCursor::new(BUFFER);
let mut tmp = [0u8; 1];
cursor.read_exact(&mut tmp).unwrap();
assert_eq!(tmp[0], 1);
cursor.seek(SeekFrom::Current(1)).unwrap();
cursor.read_exact(&mut tmp).unwrap();
assert_eq!(tmp[0], 3);
cursor.seek(SeekFrom::Start(2)).unwrap();
cursor.read_exact(&mut tmp).unwrap();
assert_eq!(tmp[0], 3);
let mut tmp = [0u8; 3];
cursor.seek(SeekFrom::End(-2)).unwrap();
let read_bytes = cursor.read(&mut tmp).unwrap();
assert_eq!(read_bytes, 2);
assert_eq!(tmp[0], 9);
assert_eq!(tmp[1], 10);
}
}