use super::chunked::{AdvanceStopped, Inner};
use crate::{DrainChunks, IntoChunks};
use bytes::buf::{Buf, BufMut, UninitSlice};
use bytes::Bytes;
use std::cmp::min;
use std::fmt;
use std::io::IoSlice;
#[derive(Debug, Default)]
pub struct ChunkedBytes {
inner: Inner,
cap: usize,
}
impl ChunkedBytes {
#[inline]
pub fn new() -> Self {
Default::default()
}
#[inline]
pub fn with_chunk_size_limit(chunk_size: usize) -> Self {
ChunkedBytes {
inner: Inner::with_chunk_size(chunk_size),
cap: 0,
}
}
#[inline]
pub fn with_profile(chunk_size: usize, chunking_capacity: usize) -> Self {
ChunkedBytes {
inner: Inner::with_profile(chunk_size, chunking_capacity),
cap: 0,
}
}
#[inline]
pub fn chunk_size_limit(&self) -> usize {
self.inner.chunk_size()
}
#[inline]
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
#[cfg(test)]
pub fn staging_capacity(&self) -> usize {
self.inner.staging_capacity()
}
#[inline]
pub fn flush(&mut self) {
debug_assert!(self.inner.staging_len() <= self.inner.chunk_size());
self.inner.flush()
}
pub fn put_bytes(&mut self, mut src: Bytes) {
if !src.is_empty() {
self.flush();
let chunk_size = self.inner.chunk_size();
while src.len() > chunk_size {
self.inner.push_chunk(src.split_to(chunk_size));
}
self.inner.push_chunk(src);
}
}
#[inline]
pub fn drain_chunks(&mut self) -> DrainChunks<'_> {
self.inner.drain_chunks()
}
#[inline]
pub fn into_chunks(self) -> IntoChunks {
debug_assert!(self.inner.staging_len() <= self.inner.chunk_size());
self.inner.into_chunks()
}
}
unsafe impl BufMut for ChunkedBytes {
#[inline]
fn remaining_mut(&self) -> usize {
self.inner.remaining_mut()
}
#[inline]
unsafe fn advance_mut(&mut self, cnt: usize) {
assert!(
self.inner.staging_len() + cnt <= self.cap,
"new_len = {}; capacity = {}",
self.inner.staging_len() + cnt,
self.cap
);
self.inner.advance_mut(cnt);
}
fn chunk_mut(&mut self) -> &mut UninitSlice {
if self.inner.staging_len() == self.cap {
let new_cap = self.inner.reserve_staging();
self.cap = min(new_cap, self.chunk_size_limit())
}
let chunk = self.inner.chunk_mut();
let len = min(chunk.len(), self.cap);
&mut chunk[..len]
}
}
impl Buf for ChunkedBytes {
#[inline]
fn remaining(&self) -> usize {
self.inner.remaining()
}
#[inline]
fn has_remaining(&self) -> bool {
!self.is_empty()
}
#[inline]
fn chunk(&self) -> &[u8] {
self.inner.chunk()
}
fn advance(&mut self, cnt: usize) {
match self.inner.advance(cnt) {
AdvanceStopped::InChunk => {}
AdvanceStopped::InStaging(adv) => {
self.cap -= adv;
}
}
}
#[inline]
fn chunks_vectored<'a>(&'a self, dst: &mut [IoSlice<'a>]) -> usize {
debug_assert!(self.inner.staging_len() <= self.inner.chunk_size());
self.inner.chunks_vectored(dst)
}
#[inline]
fn copy_to_bytes(&mut self, len: usize) -> Bytes {
self.inner.copy_to_bytes(len)
}
}
impl fmt::Write for ChunkedBytes {
#[inline]
fn write_str(&mut self, s: &str) -> fmt::Result {
if self.remaining_mut() >= s.len() {
self.put_slice(s.as_bytes());
Ok(())
} else {
Err(fmt::Error)
}
}
#[inline]
fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> fmt::Result {
fmt::write(self, args)
}
}