use std::{
pin::Pin,
task::{Context, Poll},
};
use async_std::{fs::File, io::{prelude::SeekExt, Cursor, ReadExt}, path::PathBuf};
use futures::{future::BoxFuture, FutureExt, Stream, TryStreamExt};
use crate::repr::Wad;
use super::{arc_vec::ArcVec, IoError, TextureStream};
pub trait WadSource: ReadExt + SeekExt {}
impl<T> WadSource for T where T: ReadExt + SeekExt {}
impl Wad {
pub async fn from_stream(textures: impl TextureStream) -> Result<Wad, IoError> {
textures
.try_fold(Wad::default(), |mut acc, (name, texture)| async move {
acc.insert(name, texture);
Ok(acc)
})
.await
}
}
#[cfg(doc)]
use futures::TryStream;
pub trait WadSourceStream<W>:
futures::TryStream<Item = Result<W, IoError>, Ok = W, Error = IoError> + Unpin
where
W: WadSource,
{
}
impl<W, T> WadSourceStream<W> for T
where
T: futures::TryStream<Item = Result<W, IoError>, Ok = W, Error = IoError> + Unpin,
W: WadSource,
{
}
pub struct SourceStreamSlice<'a>(&'a [u8]);
impl<'a> From<&'a [u8]> for SourceStreamSlice<'a> {
fn from(slice: &'a [u8]) -> Self {
SourceStreamSlice(slice)
}
}
impl<'a> Stream for SourceStreamSlice<'a> {
type Item = Result<Cursor<&'a [u8]>, IoError>;
fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Poll::Ready(Some(Ok(Cursor::new(self.0))))
}
}
pub struct SourceStreamVec(ArcVec<u8>);
impl From<Vec<u8>> for SourceStreamVec {
fn from(vec: Vec<u8>) -> Self {
SourceStreamVec(ArcVec::new(vec))
}
}
impl Stream for SourceStreamVec {
type Item = Result<Cursor<ArcVec<u8>>, IoError>;
fn poll_next(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll<Option<Self::Item>> {
Poll::Ready(Some(Ok(Cursor::new(self.0.clone()))))
}
}
pub struct SourceStreamFile {
path: PathBuf,
file_fut: BoxFuture<'static, Result<File, IoError>>,
}
impl From<PathBuf> for SourceStreamFile {
fn from(path: PathBuf) -> Self {
let file_fut = File::open(path.clone()).boxed();
SourceStreamFile { path, file_fut }
}
}
impl Stream for SourceStreamFile {
type Item = Result<File, IoError>;
fn poll_next(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
let self_mut = self.get_mut();
match self_mut.file_fut.poll_unpin(cx) {
Poll::Ready(result) => {
self_mut.file_fut = File::open(self_mut.path.clone()).boxed();
Poll::Ready(Some(result))
}
Poll::Pending => Poll::Pending,
}
}
}