use crate::decode::{ReadError, ReadResult, Reader};
use crate::encode::{WriteError, WriteResult, Writer};
use core::mem::MaybeUninit;
#[cfg(feature = "std")]
use std::io::{Read, Write};
#[cfg(feature = "std")]
use core::cell::UnsafeCell;
pub struct Cursor<T> {
cursor: usize,
inner: T,
}
impl<T> Cursor<T> {
#[inline]
pub const fn new(inner: T) -> Cursor<T> {
Self { cursor: 0, inner }
}
#[inline]
pub fn advance(&mut self, n: usize) {
self.cursor += n;
}
}
impl<T> Reader for Cursor<T>
where
T: AsRef<[u8]>,
{
#[inline]
fn read_borrow(&self, n: usize) -> ReadResult<&[u8]> {
self.inner
.as_ref()
.get(self.cursor..self.cursor + n)
.ok_or(ReadError::OutOfBounds)
}
#[inline]
fn advance(&mut self, n: usize) {
self.advance(n)
}
}
impl<T> Writer for Cursor<T>
where
T: AsMut<[u8]>,
{
#[inline]
fn allocate(&mut self, n: usize) -> WriteResult<&mut [MaybeUninit<u8>]> {
let slice = self
.inner
.as_mut()
.get_mut(n..)
.ok_or(WriteError::OutOfBounds)?;
Ok(unsafe {
core::slice::from_raw_parts_mut(slice.as_mut_ptr().cast(), slice.len())
})
}
#[inline]
unsafe fn commit(&mut self, n: usize) {
self.advance(n);
}
}
#[derive(Default)]
#[cfg(feature = "std")]
struct IncrementalBuffer {
buffer: Vec<u8>,
position: usize,
}
#[cfg(feature = "std")]
impl IncrementalBuffer {
fn extend_capacity_overlapping(&mut self, n: usize, overlap_index: usize) -> &mut [MaybeUninit<u8>] {
unsafe {
self.buffer.set_len(overlap_index.min(self.buffer.len()));
}
self.buffer.reserve(n * 2);
self.buffer
.spare_capacity_mut()[..n]
.as_mut()
}
fn resize_drained(&mut self, n: usize) -> &mut [u8] {
self.buffer.drain(..self.position);
self.position = 0;
let old_len = self.buffer.len();
self.buffer.resize(old_len + n * 2, 0);
&mut self.buffer[old_len..]
}
fn get(&self, n: usize) -> Option<&[u8]> {
self.buffer.get(self.position..self.position + n)
}
fn get_all(&self) -> &[u8] {
self.buffer.as_slice()
}
fn len(&self) -> usize {
self.buffer.len()
}
fn consume(&mut self, n: usize) {
self.position = core::cmp::min(self.position + n, self.buffer.len());
}
unsafe fn inc_length(&mut self, n: usize) {
unsafe { self.buffer.set_len(self.buffer.len().saturating_add(n)); }
}
fn dec_length(&mut self, n: usize) {
unsafe {
self.buffer.set_len(self.buffer.len().saturating_sub(n));
}
}
}
#[cfg(feature = "std")]
pub struct CursorView<T>(UnsafeCell<CursorViewInner<T>>);
#[cfg(feature = "std")]
impl<T> CursorView<T> {
pub fn new(inner: T) -> Self {
Self(UnsafeCell::new(CursorViewInner::new(inner)))
}
pub fn with_capacity(inner: T, capacity: usize) -> Self {
Self(UnsafeCell::new(CursorViewInner::with_capacity(inner, capacity)))
}
}
#[cfg(feature = "std")]
impl<T> CursorView<T>
where
T: Write,
{
pub fn flush(&mut self) -> std::io::Result<()> {
let borrow = self.0.get_mut();
borrow.inner.write_all(borrow.buffer.get_all())?;
borrow.inner.flush()
}
}
#[cfg(feature = "std")]
impl<T> Reader for CursorView<T>
where
T: Read,
{
fn read_borrow(&self, n: usize) -> ReadResult<&[u8]> {
let unique = unsafe {
&mut *self.0.get()
};
if unique.buffer.get(n).is_some() {
return Ok(unique.buffer.get(n).unwrap());
}
let extended = unique.buffer.resize_drained(n);
let extended_len = extended.len();
let bytes_read = unique.inner.read(extended)?;
unique.buffer.dec_length(extended_len - bytes_read);
unique.buffer.get(n).ok_or(ReadError::OutOfBounds)
}
fn advance(&mut self, n: usize) {
self.0.get_mut().buffer.consume(n);
}
}
#[cfg(feature = "std")]
impl<T> Writer for CursorView<T>
where
T: Write,
{
fn allocate(&mut self, n: usize) -> WriteResult<&mut [MaybeUninit<u8>]> {
let borrow = self.0.get_mut();
let overlap_index = if borrow.buffer.len().div_ceil(n) > 3 {
borrow.inner.write_all(borrow.buffer.get_all())?;
0
} else {
borrow.buffer.len()
};
Ok(borrow.buffer.extend_capacity_overlapping(n, overlap_index))
}
unsafe fn commit(&mut self, n: usize) {
let borrow = self.0.get_mut();
unsafe {
borrow.buffer.inc_length(n)
}
}
}
#[cfg(feature = "std")]
struct CursorViewInner<T> {
buffer: IncrementalBuffer,
inner: T
}
#[cfg(feature = "std")]
impl<T> CursorViewInner<T> {
fn new(inner: T) -> Self {
Self {
buffer: IncrementalBuffer { buffer: Vec::new(), position: 0 },
inner
}
}
fn with_capacity(inner: T, capacity: usize) -> Self {
Self {
buffer: IncrementalBuffer { buffer: Vec::with_capacity(capacity), position: 0 },
inner
}
}
}