use core::{cmp, num::NonZeroUsize};
use std::{
io,
ops::{Bound, RangeBounds},
};
use super::{
Chunk, ChunkWriter,
reader::{AdvanceableReader, DidntRead, DidntSiphon, HasReader, Reader, SiphonableReader},
writer::{DidntWrite, HasWriter, Writer},
};
use crate::{buffers::reader::SeekableReader, collections::SingleOrVec};
#[derive(Debug, Clone, Default, Eq)]
pub struct Bytes {
chunks: SingleOrVec<Chunk>,
}
impl Bytes {
#[must_use]
pub const fn new() -> Self {
Self {
chunks: SingleOrVec::new(),
}
}
#[must_use]
pub const fn single(chunk: Chunk) -> Self {
Self {
chunks: SingleOrVec::single(chunk),
}
}
#[inline(always)]
pub fn len(&self) -> usize {
self.chunks.as_ref().iter().fold(0, |len, slice| len + slice.len())
}
pub fn is_empty(&self) -> bool {
self.chunks.is_empty()
}
pub fn clear(&mut self) {
self.chunks.clear();
}
pub fn push(&mut self, chunk: Chunk) {
if !chunk.is_empty() {
self.chunks.push(chunk);
}
}
pub fn chunks(&self) -> impl Iterator<Item = &Chunk> + '_ {
self.chunks.as_ref().iter()
}
pub fn to_chunk(&self) -> Chunk {
match self.chunks.as_slice() {
[] => [].into(),
[chunk] => chunk.clone(),
_ => self.to_vec().into(),
}
}
pub fn slices(&self) -> impl Iterator<Item = &[u8]> + '_ {
self.chunks().map(Chunk::as_slice)
}
pub fn to_vec(&self) -> Vec<u8> {
self.slices().fold(Vec::with_capacity(self.len()), |mut acc, s| {
acc.extend_from_slice(s);
acc
})
}
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(),
};
let mut reader = self.reader();
reader.skip(start_delta).ok()?;
let mut bytes = Self::new();
let len = end_delta - start_delta;
reader.read_chunks(len, |c| bytes.chunks.push(c)).ok()?;
Some(bytes)
}
pub fn reader(&self) -> BytesReader<'_> {
BytesReader {
inner: self,
cursor: BytesPos { slice: 0, byte: 0 },
}
}
pub fn writer(&mut self) -> BytesWriter<'_> {
BytesWriter {
inner: self,
writer: ChunkWriter::new(),
}
}
}
impl PartialEq for Bytes {
fn eq(&self, other: &Self) -> bool {
let mut self_slices = self.slices();
let mut other_slices = other.slices();
let mut current_self = self_slices.next();
let mut current_other = other_slices.next();
loop {
match (current_self, current_other) {
(None, None) => return true,
(None, _) | (_, None) => return false,
(Some(l), Some(r)) => {
let cmp_len = l.len().min(r.len());
let lhs = super::unsafe_slice!(l, ..cmp_len);
let rhs = super::unsafe_slice!(r, ..cmp_len);
if lhs != rhs {
return false;
}
if cmp_len == l.len() {
current_self = self_slices.next();
} else {
let lhs = super::unsafe_slice!(l, cmp_len..);
current_self = Some(lhs);
}
if cmp_len == r.len() {
current_other = other_slices.next();
} else {
let rhs = super::unsafe_slice!(r, cmp_len..);
current_other = Some(rhs);
}
}
}
}
}
}
impl<T> From<T> for Bytes
where
T: Into<Chunk>,
{
fn from(t: T) -> Self {
Bytes::single(t.into())
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) struct BytesPos {
pub(crate) slice: usize,
pub(crate) byte: usize,
}
impl BytesPos {
pub(crate) const fn zero() -> Self {
Self { slice: 0, byte: 0 }
}
}
#[derive(Debug, Clone)]
pub struct BytesReader<'a> {
inner: &'a Bytes,
cursor: BytesPos,
}
impl SeekableReader for BytesReader<'_> {
type Mark = BytesPos;
fn mark(&mut self) -> BytesPos {
self.cursor
}
fn seek(&mut self, mark: Self::Mark) -> bool {
match self.inner.chunks.get(mark.slice) {
Some(slice) if mark.byte <= slice.len() => {
self.cursor = mark;
true
}
_ => false,
}
}
}
impl<'a> HasReader for &'a Bytes {
type Reader = BytesReader<'a>;
fn reader(self) -> Self::Reader {
self.reader()
}
}
impl Reader for BytesReader<'_> {
fn read(&mut self, mut into: &mut [u8]) -> Result<NonZeroUsize, DidntRead> {
let mut read = 0;
while let Some(slice) = self.inner.chunks.get(self.cursor.slice) {
let from = super::unsafe_slice!(slice.as_slice(), self.cursor.byte..);
let len = from.len().min(into.len());
let lhs = super::unsafe_slice_mut!(into, ..len);
let rhs = super::unsafe_slice!(from, ..len);
lhs.copy_from_slice(rhs);
into = super::unsafe_slice_mut!(into, len..);
read += len;
self.cursor.byte += len;
if self.cursor.byte == slice.len() {
self.cursor.slice += 1;
self.cursor.byte = 0;
}
if into.is_empty() {
break;
}
}
NonZeroUsize::new(read).ok_or(DidntRead)
}
fn read_exact(&mut self, into: &mut [u8]) -> Result<(), DidntRead> {
let len = Reader::read(self, into)?;
if len.get() == into.len() {
Ok(())
} else {
Err(DidntRead)
}
}
fn read_u8(&mut self) -> Result<u8, DidntRead> {
let slice = self.inner.chunks.get(self.cursor.slice).ok_or(DidntRead)?;
let byte = *slice.get(self.cursor.byte).ok_or(DidntRead)?;
self.cursor.byte += 1;
if self.cursor.byte == slice.len() {
self.cursor.slice += 1;
self.cursor.byte = 0;
}
Ok(byte)
}
fn remaining(&self) -> usize {
let s = super::unsafe_slice!(self.inner.chunks.as_ref(), self.cursor.slice..);
s.iter().fold(0, |acc, it| acc + it.len()) - self.cursor.byte
}
fn read_chunks<F: FnMut(Chunk)>(&mut self, len: usize, mut f: F) -> Result<(), DidntRead> {
if self.remaining() < len {
return Err(DidntRead);
}
let iter = BytesSliceIterator {
reader: self,
remaining: len,
};
for slice in iter {
f(slice);
}
Ok(())
}
fn read_chunk(&mut self, len: usize) -> Result<Chunk, DidntRead> {
let slice = self.inner.chunks.get(self.cursor.slice).ok_or(DidntRead)?;
match (slice.len() - self.cursor.byte).cmp(&len) {
cmp::Ordering::Less => {
let mut buffer = vec![0u8; len];
Reader::read_exact(self, &mut buffer)?;
Ok(buffer.into())
}
cmp::Ordering::Equal => {
let s = slice.view(self.cursor.byte..).ok_or(DidntRead)?;
self.cursor.slice += 1;
self.cursor.byte = 0;
Ok(s)
}
cmp::Ordering::Greater => {
let start = self.cursor.byte;
self.cursor.byte += len;
slice.view(start..self.cursor.byte).ok_or(DidntRead)
}
}
}
}
impl SiphonableReader for BytesReader<'_> {
fn siphon<W>(&mut self, writer: &mut W) -> Result<NonZeroUsize, DidntSiphon>
where
W: Writer,
{
let mut read = 0;
while let Some(slice) = self.inner.chunks.get(self.cursor.slice) {
let from = super::unsafe_slice!(slice.as_slice(), self.cursor.byte..);
match writer.write(from) {
Ok(len) => {
read += len.get();
self.cursor.byte += len.get();
if self.cursor.byte == slice.len() {
self.cursor.slice += 1;
self.cursor.byte = 0;
}
}
Err(_) => {
return NonZeroUsize::new(read).ok_or(DidntSiphon);
}
}
}
NonZeroUsize::new(read).ok_or(DidntSiphon)
}
}
impl io::Read for BytesReader<'_> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match <Self as Reader>::read(self, buf) {
Ok(n) => Ok(n.get()),
Err(_) => Ok(0),
}
}
}
impl AdvanceableReader for BytesReader<'_> {
fn skip(&mut self, offset: usize) -> Result<(), DidntRead> {
let mut remaining_offset = offset;
while remaining_offset > 0 {
let s = self.inner.chunks.get(self.cursor.slice).ok_or(DidntRead)?;
let remains_in_current_slice = s.len() - self.cursor.byte;
let advance = remaining_offset.min(remains_in_current_slice);
remaining_offset -= advance;
self.cursor.byte += advance;
if self.cursor.byte == s.len() {
self.cursor.slice += 1;
self.cursor.byte = 0;
}
}
Ok(())
}
fn backtrack(&mut self, offset: usize) -> Result<(), DidntRead> {
let mut remaining_offset = offset;
while remaining_offset > 0 {
let backtrack = remaining_offset.min(self.cursor.byte);
remaining_offset -= backtrack;
self.cursor.byte -= backtrack;
if self.cursor.byte == 0 {
if self.cursor.slice == 0 {
break;
}
self.cursor.slice -= 1;
self.cursor.byte = self.inner.chunks.get(self.cursor.slice).ok_or(DidntRead)?.len();
}
}
if remaining_offset == 0 { Ok(()) } else { Err(DidntRead) }
}
}
impl io::Seek for BytesReader<'_> {
fn seek(&mut self, pos: io::SeekFrom) -> io::Result<u64> {
let current_pos = self
.inner
.slices()
.take(self.cursor.slice)
.fold(0, |acc, s| acc + s.len())
+ self.cursor.byte;
let current_pos = i64::try_from(current_pos).map_err(|e| io::Error::other(e.to_string()))?;
let offset = match pos {
io::SeekFrom::Start(s) => i64::try_from(s).unwrap_or(i64::MAX) - current_pos,
io::SeekFrom::Current(s) => s,
io::SeekFrom::End(s) => self.inner.len() as i64 + s - current_pos,
};
match self.advance(offset as isize) {
Ok(()) => Ok((offset + current_pos) as u64),
Err(_) => Err(io::Error::new(io::ErrorKind::InvalidInput, "InvalidInput")),
}
}
}
pub(crate) struct BytesSliceIterator<'a, 'b> {
reader: &'a mut BytesReader<'b>,
remaining: usize,
}
impl Iterator for BytesSliceIterator<'_, '_> {
type Item = Chunk;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
return None;
}
let slice = super::unsafe_slice!(self.reader.inner.chunks.as_ref(), self.reader.cursor.slice);
let start = self.reader.cursor.byte;
let current = super::unsafe_slice!(slice, start..);
let len = current.len();
match self.remaining.cmp(&len) {
cmp::Ordering::Less => {
let end = start + self.remaining;
let slice = slice.view(start..end);
self.reader.cursor.byte = end;
self.remaining = 0;
slice
}
cmp::Ordering::Equal => {
let end = start + self.remaining;
let slice = slice.view(start..end);
self.reader.cursor.slice += 1;
self.reader.cursor.byte = 0;
self.remaining = 0;
slice
}
cmp::Ordering::Greater => {
let end = start + len;
let slice = slice.view(start..end);
self.reader.cursor.slice += 1;
self.reader.cursor.byte = 0;
self.remaining -= len;
slice
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
(1, None)
}
}
#[derive(Debug)]
pub struct BytesWriter<'a> {
inner: &'a mut Bytes,
writer: ChunkWriter,
}
impl Drop for BytesWriter<'_> {
fn drop(&mut self) {
let written = self.writer.snapshot();
if !written.is_empty() {
self.inner.push(written);
}
}
}
impl<'a> HasWriter for &'a mut Bytes {
type Writer = BytesWriter<'a>;
fn writer(self) -> Self::Writer {
self.writer()
}
}
impl Writer for BytesWriter<'_> {
fn write(&mut self, bytes: &[u8]) -> Result<NonZeroUsize, DidntWrite> {
self.writer.write(bytes)
}
fn write_exact(&mut self, bytes: &[u8]) -> Result<(), DidntWrite> {
self.writer.write_exact(bytes)
}
fn remaining(&self) -> usize {
usize::MAX
}
fn write_chunk(&mut self, slice: &Chunk) -> Result<(), DidntWrite> {
let written = self.writer.snapshot();
if !written.is_empty() {
self.inner.push(written);
}
if !slice.is_empty() {
self.inner.push(slice.clone());
}
Ok(())
}
unsafe fn with_slot<F>(&mut self, len: usize, write: F) -> Result<NonZeroUsize, DidntWrite>
where
F: FnOnce(&mut [u8]) -> usize,
{
unsafe { self.writer.with_slot(len, write) }
}
}
impl io::Write for BytesWriter<'_> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
if buf.is_empty() {
return Ok(0);
}
match <Self as Writer>::write(self, buf) {
Ok(n) => Ok(n.get()),
Err(_) => Err(io::ErrorKind::UnexpectedEof.into()),
}
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Bytes {
#[cfg(test)]
pub(crate) fn rand(len: usize) -> Self {
let mut bytes = Bytes::new();
bytes.push(Chunk::rand(len));
bytes
}
}
impl AsRef<Bytes> for Bytes {
fn as_ref(&self) -> &Bytes {
self
}
}
impl<T> Extend<T> for Bytes
where
T: Into<Chunk>,
{
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
for elem in iter {
self.push(elem.into());
}
}
}
impl IntoIterator for Bytes {
type Item = Chunk;
type IntoIter = crate::collections::single_or_vec::IntoIter<Chunk>;
fn into_iter(self) -> Self::IntoIter {
self.chunks.into_iter()
}
}
#[cfg(test)]
mod tests {
use crate::buffers::{Bytes, Chunk, reader::Reader};
#[test]
fn bytes_eq() {
let slice: Chunk = vec![0u8, 1, 2, 3, 4, 5, 6, 7].into();
let mut bytes1 = Bytes::new();
bytes1.push(slice.view(..4).unwrap());
bytes1.push(slice.view(4..8).unwrap());
let mut bytes2 = Bytes::new();
bytes2.push(slice.view(..1).unwrap());
bytes2.push(slice.view(1..4).unwrap());
bytes2.push(slice.view(4..8).unwrap());
assert_eq!(bytes1, bytes2);
let mut bytes1 = Bytes::new();
bytes1.push(slice.view(2..4).unwrap());
bytes1.push(slice.view(4..8).unwrap());
let mut bytes2 = Bytes::new();
bytes2.push(slice.view(2..3).unwrap());
bytes2.push(slice.view(3..6).unwrap());
bytes2.push(slice.view(6..8).unwrap());
assert_eq!(bytes1, bytes2);
}
#[test]
fn bytes_seek() {
use std::io::Seek;
let mut buf = Bytes::new();
buf.push([0u8, 1u8, 2u8, 3u8].into());
buf.push([4u8, 5u8, 6u8, 7u8, 8u8].into());
buf.push([9u8, 10u8, 11u8, 12u8, 13u8, 14u8].into());
let mut reader = buf.reader();
assert_eq!(reader.stream_position().unwrap(), 0);
assert_eq!(reader.read_u8().unwrap(), 0);
assert_eq!(reader.seek(std::io::SeekFrom::Current(6)).unwrap(), 7);
assert_eq!(reader.read_u8().unwrap(), 7);
assert_eq!(reader.seek(std::io::SeekFrom::Current(-5)).unwrap(), 3);
assert_eq!(reader.read_u8().unwrap(), 3);
assert_eq!(reader.seek(std::io::SeekFrom::Current(10)).unwrap(), 14);
assert_eq!(reader.read_u8().unwrap(), 14);
reader.seek(std::io::SeekFrom::Current(100)).unwrap_err();
assert_eq!(reader.seek(std::io::SeekFrom::Start(0)).unwrap(), 0);
assert_eq!(reader.read_u8().unwrap(), 0);
assert_eq!(reader.seek(std::io::SeekFrom::Start(12)).unwrap(), 12);
assert_eq!(reader.read_u8().unwrap(), 12);
assert_eq!(reader.seek(std::io::SeekFrom::Start(15)).unwrap(), 15);
reader.read_u8().unwrap_err();
reader.seek(std::io::SeekFrom::Start(100)).unwrap_err();
assert_eq!(reader.seek(std::io::SeekFrom::End(0)).unwrap(), 15);
reader.read_u8().unwrap_err();
assert_eq!(reader.seek(std::io::SeekFrom::End(-5)).unwrap(), 10);
assert_eq!(reader.read_u8().unwrap(), 10);
assert_eq!(reader.seek(std::io::SeekFrom::End(-15)).unwrap(), 0);
assert_eq!(reader.read_u8().unwrap(), 0);
reader.seek(std::io::SeekFrom::End(-20)).unwrap_err();
assert_eq!(reader.seek(std::io::SeekFrom::Start(10)).unwrap(), 10);
reader.seek(std::io::SeekFrom::Current(-100)).unwrap_err();
}
#[test]
fn bytes_view() {
let bytes: Bytes = [0, 1, 2, 3, 4, 5, 6, 7].into();
let view1: Bytes = bytes.view(..).unwrap();
assert_eq!(view1.to_vec(), vec![0, 1, 2, 3, 4, 5, 6, 7]);
let view2 = bytes.view(0..8).unwrap();
assert_eq!(view2.to_vec(), vec![0, 1, 2, 3, 4, 5, 6, 7]);
let view3 = bytes.view(1..).unwrap();
assert_eq!(view3.to_vec(), vec![1, 2, 3, 4, 5, 6, 7]);
let view4 = bytes.view(2..=4).unwrap();
assert_eq!(view4.to_vec(), vec![2, 3, 4]);
let view5 = bytes.view(3..4).unwrap();
assert_eq!(view5.to_vec(), vec![3]);
let view6 = bytes.view(..3).unwrap();
assert_eq!(view6.to_vec(), vec![0, 1, 2]);
let view7 = bytes.view(4..4).unwrap();
assert_eq!(view7.to_vec(), vec![]);
let view8 = bytes.view(7..=7).unwrap();
assert_eq!(view8.to_vec(), vec![7]);
let view9 = bytes.view(6..).unwrap();
assert_eq!(view9.to_vec(), vec![6, 7]);
let view10 = view3.view(1..4).unwrap();
assert_eq!(view10.to_vec(), vec![2, 3, 4]);
assert!(bytes.view(100..).is_none());
assert!(bytes.view(..100).is_none());
}
}