use std::{cmp, collections::VecDeque, fmt};
use tokio::io::ReadBuf;
use bytes::{Buf, Bytes};
use rand::{RngExt, distr::uniform::SampleRange};
#[allow(clippy::uninit_vec)]
#[must_use]
pub fn random(len: usize) -> Vec<u8> {
let mut buf = Vec::with_capacity(len);
unsafe {
buf.set_len(len);
}
rand::rng().fill(&mut buf[..]);
buf
}
pub fn random_size<R>(range: R) -> Vec<u8>
where
R: SampleRange<usize>
{
let sz = rand::rng().random_range::<usize, R>(range);
random(sz)
}
pub struct ByteReps<'a>(pub &'a [u8]);
struct RepeatedByte {
byte: u8,
count: usize
}
impl fmt::Debug for RepeatedByte {
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
match self.count {
1 => write!(fmtr, "0x{:02x}", self.byte),
_ => write!(fmtr, "0x{:02x}*{}", self.byte, self.count)
}
}
}
impl fmt::Debug for ByteReps<'_> {
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut list = fmtr.debug_list();
let &[mut byte, ref rest @ ..] = self.0 else {
return list.finish();
};
let mut count: usize = 1;
for &this in rest {
if byte == this {
count += 1;
continue;
}
list.entry(&RepeatedByte { byte, count });
count = 1;
byte = this;
}
list.entry(&RepeatedByte { byte, count });
list.finish()
}
}
impl fmt::Display for ByteReps<'_> {
fn fmt(&self, fmtr: &mut fmt::Formatter<'_>) -> fmt::Result {
<Self as fmt::Debug>::fmt(self, fmtr)
}
}
pub fn read_from_bufq(q: &mut VecDeque<Bytes>, dst: &mut [u8]) -> usize {
let mut offs = 0;
loop {
let rem = dst.len() - offs;
if rem == 0 {
break;
}
let Some(mut n) = q.pop_front() else {
break;
};
let ncopy = cmp::min(rem, n.len());
if ncopy < n.len() {
dst[offs..offs + ncopy].copy_from_slice(&n[..ncopy]);
n.advance(ncopy);
offs += ncopy;
q.push_front(n);
break;
}
dst[offs..offs + n.len()].copy_from_slice(&n);
offs += n.len();
}
offs
}
pub fn readbuf_from_bufq(q: &mut VecDeque<Bytes>, dst: &mut ReadBuf<'_>) {
while dst.remaining() > 0
&& let Some(mut n) = q.pop_front()
{
let ncopy = cmp::min(dst.remaining(), n.len());
if ncopy < n.len() {
dst.put_slice(&n[..ncopy]);
n.advance(ncopy);
q.push_front(n);
break;
}
dst.put_slice(&n);
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hex_rle() {
let buf = [0];
assert_eq!(ByteReps(&buf).to_string(), "[0x00]");
let buf = [0, 0];
assert_eq!(ByteReps(&buf).to_string(), "[0x00*2]");
let buf = [0, 1];
assert_eq!(ByteReps(&buf).to_string(), "[0x00, 0x01]");
let buf = [0, 0, 1, 1];
assert_eq!(ByteReps(&buf).to_string(), "[0x00*2, 0x01*2]");
let buf = [0, 0, 1, 1, 0, 0];
assert_eq!(ByteReps(&buf).to_string(), "[0x00*2, 0x01*2, 0x00*2]");
}
}
#[cfg(test)]
mod read_from_bufq_tests {
use super::{Bytes, VecDeque, read_from_bufq};
#[test]
fn empty() {
let mut q = VecDeque::new();
let mut buf = [0u8; 4];
let copied = read_from_bufq(&mut q, &mut buf[..]);
assert_eq!(copied, 0);
}
#[test]
fn exact_fit() {
let mut q = VecDeque::new();
q.push_back(Bytes::from("foo"));
q.push_back(Bytes::from("bar"));
let mut buf = vec![0u8; 6];
let copied = read_from_bufq(&mut q, &mut buf[..]);
assert_eq!(copied, 6);
assert_eq!(buf, b"foobar");
}
#[test]
fn partial() {
let mut q = VecDeque::new();
q.push_back(Bytes::from("foo"));
q.push_back(Bytes::from("bar"));
let mut buf = vec![0u8; 4];
let copied = read_from_bufq(&mut q, &mut buf[..]);
assert_eq!(copied, 4);
assert_eq!(buf, b"foob");
let copied = read_from_bufq(&mut q, &mut buf[..]);
assert_eq!(copied, 2);
assert_eq!(&buf[..copied], b"ar");
}
#[test]
fn q_order() {
let mut q = VecDeque::new();
q.push_back(Bytes::from("foo"));
q.push_back(Bytes::from("bar"));
q.push_back(Bytes::from("baz"));
let mut buf = vec![0u8; 2];
let copied = read_from_bufq(&mut q, &mut buf[..]);
assert_eq!(copied, 2);
assert_eq!(buf, b"fo");
let copied = read_from_bufq(&mut q, &mut buf[..]);
assert_eq!(copied, 2);
assert_eq!(buf, b"ob");
let copied = read_from_bufq(&mut q, &mut buf[..]);
assert_eq!(copied, 2);
assert_eq!(buf, b"ar");
let copied = read_from_bufq(&mut q, &mut buf[..]);
assert_eq!(copied, 2);
assert_eq!(buf, b"ba");
let copied = read_from_bufq(&mut q, &mut buf[..]);
assert_eq!(copied, 1);
assert_eq!(&buf[..copied], b"z");
}
}
#[cfg(test)]
mod readbuf_from_bufq_tests {
use super::{Bytes, ReadBuf, VecDeque, readbuf_from_bufq};
use std::mem::MaybeUninit;
#[test]
fn empty() {
let mut q = VecDeque::new();
let mut ubuf: [MaybeUninit<u8>; 4] = [MaybeUninit::uninit(); 4];
let mut buf = ReadBuf::uninit(&mut ubuf);
readbuf_from_bufq(&mut q, &mut buf);
assert_eq!(buf.initialized(), &[]);
assert_eq!(buf.filled(), &[]);
}
#[test]
fn exact_fit() {
let mut q = VecDeque::new();
q.push_back(Bytes::from("foo"));
q.push_back(Bytes::from("bar"));
let mut ubuf: [MaybeUninit<u8>; 6] = [MaybeUninit::uninit(); 6];
let mut buf = ReadBuf::uninit(&mut ubuf);
readbuf_from_bufq(&mut q, &mut buf);
assert_eq!(buf.initialized(), b"foobar");
assert_eq!(buf.filled(), b"foobar");
}
#[test]
fn partial() {
let mut q = VecDeque::new();
q.push_back(Bytes::from("foo"));
q.push_back(Bytes::from("bar"));
let mut ubuf: [MaybeUninit<u8>; 4] = [MaybeUninit::uninit(); 4];
let mut buf = ReadBuf::uninit(&mut ubuf);
readbuf_from_bufq(&mut q, &mut buf);
assert_eq!(buf.filled(), b"foob");
buf.clear();
readbuf_from_bufq(&mut q, &mut buf);
assert_eq!(buf.filled(), b"ar");
}
#[test]
fn q_order() {
let mut q = VecDeque::new();
q.push_back(Bytes::from("foo"));
q.push_back(Bytes::from("bar"));
q.push_back(Bytes::from("baz"));
let mut ubuf: [MaybeUninit<u8>; 2] = [MaybeUninit::uninit(); 2];
let mut buf = ReadBuf::uninit(&mut ubuf);
readbuf_from_bufq(&mut q, &mut buf);
assert_eq!(buf.filled(), b"fo");
buf.clear();
readbuf_from_bufq(&mut q, &mut buf);
assert_eq!(buf.filled(), b"ob");
buf.clear();
readbuf_from_bufq(&mut q, &mut buf);
assert_eq!(buf.filled(), b"ar");
buf.clear();
readbuf_from_bufq(&mut q, &mut buf);
assert_eq!(buf.filled(), b"ba");
buf.clear();
readbuf_from_bufq(&mut q, &mut buf);
assert_eq!(buf.filled(), b"z");
}
}