dir_structure/
try_parse.rs

1//! A wrapper that tries to parse a value of type `T`, keeping the original error if it fails.
2//!
3//! See [`TryParse`] for more details.
4
5#[cfg(feature = "async")]
6use std::future;
7#[cfg(feature = "async")]
8use std::future::poll_fn;
9use std::pin::Pin;
10#[cfg(feature = "async")]
11use std::task::Poll;
12#[cfg(feature = "async")]
13use std::task::ready;
14
15use crate::error::Error;
16use crate::error::VfsResult;
17use crate::prelude::*;
18#[cfg(feature = "async")]
19use crate::traits::async_vfs::VfsAsync;
20#[cfg(feature = "async")]
21use crate::traits::async_vfs::WriteSupportingVfsAsync;
22use crate::traits::vfs;
23use crate::traits::vfs::PathType;
24
25/// A type that tries to parse a value of type `T`, but doesn't fail if it can't.
26///
27/// Instead, it keeps the original [`Error`].
28pub enum TryParse<T, P: PathType + ?Sized> {
29    /// Successfully parsed a value of type `T`.
30    Success(T),
31
32    /// Failed to parse a value of type `T`.
33    Failure(Error<P::OwnedPath>),
34}
35
36impl<'vfs, Vfs, T, P> ReadFrom<'vfs, Vfs> for TryParse<T, P>
37where
38    Vfs: vfs::Vfs<'vfs, Path = P>,
39    P: PathType + ?Sized + 'vfs,
40    T: ReadFrom<'vfs, Vfs>,
41{
42    fn read_from(path: &Vfs::Path, vfs: Pin<&'vfs Vfs>) -> VfsResult<Self, Vfs> {
43        match T::read_from(path, vfs) {
44            Ok(value) => Ok(TryParse::Success(value)),
45            Err(error) => Ok(TryParse::Failure(error)),
46        }
47    }
48}
49
50impl<'vfs, Vfs, T, P> WriteTo<'vfs, Vfs> for TryParse<T, P>
51where
52    P: PathType + ?Sized + 'vfs,
53    Vfs: vfs::WriteSupportingVfs<'vfs, Path = P>,
54    T: WriteTo<'vfs, Vfs>,
55{
56    fn write_to(&self, path: &Vfs::Path, vfs: Pin<&'vfs Vfs>) -> VfsResult<(), Vfs> {
57        match self {
58            Self::Success(value) => value.write_to(path, vfs),
59            Self::Failure(_error) => Ok(()),
60        }
61    }
62}
63
64#[cfg(feature = "async")]
65#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
66impl<'vfs, Vfs, T, P> ReadFromAsync<'vfs, Vfs> for TryParse<T, P>
67where
68    P: PathType + 'vfs,
69    Vfs: VfsAsync<Path = P> + 'vfs,
70    T: ReadFromAsync<'vfs, Vfs> + Send + 'vfs,
71{
72    type Future = Pin<Box<dyn Future<Output = VfsResult<Self, Vfs>> + Send + 'vfs>>;
73
74    fn read_from_async(path: P::OwnedPath, vfs: Pin<&'vfs Vfs>) -> Self::Future {
75        let mut read_fut = Box::pin(T::read_from_async(path, vfs));
76        Box::pin(poll_fn(move |cx| {
77            let result = ready!(read_fut.as_mut().poll(cx));
78            match result {
79                Ok(value) => Poll::Ready(Ok(TryParse::Success(value))),
80                Err(error) => Poll::Ready(Ok(TryParse::Failure(error))),
81            }
82        }))
83    }
84}
85
86#[cfg(feature = "async")]
87#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
88impl<'vfs, Vfs, T, P> WriteToAsync<'vfs, Vfs> for TryParse<T, P>
89where
90    P: PathType + ?Sized + 'vfs,
91    Vfs: WriteSupportingVfsAsync<Path = P> + 'vfs,
92    T: WriteToAsync<'vfs, Vfs> + Send + 'vfs,
93    <T as WriteToAsync<'vfs, Vfs>>::Future: Future<Output = VfsResult<(), Vfs>> + Unpin,
94{
95    type Future = Pin<Box<dyn Future<Output = VfsResult<(), Vfs>> + Send + 'vfs>>;
96
97    fn write_to_async(self, path: P::OwnedPath, vfs: Pin<&'vfs Vfs>) -> Self::Future {
98        match self {
99            Self::Success(value) => Box::pin(value.write_to_async(path, vfs)),
100            Self::Failure(_error) => Box::pin(future::ready(Ok(()))),
101        }
102    }
103}
104
105#[cfg(feature = "async")]
106#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
107impl<'vfs, Vfs, T, P> WriteToAsyncRef<'vfs, Vfs> for TryParse<T, P>
108where
109    P: PathType + ?Sized + 'vfs,
110    Vfs: WriteSupportingVfsAsync<Path = P> + 'static,
111    T: WriteToAsyncRef<'vfs, Vfs> + Send + 'vfs,
112    for<'a> <T as WriteToAsyncRef<'vfs, Vfs>>::Future<'a>:
113        Future<Output = VfsResult<(), Vfs>> + Send + Sync + Unpin + 'a,
114{
115    type Future<'a>
116        = Pin<Box<dyn Future<Output = VfsResult<(), Vfs>> + Send + Sync + 'a>>
117    where
118        Self: 'a,
119        'vfs: 'a,
120        T: 'a,
121        Vfs: 'a;
122
123    fn write_to_async_ref<'a>(&'a self, path: P::OwnedPath, vfs: Pin<&'a Vfs>) -> Self::Future<'a>
124    where
125        'vfs: 'a,
126    {
127        use std::future::poll_fn;
128
129        let mut wr: Option<Pin<Box<<T as WriteToAsyncRef<'vfs, Vfs>>::Future<'a>>>> = match self {
130            Self::Success(value) => Some(Box::pin(value.write_to_async_ref(path, vfs))),
131            Self::Failure(_error) => None,
132        };
133
134        Box::pin(poll_fn(move |cx| match &mut wr {
135            Some(wr) => wr.as_mut().poll(cx),
136            None => Poll::Ready(Ok(())),
137        }))
138    }
139}