Skip to main content

other_error/
either.rs

1
2use either::Either;
3use core::error::Error;
4use core::fmt::{Debug, Display};
5use core::ops::Deref;
6
7/// Error that is one of two possible error types.
8pub struct EitherError<L, R> {
9    inner: Either<L, R>,
10}
11
12impl<L, R> AsRef<Either<L, R>> for EitherError<L, R> {
13    fn as_ref(&self) -> &Either<L, R> {
14        &self.inner
15    }
16}
17
18impl<L, R> Deref for EitherError<L, R> {
19    type Target = Either<L, R>;
20    fn deref(&self) -> &Self::Target {
21        &self.inner
22    }   
23}
24
25impl<L, R> From<Either<L, R>> for EitherError<L, R> {
26    fn from(inner: Either<L, R>) -> Self {
27        Self::new(inner)
28    }
29}
30
31impl<L, R> PartialEq for EitherError<L, R> where L: PartialEq, R: PartialEq {
32    fn eq(&self, other: &Self) -> bool {
33        self.inner == other.inner
34    }
35}
36
37impl<L, R> Eq for EitherError<L, R> where L: Eq, R: Eq {}
38
39impl<L, R> EitherError<L, R> {
40    pub fn new(inner: Either<L, R>) -> Self {
41        Self { inner }
42    }
43    
44    pub fn into_inner(self) -> Either<L, R> {
45        self.inner
46    }
47}
48
49impl<L: Debug, R: Debug> Debug for EitherError<L, R> {
50    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
51        match &self.inner {
52            Either::Left(err) => err.fmt(f),
53            Either::Right(err) => err.fmt(f),
54        }
55    }
56}
57
58impl<L: Display, R: Display> Display for EitherError<L, R> {
59    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
60        match &self.inner {
61            Either::Left(err) => err.fmt(f),
62            Either::Right(err) => err.fmt(f),
63        }
64    }
65}
66
67impl<L, R> Error for EitherError<L, R> where L: Error, R: Error {
68    fn source(&self) -> Option<&(dyn Error + 'static)> {
69        match &self.inner {
70            Either::Left(err) => err.source(),
71            Either::Right(err) => err.source(),
72        }
73    }
74}
75
76#[cfg(all(test, feature = "alloc"))]
77mod tests {
78    extern crate alloc;
79    use super::*;
80    use alloc::format;
81
82    #[derive(Debug)]
83    struct LeftErr;
84    #[derive(Debug)]
85    struct RightErr;
86
87    impl Display for LeftErr {
88        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
89            f.write_str("left")
90        }
91    }
92
93    impl Display for RightErr {
94        fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
95            f.write_str("right")
96        }
97    }
98
99    #[test]
100    fn left_formats_left() {
101        let err: EitherError<LeftErr, RightErr> = Either::Left(LeftErr).into();
102        assert_eq!(format!("{}", err), "left");
103        assert_eq!(format!("{:?}", err), "LeftErr");
104    }
105
106    #[test]
107    fn right_formats_right() {
108        let err: EitherError<LeftErr, RightErr> = Either::Right(RightErr).into();
109        assert_eq!(format!("{}", err), "right");
110        assert_eq!(format!("{:?}", err), "RightErr");
111    }
112
113    #[test]
114    fn into_inner_round_trips() {
115        let err = EitherError::<LeftErr, RightErr>::new(Either::Left(LeftErr));
116        assert!(matches!(err.into_inner(), Either::Left(LeftErr)));
117    }
118}