use std::io::{self, IoSlice, Write};
use crate::util;
#[derive(Debug)]
pub struct Cursor<'a> {
pos: &'a mut usize,
buf: &'a mut [u8],
}
impl<'a> Cursor<'a> {
#[inline]
pub(super) fn new(pos: &'a mut usize, buf: &'a mut [u8]) -> Self {
Self { pos, buf }
}
#[inline]
pub fn pos(&self) -> usize {
*self.pos
}
#[inline]
pub fn set_pos(&mut self, pos: usize) {
*self.pos = util::min_usize(pos, self.buf.len());
}
#[inline]
pub fn buf_len(&mut self) -> usize {
self.buf.len()
}
#[inline]
pub fn zero_out(&mut self) {
self.buf.fill(0);
self.set_pos(0);
}
}
impl Write for Cursor<'_> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let pos = util::min_usize(*self.pos, self.buf.len());
let amt = (&mut self.buf[pos..]).write(buf)?;
*self.pos += amt;
Ok(amt)
}
#[inline]
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
let mut nwritten = 0;
for buf in bufs {
let n = self.write(buf)?;
nwritten += n;
if n < buf.len() {
break;
}
}
Ok(nwritten)
}
#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn write_works() {
let mut pos = 0;
let mut buf = [0; 32];
{
let mut cursor = Cursor::new(&mut pos, &mut buf[..]);
cursor.write_all(b"hello").unwrap();
}
assert_eq!(pos, 5);
assert_eq!(&buf[..pos], b"hello");
{
let mut cursor = Cursor::new(&mut pos, &mut buf[..]);
cursor.write_all(b", world").unwrap();
}
assert_eq!(pos, 12);
assert_eq!(&buf[..pos], b"hello, world");
}
#[test]
fn zero_out_works() {
let mut pos = 0;
let mut buf = [0; 32];
{
let mut cursor = Cursor::new(&mut pos, &mut buf[..]);
cursor.write_all(b"hello").unwrap();
}
assert_eq!(pos, 5);
assert_eq!(&buf[..pos], b"hello");
{
let mut cursor = Cursor::new(&mut pos, &mut buf[..]);
cursor.zero_out();
}
assert_eq!(pos, 0);
assert_eq!(&buf, &[0; 32]);
}
#[test]
fn set_pos_cannot_exceed_buf_len() {
let mut pos = 0;
let mut buf = [0; 32];
let mut cursor = Cursor::new(&mut pos, &mut buf[..]);
cursor.set_pos(1);
assert_eq!(cursor.pos(), 1);
cursor.set_pos(32);
assert_eq!(cursor.pos(), 32);
cursor.set_pos(33);
assert_eq!(cursor.pos(), 32);
}
}