1use crate::{Pipe, Result};
2use fatal_error::FatalError;
3use std::{fmt::Debug, marker::PhantomData};
4
5pub trait NotExt<I, O, E, R> {
7 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
20pub 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
29pub enum NotError<T, E> {
30 Not(T),
32 Fatal(E),
34}
35
36impl<T, E> NotError<T, E> {
37 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}