use std::pin::Pin;
#[cfg(feature = "async")]
use std::task::Context;
#[cfg(feature = "async")]
use std::task::Poll;
#[cfg(feature = "async")]
use pin_project::pin_project;
use crate::error::VfsResult;
use crate::prelude::*;
#[cfg(feature = "async")]
use crate::traits::async_vfs::VfsAsync;
#[cfg(feature = "async")]
use crate::traits::async_vfs::WriteSupportingVfsAsync;
#[cfg(feature = "resolve-path")]
use crate::traits::resolve::DynamicHasField;
#[cfg(feature = "resolve-path")]
use crate::traits::resolve::HAS_FIELD_MAX_LEN;
#[cfg(feature = "resolve-path")]
use crate::traits::resolve::HasField;
use crate::traits::vfs;
#[cfg(feature = "resolve-path")]
use crate::traits::vfs::OwnedPathType;
use crate::traits::vfs::PathType;
impl<'a, T, Vfs: vfs::Vfs<'a>> ReadFrom<'a, Vfs> for Option<T>
where
T: ReadFrom<'a, Vfs>,
{
fn read_from(path: &Vfs::Path, vfs: Pin<&'a Vfs>) -> VfsResult<Self, Vfs>
where
Self: Sized,
{
if vfs.exists(path)? {
T::read_from(path, vfs).map(Some)
} else {
Ok(None)
}
}
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
#[pin_project(project_replace = OptionReadFromAsyncFutureOwnProj)]
#[doc(hidden)]
pub enum OptionReadFromAsyncFuture<'a, T, P: PathType + ?Sized + 'a, Vfs: VfsAsync<Path = P> + 'a>
where
T: ReadFromAsync<'a, Vfs> + 'static,
Vfs::ExistsFuture<'a>: Future<Output = VfsResult<bool, Vfs>>,
T::Future: Future<Output = VfsResult<T, Vfs>> + Unpin,
{
Poison,
Check {
path: P::OwnedPath,
check_fut: Pin<Box<Vfs::ExistsFuture<'a>>>,
vfs: Pin<&'a Vfs>,
},
HasContents {
inner: T::Future,
vfs: Pin<&'a Vfs>,
},
NoContents,
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
impl<'a, T, Vfs: VfsAsync<Path = P> + 'a, P: PathType + ?Sized + 'a> Future
for OptionReadFromAsyncFuture<'a, T, P, Vfs>
where
T: ReadFromAsync<'a, Vfs> + 'static,
T::Future: Future<Output = VfsResult<T, Vfs>> + Unpin,
{
type Output = VfsResult<Option<T>, Vfs>;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
use std::task::Poll;
let this = self.as_mut().project_replace(Self::Poison);
match this {
OptionReadFromAsyncFutureOwnProj::Check {
path,
mut check_fut,
vfs,
} => {
match check_fut.as_mut().poll(cx) {
Poll::Ready(Ok(true)) => {
self.project_replace(Self::HasContents {
inner: T::read_from_async(path, vfs),
vfs,
});
cx.waker().wake_by_ref();
Poll::Pending
}
Poll::Ready(Ok(false)) => {
Poll::Ready(Ok(None))
}
Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
Poll::Pending => {
self.project_replace(Self::Check {
path,
check_fut,
vfs,
});
Poll::Pending
}
}
}
OptionReadFromAsyncFutureOwnProj::HasContents { mut inner, vfs } => {
match Pin::new(&mut inner).poll(cx) {
Poll::Ready(v) => Poll::Ready(v.map(Some)),
Poll::Pending => {
self.project_replace(Self::HasContents { inner, vfs });
Poll::Pending
}
}
}
OptionReadFromAsyncFutureOwnProj::NoContents => {
Poll::Ready(Ok(None))
}
OptionReadFromAsyncFutureOwnProj::Poison => {
panic!("OptionReadFromAsyncFuture was polled after it was replaced with Poison");
}
}
}
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
impl<'a, T, Vfs: VfsAsync<Path = P> + 'a, P: PathType + ?Sized + 'a> ReadFromAsync<'a, Vfs>
for Option<T>
where
T: ReadFromAsync<'a, Vfs> + 'static,
T::Future: Future<Output = VfsResult<T, Vfs>> + Unpin + 'a,
{
type Future
= OptionReadFromAsyncFuture<'a, T, P, Vfs>
where
Self: 'static;
fn read_from_async(path: P::OwnedPath, vfs: Pin<&'a Vfs>) -> Self::Future {
OptionReadFromAsyncFuture::Check {
check_fut: Box::pin(vfs.exists(path.clone())),
path,
vfs,
}
}
}
impl<'vfs, T, P: PathType + ?Sized + 'vfs, Vfs: vfs::WriteSupportingVfs<'vfs, Path = P>>
WriteTo<'vfs, Vfs> for Option<T>
where
T: WriteTo<'vfs, Vfs>,
{
fn write_to(&self, path: &P, vfs: Pin<&'vfs Vfs>) -> VfsResult<(), Vfs> {
if let Some(v) = self {
v.write_to(path, vfs)
} else {
Ok(())
}
}
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
#[pin_project(project = OptionWriteToAsyncFutureProj)]
#[doc(hidden)]
pub enum OptionWriteToAsyncFuture<'a, T, Vfs: WriteSupportingVfsAsync + 'a>
where
T: WriteToAsync<'a, Vfs> + 'static,
{
HasContents {
#[pin]
inner: <T as WriteToAsync<'a, Vfs>>::Future,
},
NoContents,
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
impl<'a, T, Vfs: WriteSupportingVfsAsync<Path = P>, P: PathType + ?Sized + 'a> Future
for OptionWriteToAsyncFuture<'a, T, Vfs>
where
T: WriteToAsync<'a, Vfs> + 'static,
{
type Output = VfsResult<(), Vfs>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let this = self.project();
match this {
OptionWriteToAsyncFutureProj::HasContents { inner } => inner.poll(cx),
OptionWriteToAsyncFutureProj::NoContents => Poll::Ready(Ok(())),
}
}
}
#[cfg(feature = "async")]
#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
impl<'a, T, Vfs: WriteSupportingVfsAsync + 'static> WriteToAsync<'a, Vfs> for Option<T>
where
T: WriteToAsync<'a, Vfs> + Send + 'static,
{
type Future = OptionWriteToAsyncFuture<'a, T, Vfs>;
fn write_to_async(
self,
path: <Vfs::Path as PathType>::OwnedPath,
vfs: Pin<&'a Vfs>,
) -> Self::Future {
if let Some(v) = self {
OptionWriteToAsyncFuture::HasContents {
inner: v.write_to_async(path, vfs),
}
} else {
OptionWriteToAsyncFuture::NoContents
}
}
}
#[cfg(feature = "resolve-path")]
#[cfg_attr(docsrs, doc(cfg(feature = "resolve-path")))]
impl<const NAME: [char; HAS_FIELD_MAX_LEN], T> HasField<NAME> for Option<T>
where
T: HasField<NAME>,
{
type Inner = <T as HasField<NAME>>::Inner;
fn resolve_path<P: OwnedPathType>(p: P) -> P {
T::resolve_path(p)
}
}
#[cfg(feature = "resolve-path")]
#[cfg_attr(docsrs, doc(cfg(feature = "resolve-path")))]
impl<T> DynamicHasField for Option<T>
where
T: DynamicHasField,
{
type Inner = <T as DynamicHasField>::Inner;
fn resolve_path<P: OwnedPathType>(p: P, name: &str) -> P {
T::resolve_path(p, name)
}
}