pipe_chain/pipe/
not.rs

1use crate::{Pipe, Result};
2use fatal_error::FatalError;
3use std::{fmt::Debug, marker::PhantomData};
4
5/// Changes error behaviour
6pub trait NotExt<I, O, E, R> {
7    /// Fails if the given pipe succeeds
8    fn not(self) -> Not<O, R, Self>
9    where
10        I: Clone,
11        O: Debug,
12        Self: Sized,
13    {
14        Not::new(self)
15    }
16}
17
18impl<I, O, E, R, P> NotExt<I, O, E, R> for P where P: Pipe<I, O, E, R> {}
19
20/// [NotExt::not] implementation
21pub struct Not<O, R, P>(P, PhantomData<O>, PhantomData<R>);
22
23impl<O, R, P> Not<O, R, P> {
24    fn new(p: P) -> Self { Not(p, PhantomData, PhantomData) }
25}
26
27/// A pipe that should have failed succeed
28#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum NotError<T, E> {
30    /// The error succeeded
31    Not(T),
32    /// A fatal error occured
33    Fatal(E),
34}
35
36impl<T, E> NotError<T, E> {
37    /// unwrap the successfull result
38    /// panics if `self` is [NotError::Fatal]
39    pub fn unwrap_not(self) -> T
40    where
41        E: Debug,
42    {
43        match self {
44            NotError::Not(x) => x,
45            NotError::Fatal(x) => panic!("not error encountered a fatal error: {x:?}"),
46        }
47    }
48}
49
50impl<T: std::fmt::Debug, E: std::fmt::Display> std::fmt::Display for NotError<T, E> {
51    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52        match self {
53            NotError::Not(x) => write!(f, "Not pipe succeeded: {x:?}"),
54            NotError::Fatal(x) => write!(f, "Not pipe encountered a fatal error: '{x}'"),
55        }
56    }
57}
58
59impl<O: std::fmt::Debug, E: std::error::Error> std::error::Error for NotError<O, E> {}
60
61impl<I, O, E, R, P> Pipe<I, (E,), NotError<(R, O), E>> for Not<O, R, P>
62where
63    I: Clone,
64    P: Pipe<I, O, E, R>,
65{
66    fn apply(&mut self, input: I) -> Result<I, (E,), NotError<(R, O), E>> {
67        match self.0.apply(input.clone()) {
68            Ok(x) => Err(FatalError::Error(NotError::Not(x))),
69            Err(x) if x.is_fatal() => Err(x.map(NotError::Fatal)),
70            Err(x) => Ok((input, (x.into_inner(),))),
71        }
72    }
73}