use crate::{
buffer::{Buffer, SplitBuffer},
reader::HasReader,
vec,
writer::{BacktrackableWriter, DidntWrite, HasWriter, Writer},
ZSlice,
};
use alloc::{boxed::Box, sync::Arc};
use core::{fmt, num::NonZeroUsize, option};
#[derive(Clone, PartialEq, Eq)]
pub struct BBuf {
buffer: Box<[u8]>,
len: usize,
}
impl BBuf {
#[must_use]
pub fn with_capacity(capacity: usize) -> Self {
Self {
buffer: vec::uninit(capacity).into_boxed_slice(),
len: 0,
}
}
#[must_use]
pub const fn capacity(&self) -> usize {
self.buffer.len()
}
#[must_use]
pub fn as_slice(&self) -> &[u8] {
crate::unsafe_slice!(self.buffer, ..self.len)
}
pub fn as_mut_slice(&mut self) -> &mut [u8] {
crate::unsafe_slice_mut!(self.buffer, ..self.len)
}
pub fn clear(&mut self) {
self.len = 0;
}
fn as_writable_slice(&mut self) -> &mut [u8] {
crate::unsafe_slice_mut!(self.buffer, self.len..)
}
}
impl fmt::Debug for BBuf {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:02x?}", self.as_slice())
}
}
impl Buffer for BBuf {
fn len(&self) -> usize {
self.len
}
}
impl Buffer for &BBuf {
fn len(&self) -> usize {
self.len
}
}
impl Buffer for &mut BBuf {
fn len(&self) -> usize {
self.len
}
}
impl SplitBuffer for BBuf {
type Slices<'a> = option::IntoIter<&'a [u8]>;
fn slices(&self) -> Self::Slices<'_> {
Some(self.as_slice()).into_iter()
}
}
impl HasWriter for &mut BBuf {
type Writer = Self;
fn writer(self) -> Self::Writer {
self
}
}
impl Writer for &mut BBuf {
fn write(&mut self, bytes: &[u8]) -> Result<NonZeroUsize, DidntWrite> {
let mut writer = self.as_writable_slice().writer();
let len = writer.write(bytes)?;
self.len += len.get();
Ok(len)
}
fn write_exact(&mut self, bytes: &[u8]) -> Result<(), DidntWrite> {
let mut writer = self.as_writable_slice().writer();
writer.write_exact(bytes)?;
self.len += bytes.len();
Ok(())
}
fn remaining(&self) -> usize {
self.capacity() - self.len()
}
fn with_slot<F>(&mut self, len: usize, f: F) -> Result<NonZeroUsize, DidntWrite>
where
F: FnOnce(&mut [u8]) -> usize,
{
if self.remaining() < len {
return Err(DidntWrite);
}
let written = f(self.as_writable_slice());
self.len += written;
NonZeroUsize::new(written).ok_or(DidntWrite)
}
}
impl BacktrackableWriter for &mut BBuf {
type Mark = usize;
fn mark(&mut self) -> Self::Mark {
self.len
}
fn rewind(&mut self, mark: Self::Mark) -> bool {
self.len = mark;
true
}
}
#[cfg(feature = "std")]
impl std::io::Write for &mut BBuf {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
match <Self as Writer>::write(self, buf) {
Ok(n) => Ok(n.get()),
Err(_) => Err(std::io::Error::new(
std::io::ErrorKind::UnexpectedEof,
"UnexpectedEof",
)),
}
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}
impl<'a> HasReader for &'a BBuf {
type Reader = &'a [u8];
fn reader(self) -> Self::Reader {
self.as_slice()
}
}
impl From<BBuf> for ZSlice {
fn from(value: BBuf) -> Self {
ZSlice {
buf: Arc::new(value.buffer),
start: 0,
end: value.len,
#[cfg(feature = "shared-memory")]
kind: crate::ZSliceKind::Raw,
}
}
}
#[cfg(feature = "test")]
impl BBuf {
pub fn rand(len: usize) -> Self {
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use rand::Rng;
let mut rng = rand::thread_rng();
let buffer = (0..len)
.map(|_| rng.gen())
.collect::<Vec<u8>>()
.into_boxed_slice();
Self { buffer, len }
}
}