use pin_project::pin_project;
use std::{
future::Future,
io::{Cursor, Result},
pin::Pin,
task::Poll,
};
use tokio::io::{AsyncRead, AsyncSeek};
use crate::entry_data::EntryData;
#[derive(Clone, Debug)]
#[pin_project]
pub struct Zeros {
size: u64,
remaining: u64,
}
impl Zeros {
pub fn new(size: u64) -> Self {
Zeros {
size,
remaining: size,
}
}
}
impl AsyncRead for Zeros {
fn poll_read(
self: Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
buf: &mut tokio::io::ReadBuf<'_>,
) -> Poll<std::io::Result<()>> {
if self.remaining > 0 {
let n = self.remaining.min(buf.remaining() as u64);
let n_usize = usize::try_from(n).expect("n is lower than buf.remaining()");
buf.initialize_unfilled_to(n_usize).fill(0);
buf.advance(n_usize);
*self.project().remaining -= n;
}
Poll::Ready(Ok(()))
}
}
impl AsyncSeek for Zeros {
fn start_seek(self: Pin<&mut Self>, position: std::io::SeekFrom) -> std::io::Result<()> {
match position {
std::io::SeekFrom::Start(pos) => *self.project().remaining = self.size - pos,
std::io::SeekFrom::End(_) => unimplemented!(),
std::io::SeekFrom::Current(_) => unimplemented!(),
}
Ok(())
}
fn poll_complete(
self: Pin<&mut Self>,
_cx: &mut std::task::Context<'_>,
) -> Poll<std::io::Result<u64>> {
Poll::Ready(Ok(self.size - self.remaining))
}
}
impl EntryData for Zeros {
type Reader = Self;
type Future = std::future::Ready<Result<Self>>;
fn get_reader(&self) -> Self::Future {
std::future::ready(Ok(self.clone()))
}
fn size(&self) -> u64 {
self.size
}
}
#[pin_project]
pub struct LazyReader<'a> {
#[pin]
inner: Cursor<&'a [u8]>,
delay: bool,
}
impl<'a> From<&'a [u8]> for LazyReader<'a> {
fn from(value: &'a [u8]) -> Self {
LazyReader {
inner: Cursor::new(value),
delay: true,
}
}
}
impl AsyncRead for LazyReader<'_> {
fn poll_read(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
buf: &mut tokio::io::ReadBuf<'_>,
) -> Poll<std::io::Result<()>> {
let projected = self.project();
*projected.delay = !*projected.delay;
if *projected.delay {
projected.inner.poll_read(cx, buf)
} else {
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
impl AsyncSeek for LazyReader<'_> {
fn start_seek(self: Pin<&mut Self>, position: std::io::SeekFrom) -> std::io::Result<()> {
self.project().inner.start_seek(position)
}
fn poll_complete(
self: Pin<&mut Self>,
cx: &mut std::task::Context<'_>,
) -> Poll<std::io::Result<u64>> {
let projected = self.project();
*projected.delay = !*projected.delay;
if *projected.delay {
projected.inner.poll_complete(cx)
} else {
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
pub struct LazyReaderFuture<'a> {
data: &'a [u8],
delay: bool,
}
impl<'a> Future for LazyReaderFuture<'a> {
type Output = std::io::Result<LazyReader<'a>>;
fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
self.delay = !self.delay;
if self.delay {
Poll::Ready(Result::Ok(LazyReader {
inner: Cursor::new(self.data),
delay: true,
}))
} else {
cx.waker().wake_by_ref();
Poll::Pending
}
}
}
impl<'a> EntryData for LazyReader<'a> {
type Reader = LazyReader<'a>;
type Future = LazyReaderFuture<'a>;
fn get_reader(&self) -> Self::Future {
LazyReaderFuture {
data: self.inner.get_ref(),
delay: true,
}
}
fn size(&self) -> u64 {
self.inner.get_ref().len() as u64
}
}
pub struct BadSize {
pub reported_size: u64,
pub actual_size: u64,
}
impl EntryData for BadSize {
type Reader = Zeros;
type Future = std::future::Ready<Result<Self::Reader>>;
fn get_reader(&self) -> Self::Future {
std::future::ready(Ok(Zeros::new(self.actual_size)))
}
fn size(&self) -> u64 {
self.reported_size
}
}
pub struct EmptyUnsupportedReader();
impl EntryData for EmptyUnsupportedReader {
type Reader = std::io::Cursor<&'static [u8]>;
type Future = std::future::Ready<Result<Self::Reader>>;
fn get_reader(&self) -> Self::Future {
unimplemented!("This test struct doesn't support getting futures")
}
fn size(&self) -> u64 {
0
}
}