use super::Body;
use std::{
io::{self, Cursor, Read},
pin::Pin,
task::{Context, Poll},
};
#[derive(Debug)]
pub(crate) struct TestBody {
chunks: Cursor<Vec<Cursor<Vec<u8>>>>,
}
impl TestBody {
pub fn new<C>(chunks: C) -> Self
where
C: IntoIterator,
C::Item: IntoIterator<Item = u8>,
{
Self {
chunks: Cursor::new(
chunks
.into_iter()
.map(|chunk| Cursor::new(chunk.into_iter().collect()))
.collect(),
),
}
}
fn increment_chunks_position(&mut self) {
let next_position = self.chunks.position() + 1;
self.chunks.set_position(next_position);
}
}
impl From<&'_ Vec<Vec<u8>>> for TestBody {
fn from(chunks: &'_ Vec<Vec<u8>>) -> Self {
Self::new(chunks.iter().map(|chunk| chunk.iter().copied()))
}
}
impl Body for TestBody {
fn poll_chunk(
mut self: Pin<&mut Self>,
_cx: &mut Context<'_>,
buf: &mut [u8],
) -> Poll<io::Result<usize>> {
let chunk_pos = usize_position(&self.chunks);
let chunk = match self.chunks.get_mut().get_mut(chunk_pos) {
Some(x) => x,
None => return Poll::Ready(Ok(0)),
};
let read_amount = chunk.read(buf)?;
if read_amount == 0 {
self.increment_chunks_position();
Poll::Ready(Ok(0))
} else {
Poll::Ready(Ok(read_amount))
}
}
fn poll_chunk_size_hint(
self: Pin<&mut Self>,
_cx: &mut Context<'_>,
) -> Poll<io::Result<(usize, Option<usize>)>> {
let chunk_pos = usize_position(&self.chunks);
let size = self.chunks.get_ref().get(chunk_pos).map_or(0, chunk_size);
Poll::Ready(Ok(exact_size_hint(size)))
}
fn size_hint(&self) -> (usize, Option<usize>) {
let chunk_pos = usize_position(&self.chunks);
let chunks = &self.chunks.get_ref()[chunk_pos..];
let size = chunks.iter().map(chunk_size).sum();
exact_size_hint(size)
}
}
fn usize_position<T>(cursor: &Cursor<T>) -> usize {
usize_from(cursor.position())
}
fn usize_from(x: u64) -> usize {
x.try_into().unwrap()
}
fn chunk_size(chunk: &Cursor<Vec<u8>>) -> usize {
chunk.get_ref().len() - usize_position(chunk)
}
fn exact_size_hint(size: usize) -> (usize, Option<usize>) {
(size, Some(size))
}