use core::future::poll_fn;
use core::task::Poll;
use std::fs::File as StdFile;
use std::io;
use std::sync::Arc;
use super::FileIo;
use super::work::{Work, tally_read};
use crate::buf::owned::{IoBufMut, OwnedBuf};
use crate::io::Handle;
use crate::io::source::Failure;
pub(crate) const MANY_AT_ONCE: usize = 64;
type End = (io::Result<usize>, OwnedBuf);
impl FileIo {
pub(crate) async fn read_many_at<B>(
self: &Arc<Self>,
reads: Vec<(B, u64)>,
) -> Vec<(io::Result<usize>, B)>
where
B: IoBufMut,
{
poll_fn(|cx| self.poll_ordered(cx)).await;
let mut ends: Vec<Option<End>> = (0..reads.len()).map(|_| None).collect();
let mut waiting = reads.into_iter().enumerate();
let mut out: Vec<(usize, Work<End>)> = Vec::with_capacity(MANY_AT_ONCE.min(ends.len()));
poll_fn(|cx| {
loop {
while out.len() < MANY_AT_ONCE {
let Some((i, (buf, at))) = waiting.next() else {
break;
};
let buf = OwnedBuf::filled(buf);
if buf.len() == buf.capacity() {
ends[i] = Some((Ok(0), buf));
continue;
}
out.push((i, self.submit_read_owned(&mut Some(buf), at, cx.waker())));
}
let before = out.len();
out.retain_mut(|(i, work)| match (work.pooled(), work.poll(cx.waker())) {
(pooled, Poll::Ready(end)) => {
tally_read(pooled, &end.0, |n| *n);
ends[*i] = Some(end);
false
}
(_, Poll::Pending) => true,
});
if out.is_empty() && waiting.len() == 0 {
return Poll::Ready(());
}
if out.len() == before {
return Poll::Pending;
}
}
})
.await;
ends.into_iter()
.map(|end| {
let (result, buf) = end.unwrap_or_else(|| {
(
Err(io::Error::other("the read lost its buffer")),
OwnedBuf::default(),
)
});
(result, buf.into_filled())
})
.collect()
}
}
impl Handle<StdFile> {
pub async fn read_many_at<B>(&self, reads: Vec<(B, u64)>) -> Vec<(io::Result<usize>, B)>
where
B: IoBufMut,
{
match self.file() {
Ok(file) => file.read_many_at(reads).await,
Err(err) => {
let failure = Failure::of(&err);
reads
.into_iter()
.map(|(buf, _)| (Err(failure.error()), buf))
.collect()
}
}
}
}