pipe_chain/pipe/
error.rs

1use crate::Pipe;
2use fatal_error::FatalError;
3use std::error::Error as StdError;
4
5/// Changes error behaviour
6pub trait ErrExt<I, O, E, R> {
7    /// Makes non fatal errors fatal
8    fn escalate(self) -> Escalate<Self>
9    where
10        Self: Sized,
11    {
12        Escalate(self)
13    }
14
15    /// makes fatal errors non fatal
16    fn deescalate(self) -> Deescalate<Self>
17    where
18        Self: Sized,
19    {
20        Deescalate(self)
21    }
22}
23
24impl<I, O, E, R, P> ErrExt<I, O, E, R> for P where P: Pipe<I, O, E, R> {}
25
26/// [ErrExt::escalate] implementation
27pub struct Escalate<P>(P);
28
29impl<I, O, E, R, P: Pipe<I, O, E, R>> Pipe<I, O, E, R> for Escalate<P> {
30    fn apply(&mut self, input: I) -> crate::Result<R, O, E> {
31        self.0.apply(input).map_err(|x| x.escalate())
32    }
33}
34
35/// [ErrExt::deescalate] implementation
36pub struct Deescalate<P>(P);
37
38impl<I, O, E, R, P: Pipe<I, O, E, R>> Pipe<I, O, E, R> for Deescalate<P> {
39    fn apply(&mut self, input: I) -> crate::Result<R, O, E> {
40        self.0.apply(input).map_err(|x| x.deescalate())
41    }
42}
43
44/// Incomplete error
45///
46/// This error is returned when a pipe needs more input items
47#[derive(Debug, Clone, Copy, PartialEq, Eq)]
48pub enum Incomplete {
49    /// an unknown number of items is needed
50    Unknown,
51    /// a minimum of items is needed
52    Size(usize),
53}
54
55impl std::fmt::Display for Incomplete {
56    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
57        match self {
58            Incomplete::Unknown => write!(f, "more bytes needed"),
59            Incomplete::Size(x) => write!(f, "at least {x} more bytes are needed"),
60        }
61    }
62}
63
64impl StdError for Incomplete {}
65
66/// creates a pipe that always return an error
67/// ```
68/// # use pipe_chain::{error, tag, str::{TagStrError, digits}, OrExt, Pipe, Incomplete, EitherExt};
69/// # use fatal_error::FatalError;
70/// #[derive(Debug, PartialEq)]
71/// enum Error {
72///     Tag(TagStrError),
73///     Incomplete(Incomplete),
74///     Other
75/// }
76///
77/// impl From<TagStrError> for Error { fn from(e: TagStrError) -> Error { Error::Tag(e)} }
78///
79/// impl From<Incomplete> for Error { fn from(e: Incomplete) -> Error { Error::Incomplete(e) } }
80///
81/// impl std::error::Error for Error {}
82///
83/// impl std::fmt::Display for Error {
84///    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
85///         write!(f, "{self:?}")
86///     }
87/// }
88///
89///
90/// assert_eq!(tag::<Error, _, _>("a").or(error(|| FatalError::Fatal(Error::Other))).apply("b"), Err(FatalError::Fatal(Error::Other)));
91/// ```
92pub fn error<I, O, E, R, F>(mut f: F) -> impl Pipe<I, O, E, R>
93where
94    F: FnMut() -> FatalError<E>,
95{
96    move |_| Err(f())
97}