use std::{io::IoSlice, ops::Deref};
use bytes::Bytes;
use tokio_io_utility::IoSliceExt;
fn take_slices<T: Deref<Target = [u8]>>(
bufs: &'_ [T],
limit: usize,
create_slice: impl FnOnce(&T, usize) -> T,
) -> Option<(usize, &'_ [T], [T; 1])> {
if bufs.is_empty() {
return None;
}
let mut end = 0;
let mut n = 0;
for buf in bufs {
let cnt = n + buf.len();
if cnt > limit {
break;
}
n = cnt;
end += 1;
}
let buf = if end < bufs.len() {
let res = [create_slice(&bufs[end], limit - n)];
n = limit;
res
} else {
if n == 0 {
return None;
}
[create_slice(&bufs[0], 0)]
};
Some((n, &bufs[..end], buf))
}
pub(super) fn take_io_slices<'a>(
io_slices: &'a [IoSlice<'a>],
limit: usize,
) -> Option<(usize, &'a [IoSlice<'a>], [IoSlice<'a>; 1])> {
take_slices(io_slices, limit, |io_slice, end| {
IoSlice::new(&io_slice.into_inner()[..end])
})
}
pub(super) fn take_bytes(
bytes_slice: &[Bytes],
limit: usize,
) -> Option<(usize, &[Bytes], [Bytes; 1])> {
take_slices(bytes_slice, limit, |bytes, end| bytes.slice(0..end))
}
#[cfg(test)]
mod tests {
use super::{take_io_slices, IoSlice};
use pretty_assertions::assert_eq;
#[test]
fn test_take_io_slices() {
let limit = 200;
let content = b"HELLO, WORLD!\n".repeat(limit / 8);
let len = content.len();
assert!(len / 2 < limit);
let io_slices = [
IoSlice::new(&content[..len / 2]),
IoSlice::new(&content[len / 2..]),
];
let (n, io_subslices, reminder) = take_io_slices(&io_slices, limit).unwrap();
assert_eq!(n, limit);
assert_eq!(io_subslices.len(), 1);
assert_eq!(&*io_subslices[0], &*io_slices[0]);
assert_eq!(&*reminder[0], &io_slices[1][..(limit - len / 2)]);
}
}