use core::{
fmt,
num::NonZeroUsize,
ops::{Bound, Deref, RangeBounds},
};
use std::{any::Any, sync::Arc};
use super::{
reader::{DidntRead, HasReader, Reader},
writer::{DidntWrite, Writer},
};
use crate::buffers::writer::HasWriter;
pub trait DynBuf: Send + Sync {
fn as_slice(&self) -> &[u8];
fn as_any(&self) -> &dyn Any;
}
impl DynBuf for Vec<u8> {
fn as_slice(&self) -> &[u8] {
self
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl DynBuf for Box<[u8]> {
fn as_slice(&self) -> &[u8] {
self
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl<const N: usize> DynBuf for [u8; N] {
fn as_slice(&self) -> &[u8] {
self
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl DynBuf for &'static [u8] {
fn as_slice(&self) -> &[u8] {
self
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl DynBuf for String {
fn as_slice(&self) -> &[u8] {
self.as_bytes()
}
fn as_any(&self) -> &dyn Any {
self
}
}
impl DynBuf for &'static str {
fn as_slice(&self) -> &[u8] {
self.as_bytes()
}
fn as_any(&self) -> &dyn Any {
self
}
}
#[derive(Clone)]
pub struct Chunk {
buf: Arc<dyn DynBuf>,
start: usize,
end: usize,
}
impl Chunk {
pub fn new(buf: Arc<dyn DynBuf>, start: usize, end: usize) -> Result<Chunk, Arc<dyn DynBuf>> {
if start <= end && end <= buf.as_slice().len() {
Ok(Self { buf, start, end })
} else {
Err(buf)
}
}
#[must_use]
pub unsafe fn new_unchecked(buf: Arc<dyn DynBuf>, start: usize, end: usize) -> Chunk {
Self { buf, start, end }
}
pub const fn len(&self) -> usize {
self.end - self.start
}
pub const fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn as_slice(&self) -> &[u8] {
unsafe { self.buf.as_slice().get_unchecked(self.start..self.end) }
}
#[must_use]
pub fn downcast_ref<T: Any>(&self) -> Option<&T> {
self.buf.as_any().downcast_ref()
}
#[must_use]
pub fn view(&self, range: impl RangeBounds<usize>) -> Option<Self> {
let start_delta = match range.start_bound() {
Bound::Included(&n) => n,
Bound::Excluded(&n) => n + 1,
Bound::Unbounded => 0,
};
let end_delta = match range.end_bound() {
Bound::Included(&n) => n + 1,
Bound::Excluded(&n) => n,
Bound::Unbounded => self.len(),
};
(start_delta <= end_delta && end_delta <= self.len()).then_some(Chunk {
buf: Arc::clone(&self.buf),
start: self.start + start_delta,
end: self.start + end_delta,
})
}
}
impl Deref for Chunk {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_slice()
}
}
impl AsRef<[u8]> for Chunk {
fn as_ref(&self) -> &[u8] {
self
}
}
impl<Rhs: AsRef<[u8]> + ?Sized> PartialEq<Rhs> for Chunk {
fn eq(&self, other: &Rhs) -> bool {
self.as_slice() == other.as_ref()
}
}
impl Eq for Chunk {}
impl fmt::Display for Chunk {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:02x?}", self.as_slice())
}
}
impl fmt::Debug for Chunk {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{:02x?}", self.as_slice())
}
}
impl<T> From<Arc<T>> for Chunk
where
T: DynBuf + 'static,
{
fn from(buf: Arc<T>) -> Self {
let end = buf.as_slice().len();
Self { buf, start: 0, end }
}
}
impl<T> From<T> for Chunk
where
T: DynBuf + 'static,
{
fn from(buf: T) -> Self {
Self::from(Arc::new(buf))
}
}
#[derive(Debug)]
pub(crate) struct ChunkWriter {
inner: Arc<Vec<u8>>,
start: usize,
}
impl ChunkWriter {
pub(crate) fn new() -> Self {
Self {
inner: Arc::new(Vec::new()),
start: 0,
}
}
pub(crate) fn snapshot(&mut self) -> Chunk {
let dynbuf = Chunk {
buf: self.inner.clone(),
start: self.start,
end: self.inner.len(),
};
self.start = self.inner.len();
dynbuf
}
fn writer(&mut self) -> &mut Vec<u8> {
unsafe { &mut *(Arc::as_ptr(&self.inner) as *mut Vec<u8>) }.writer()
}
}
impl Writer for ChunkWriter {
fn write(&mut self, bytes: &[u8]) -> Result<NonZeroUsize, DidntWrite> {
let mut writer = self.writer();
let len = writer.write(bytes)?;
Ok(len)
}
fn write_exact(&mut self, bytes: &[u8]) -> Result<(), DidntWrite> {
self.write(bytes).map(|_| ())
}
fn remaining(&self) -> usize {
usize::MAX
}
unsafe fn with_slot<F>(&mut self, len: usize, write: F) -> Result<NonZeroUsize, DidntWrite>
where
F: FnOnce(&mut [u8]) -> usize,
{
let len = unsafe { self.writer().with_slot(len, write) }?;
Ok(len)
}
}
impl HasReader for &mut Chunk {
type Reader = Self;
fn reader(self) -> Self::Reader {
self
}
}
impl Reader for &mut Chunk {
fn read(&mut self, into: &mut [u8]) -> Result<NonZeroUsize, DidntRead> {
let mut reader = self.as_slice().reader();
let len = reader.read(into)?;
self.start += len.get();
Ok(len)
}
fn read_exact(&mut self, into: &mut [u8]) -> Result<(), DidntRead> {
let mut reader = self.as_slice().reader();
reader.read_exact(into)?;
self.start += into.len();
Ok(())
}
fn read_u8(&mut self) -> Result<u8, DidntRead> {
let mut reader = self.as_slice().reader();
let res = reader.read_u8()?;
self.start += 1;
Ok(res)
}
fn read_chunks<F: FnMut(Chunk)>(&mut self, len: usize, mut f: F) -> Result<(), DidntRead> {
let dynbuf = self.read_chunk(len)?;
f(dynbuf);
Ok(())
}
fn read_chunk(&mut self, len: usize) -> Result<Chunk, DidntRead> {
let res = self.view(..len).ok_or(DidntRead)?;
self.start += len;
Ok(res)
}
fn remaining(&self) -> usize {
self.len()
}
}
impl Chunk {
#[cfg(test)]
pub(crate) fn rand(len: usize) -> Self {
use rand::Rng;
let mut rng = rand::rng();
(0..len).map(|_| rng.random()).collect::<Vec<u8>>().into()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hash() {
use std::{
collections::hash_map::DefaultHasher,
hash::{Hash, Hasher},
};
let buf = vec![1, 2, 3, 4, 5];
let mut buf_hasher = DefaultHasher::new();
buf.hash(&mut buf_hasher);
let buf_hash = buf_hasher.finish();
let dynbuf: Chunk = buf.clone().into();
let mut dynbuf_hasher = DefaultHasher::new();
dynbuf.hash(&mut dynbuf_hasher);
let dynbuf_hash = dynbuf_hasher.finish();
assert_eq!(buf_hash, dynbuf_hash);
}
#[test]
fn chunk_downcast() {
let vec = vec![1u8, 2, 3, 4, 5];
let chunk1: Chunk = vec.clone().into();
let vec_ref = chunk1.downcast_ref::<Vec<u8>>().unwrap();
assert_eq!(vec_ref, &vec);
assert!(chunk1.downcast_ref::<Box<[u8]>>().is_none());
assert!(chunk1.downcast_ref::<[u8; 5]>().is_none());
let boxed: Box<[u8]> = vec![1, 2, 3, 4, 5].into_boxed_slice();
let chunk2: Chunk = boxed.clone().into();
let box_ref = chunk2.downcast_ref::<Box<[u8]>>().unwrap();
assert_eq!(box_ref.as_ref(), boxed.as_ref());
assert!(chunk2.downcast_ref::<Vec<u8>>().is_none());
let array: [u8; 5] = [1, 2, 3, 4, 5];
let chunk3: Chunk = array.into();
let array_ref = chunk3.downcast_ref::<[u8; 5]>().unwrap();
assert_eq!(array_ref, &array);
assert!(chunk3.downcast_ref::<Vec<u8>>().is_none());
assert!(chunk3.downcast_ref::<[u8; 4]>().is_none());
}
#[test]
fn chunk_as_slice() {
let chunk1: Chunk = vec![1u8, 2, 3, 4, 5].into();
let slice1 = chunk1.as_slice();
assert_eq!(slice1, &[1, 2, 3, 4, 5]);
assert_eq!(slice1.len(), 5);
let chunk2: Chunk = vec![1u8, 2, 3, 4, 5, 6, 7, 8].into();
let view2 = chunk2.view(2..6).unwrap();
let slice2 = view2.as_slice();
assert_eq!(slice2, &[3, 4, 5, 6]);
assert_eq!(slice2.len(), 4);
let chunk3: Chunk = vec![1u8, 2, 3, 4, 5].into();
let view3 = chunk3.view(2..2).unwrap();
let slice3 = view3.as_slice();
assert_eq!(slice3, &[]);
assert_eq!(slice3.len(), 0);
assert!(slice3.is_empty());
let chunk4: Chunk = vec![42u8].into();
let slice4 = chunk4.as_slice();
assert_eq!(slice4, &[42]);
assert_eq!(slice4.len(), 1);
let vec_chunk: Chunk = vec![1u8, 2, 3].into();
assert_eq!(vec_chunk.as_slice(), &[1, 2, 3]);
let box_chunk: Chunk = vec![4u8, 5, 6].into_boxed_slice().into();
assert_eq!(box_chunk.as_slice(), &[4, 5, 6]);
let array_chunk: Chunk = [7u8, 8, 9].into();
assert_eq!(array_chunk.as_slice(), &[7, 8, 9]);
}
#[test]
fn chunk_view() {
let data = vec![0u8, 1, 2, 3, 4, 5, 6, 7, 8, 9];
let chunk: Chunk = data.into();
let view1 = chunk.view(..).unwrap();
assert_eq!(view1.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
let view2 = chunk.view(2..6).unwrap();
assert_eq!(view2.as_slice(), &[2, 3, 4, 5]);
let view3 = chunk.view(..3).unwrap();
assert_eq!(view3.as_slice(), &[0, 1, 2]);
let view4 = chunk.view(7..).unwrap();
assert_eq!(view4.as_slice(), &[7, 8, 9]);
let view5 = chunk.view(1..=4).unwrap();
assert_eq!(view5.as_slice(), &[1, 2, 3, 4]);
let view6 = chunk.view(5..6).unwrap();
assert_eq!(view6.as_slice(), &[5]);
let view7 = chunk.view(3..3).unwrap();
assert_eq!(view7.as_slice(), &[]);
let view8a = chunk.view(0..2).unwrap();
assert_eq!(view8a.as_slice(), &[0, 1]);
let view8b = chunk.view(8..10).unwrap();
assert_eq!(view8b.as_slice(), &[8, 9]);
let view8c = chunk.view(0..10).unwrap();
assert_eq!(view8c.as_slice(), &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
let view9a = chunk.view(2..8).unwrap();
assert_eq!(view9a.as_slice(), &[2, 3, 4, 5, 6, 7]);
let view9b = view9a.view(1..4).unwrap();
assert_eq!(view9b.as_slice(), &[3, 4, 5]);
let view9c = view9b.view(1..2).unwrap();
assert_eq!(view9c.as_slice(), &[4]);
assert!(chunk.view(0..20).is_none());
assert!(chunk.view(5..20).is_none());
assert!(chunk.view(15..).is_none());
assert!(chunk.view(100..200).is_none());
let view11 = chunk.view(2..8).unwrap();
assert_eq!(view11.as_slice(), &[2, 3, 4, 5, 6, 7]);
let view11b = view11.view(1..4).unwrap();
assert_eq!(view11b.as_slice(), &[3, 4, 5]);
assert!(view11.view(0..10).is_none());
assert!(view11.view(7..).is_none());
let view12a = chunk.view(2..5).unwrap();
let view12b = chunk.view(2..5).unwrap();
assert_eq!(view12a, view12b);
let view12c = chunk.view(3..5).unwrap();
assert_ne!(view12a, view12c);
}
}