use bytes::{BufMut, Bytes, BytesMut};
#[derive(Default)]
pub struct BytesGatherer {
segments: Vec<Bytes>,
current: BytesMut,
}
impl BytesGatherer {
pub fn from_bytes(bytes: Bytes) -> Self {
let mut bytes_gatherer = Self::default();
bytes_gatherer.put_bytes(bytes);
bytes_gatherer
}
pub fn put_u8(&mut self, v: u8) {
self.current.put_u8(v);
}
pub fn put_u16_le(&mut self, v: u16) {
self.current.put_u16_le(v);
}
pub fn put_u16(&mut self, v: u16) {
self.current.put_u16(v);
}
pub fn put_u32_le(&mut self, v: u32) {
self.current.put_u32_le(v);
}
pub fn put_u32(&mut self, v: u32) {
self.current.put_u32(v);
}
pub fn put_u64(&mut self, v: u64) {
self.current.put_u64(v);
}
pub fn put_slice(&mut self, s: &[u8]) {
self.current.put_slice(s);
}
pub fn put_bytes(&mut self, bytes: Bytes) {
if bytes.is_empty() {
return;
}
self.flush();
self.segments.push(bytes);
}
pub fn put_bytes_gatherer(&mut self, mut other: BytesGatherer) {
if other.segments.is_empty() {
if !other.current.is_empty() {
self.current.put_slice(&other.current);
}
return;
}
other.flush();
self.flush();
self.segments.extend(other.segments);
}
pub fn is_empty(&self) -> bool {
self.segments.is_empty() && self.current.is_empty()
}
pub fn len(&self) -> usize {
self.segments.iter().map(|b| b.len()).sum::<usize>() + self.current.len()
}
pub fn compact(mut self, threshold: usize) -> Self {
self.flush();
let mut out: Vec<Bytes> = Vec::with_capacity(self.segments.len());
let mut acc = BytesMut::new();
for seg in self.segments {
if seg.len() < threshold {
acc.extend_from_slice(&seg);
}
else {
if !acc.is_empty() {
out.push(acc.split().freeze());
}
out.push(seg); }
}
if !acc.is_empty() {
out.push(acc.freeze());
}
Self { segments: out, current: BytesMut::new() }
}
pub fn finish(mut self) -> Vec<Bytes> {
self.flush();
self.segments
}
pub fn to_bytes(mut self) -> Bytes {
self.flush();
if self.segments.len() == 1 {
return self.segments.remove(0);
}
let total = self.segments.iter().map(|b| b.len()).sum();
let mut out = BytesMut::with_capacity(total);
for seg in self.segments {
out.extend_from_slice(&seg);
}
out.freeze()
}
fn flush(&mut self) {
if !self.current.is_empty() {
self.segments.push(self.current.split().freeze());
}
}
}