#[cfg(feature = "alloc")]
use alloc::boxed::Box;
use core::{cmp, io::BorrowedBuf, mem::MaybeUninit};
#[cfg(not(feature = "alloc"))]
use heapless::Vec;
#[cfg(not(feature = "alloc"))]
use crate::DEFAULT_BUF_SIZE;
use crate::{Read, Result};
pub struct Buffer {
#[cfg(feature = "alloc")]
buf: Box<[MaybeUninit<u8>]>,
#[cfg(not(feature = "alloc"))]
buf: Vec<MaybeUninit<u8>, DEFAULT_BUF_SIZE, u16>,
pos: usize,
filled: usize,
#[cfg(borrowedbuf_init)]
initialized: usize,
}
impl Buffer {
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
#[cfg(feature = "alloc")]
let buf = Box::new_uninit_slice(capacity);
#[cfg(not(feature = "alloc"))]
let buf = {
let mut buf = Vec::new();
assert!(capacity <= buf.capacity());
unsafe { buf.set_len(capacity) };
buf
};
Self {
buf,
pos: 0,
filled: 0,
#[cfg(borrowedbuf_init)]
initialized: 0,
}
}
#[inline]
pub fn buffer(&self) -> &[u8] {
unsafe {
self.buf
.get_unchecked(self.pos..self.filled)
.assume_init_ref()
}
}
#[inline]
pub fn capacity(&self) -> usize {
self.buf.len()
}
#[inline]
pub fn filled(&self) -> usize {
self.filled
}
#[inline]
pub fn pos(&self) -> usize {
self.pos
}
#[cfg(borrowedbuf_init)]
#[inline]
pub fn initialized(&self) -> usize {
self.initialized
}
#[inline]
pub fn discard_buffer(&mut self) {
self.pos = 0;
self.filled = 0;
}
#[inline]
pub fn consume(&mut self, amt: usize) {
self.pos = cmp::min(self.pos + amt, self.filled);
}
#[inline]
pub fn consume_with<V>(&mut self, amt: usize, mut visitor: V) -> bool
where
V: FnMut(&[u8]),
{
if let Some(claimed) = self.buffer().get(..amt) {
visitor(claimed);
self.pos += amt;
true
} else {
false
}
}
#[inline]
pub fn unconsume(&mut self, amt: usize) {
self.pos = self.pos.saturating_sub(amt);
}
pub fn read_more(&mut self, mut reader: impl Read) -> Result<usize> {
let mut buf = BorrowedBuf::from(&mut self.buf[self.filled..]);
#[cfg(borrowedbuf_init)]
let old_init = self.initialized - self.filled;
#[cfg(borrowedbuf_init)]
unsafe {
buf.set_init(old_init);
}
reader.read_buf(buf.unfilled())?;
self.filled += buf.len();
#[cfg(borrowedbuf_init)]
{
self.initialized += buf.init_len() - old_init;
}
Ok(buf.len())
}
pub fn backshift(&mut self) {
self.buf.copy_within(self.pos.., 0);
self.filled -= self.pos;
self.pos = 0;
}
#[inline]
pub fn fill_buf(&mut self, mut reader: impl Read) -> Result<&[u8]> {
if self.pos >= self.filled {
debug_assert!(self.pos == self.filled);
#[cfg(feature = "alloc")]
let mut buf = BorrowedBuf::from(&mut *self.buf);
#[cfg(not(feature = "alloc"))]
let mut buf = BorrowedBuf::from(self.buf.as_mut_slice());
#[cfg(borrowedbuf_init)]
unsafe {
buf.set_init(self.initialized);
}
let result = reader.read_buf(buf.unfilled());
self.pos = 0;
self.filled = buf.len();
#[cfg(borrowedbuf_init)]
{
self.initialized = buf.init_len();
}
result?;
}
Ok(self.buffer())
}
}