use std::io;
use std::io::{Read, Seek, SeekFrom, Write};
use super::{ReadAt, Size, WriteAt};
#[derive(Debug, Clone)]
pub struct Cursor<I> {
io: I,
pos: u64,
}
impl<I> Cursor<I> {
#[inline]
pub fn new_pos(io: I, pos: u64) -> Self {
Cursor { io, pos }
}
#[inline]
pub fn new(io: I) -> Self {
Self::new_pos(io, 0)
}
#[inline]
pub fn into_inner(self) -> I {
self.io
}
#[inline]
pub fn get_ref(&self) -> &I {
&self.io
}
#[inline]
pub fn get_mut(&mut self) -> &mut I {
&mut self.io
}
#[inline]
pub fn position(&self) -> u64 {
self.pos
}
#[inline]
pub fn set_position(&mut self, pos: u64) {
self.pos = pos;
}
}
impl<I> Seek for Cursor<I> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
match pos {
SeekFrom::Start(p) => self.pos = p,
SeekFrom::Current(p) => {
let pos = self.pos as i64 + p;
if pos < 0 {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "seek to a negative position"));
}
self.pos = pos as u64;
}
SeekFrom::End(_) => {
return Err(io::Error::new(io::ErrorKind::InvalidInput, "seek from unknown end"))
}
}
Ok(self.pos)
}
}
impl<I: ReadAt> Read for Cursor<I> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let bytes = self.get_ref().read_at(self.pos, buf)?;
self.pos += bytes as u64;
Ok(bytes)
}
}
impl<I: WriteAt> Write for Cursor<I> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let pos = self.pos;
let bytes = self.get_mut().write_at(pos, buf)?;
self.pos += bytes as u64;
Ok(bytes)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
WriteAt::flush(self.get_mut())
}
}
#[derive(Debug, Clone)]
pub struct SizeCursor<I: Size> {
cursor: Cursor<I>,
}
impl<I: Size> SizeCursor<I> {
#[inline]
pub fn new_pos(io: I, pos: u64) -> Self {
SizeCursor {
cursor: Cursor::new_pos(io, pos)
}
}
#[inline]
pub fn new(io: I) -> Self {
SizeCursor {
cursor: Cursor::new(io)
}
}
#[inline]
pub fn as_cursor(&self) -> &Cursor<I> {
&self.cursor
}
#[inline]
pub fn as_cursor_mut(&mut self) -> &mut Cursor<I> {
&mut self.cursor
}
#[inline]
pub fn into_cursor(self) -> Cursor<I> {
self.cursor
}
#[inline]
pub fn into_inner(self) -> I {
self.cursor.io
}
#[inline]
pub fn get_ref(&self) -> &I {
&self.cursor.io
}
#[inline]
pub fn get_mut(&mut self) -> &mut I {
&mut self.cursor.io
}
#[inline]
pub fn position(&self) -> u64 {
self.cursor.position()
}
#[inline]
pub fn set_position(&mut self, pos: u64) {
self.cursor.set_position(pos)
}
}
impl<I: Size + ReadAt> Read for SizeCursor<I> {
#[inline]
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.cursor.read(buf)
}
}
impl<I: Size + WriteAt> Write for SizeCursor<I> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.cursor.write(buf)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
self.cursor.flush()
}
}
impl<I: Size> Seek for SizeCursor<I> {
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
let pos = match pos {
SeekFrom::Start(p) => p as i64,
SeekFrom::Current(p) => self.cursor.pos as i64 + p,
SeekFrom::End(p) => {
match self.get_ref().size() {
Err(e) => return Err(e),
Ok(None) => {
return Err(io::Error::new(io::ErrorKind::InvalidData, "seek from unknown end"))
}
Ok(Some(s)) => s as i64 + p,
}
}
};
self.cursor.pos = pos as u64;
Ok(self.cursor.pos)
}
}