use core::cmp;
use super::{Error, ErrorKind, Read, Result, Write};
#[derive(Clone, Debug, Default, Eq, PartialEq)]
pub struct Cursor<T> {
inner: T,
pos: u64,
}
impl<T> Cursor<T> {
pub fn new(inner: T) -> Self {
Cursor { inner, pos: 0 }
}
pub fn into_inner(self) -> T {
self.inner
}
pub fn get_ref(&self) -> &T {
&self.inner
}
pub fn get_mut(&mut self) -> &mut T {
&mut self.inner
}
pub fn position(&self) -> u64 {
self.pos
}
pub fn set_position(&mut self, pos: u64) {
self.pos = pos;
}
}
impl<T: AsRef<[u8]>> Read for Cursor<T> {
fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
let slice = self.inner.as_ref();
let start = cmp::min(self.pos, slice.len() as u64) as usize;
let remaining = &slice[start..];
let amt = cmp::min(buf.len(), remaining.len());
buf[..amt].copy_from_slice(&remaining[..amt]);
self.pos += amt as u64;
Ok(amt)
}
fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
let slice = self.inner.as_ref();
let start = cmp::min(self.pos, slice.len() as u64) as usize;
let remaining = &slice[start..];
if buf.len() > remaining.len() {
return Err(Error::from(ErrorKind::UnexpectedEof));
}
buf.copy_from_slice(&remaining[..buf.len()]);
self.pos += buf.len() as u64;
Ok(())
}
}
fn slice_write(pos: &mut u64, slice: &mut [u8], buf: &[u8]) -> Result<usize> {
let start = cmp::min(*pos, slice.len() as u64) as usize;
let amt = cmp::min(buf.len(), slice.len() - start);
slice[start..start + amt].copy_from_slice(&buf[..amt]);
*pos += amt as u64;
Ok(amt)
}
impl Write for Cursor<&mut [u8]> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
slice_write(&mut self.pos, self.inner, buf)
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
#[cfg(feature = "alloc")]
fn vec_write(pos: &mut u64, vec: &mut alloc::vec::Vec<u8>, buf: &[u8]) -> Result<usize> {
let start: usize = (*pos).try_into().map_err(|_| {
Error::new_static(
ErrorKind::InvalidInput,
"cursor position exceeds maximum possible vector length",
)
})?;
if start > vec.len() {
vec.resize(start, 0);
}
let overlap = cmp::min(buf.len(), vec.len() - start);
vec[start..start + overlap].copy_from_slice(&buf[..overlap]);
if overlap < buf.len() {
vec.extend_from_slice(&buf[overlap..]);
}
*pos += buf.len() as u64;
Ok(buf.len())
}
#[cfg(feature = "alloc")]
impl Write for Cursor<alloc::vec::Vec<u8>> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
vec_write(&mut self.pos, &mut self.inner, buf)
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}
#[cfg(feature = "alloc")]
impl Write for Cursor<&mut alloc::vec::Vec<u8>> {
fn write(&mut self, buf: &[u8]) -> Result<usize> {
vec_write(&mut self.pos, self.inner, buf)
}
fn flush(&mut self) -> Result<()> {
Ok(())
}
}