sophia_api/source/_stream_error.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
use std::error::Error;
/// A error that is raised by functions that move fallible `Source`s into
/// fallible `Sinks`.
///
/// In case this error is raised it can be matched to investigate if `Source`
/// or `Sink` failed.
///
/// # Conversion
///
/// Both variants `SourceError` and `SinkError` are public exported.
/// Consequently, `StreamError` can be constructed with `.map_err(SourceError)`
/// and `.map_err(SinkError)`.
#[derive(Debug, thiserror::Error)]
pub enum StreamError<SourceErr, SinkErr>
where
SourceErr: Error,
SinkErr: Error,
{
/// Error caused by the source
#[error("Source failed: {0}")]
SourceError(#[source] SourceErr),
/// Error caused by the sink
#[error("Sink failed: {0}")]
SinkError(#[source] SinkErr),
}
pub use StreamError::*;
impl<SourceErr, SinkErr> StreamError<SourceErr, SinkErr>
where
SourceErr: Error,
SinkErr: Error,
{
/// Checks if `StreamError` was raised by the `Source`.
pub fn is_source_error(&self) -> bool {
matches!(self, SourceError(_))
}
/// Checks if `StreamError` was raised by the `Sink`.
pub fn is_sink_error(&self) -> bool {
matches!(self, SinkError(_))
}
/// Converts `StreamError` into an inner error.
pub fn inner_into<Err>(self) -> Err
where
SourceErr: Error + Into<Err>,
SinkErr: Error + Into<Err>,
{
match self {
SourceError(err) => err.into(),
SinkError(err) => err.into(),
}
}
/// Convert using `f` if a `SourceError`
pub fn map_source<E, F>(self, f: F) -> StreamError<E, SinkErr>
where
E: Error,
F: FnOnce(SourceErr) -> E,
{
match self {
SourceError(e) => SourceError(f(e)),
SinkError(e) => SinkError(e),
}
}
/// Convert using `f` if a `SinkError`
pub fn map_sink<E, F>(self, f: F) -> StreamError<SourceErr, E>
where
E: Error,
F: FnOnce(SinkErr) -> E,
{
match self {
SourceError(e) => SourceError(e),
SinkError(e) => SinkError(f(e)),
}
}
/// Unwrap as the inner SourceError.
///
/// # Panic
/// Panic if self is actually a SinkError.
pub fn unwrap_source_error(self) -> SourceErr {
match self {
SourceError(err) => err,
SinkError(_) => panic!("this is a SinkError"),
}
}
/// Unwrap as the inner SinkError.
///
/// # Panic
/// Panic if self is actually a SourceError.
pub fn unwrap_sink_error(self) -> SinkErr {
match self {
SourceError(_) => panic!("this is a SourceError"),
SinkError(err) => err,
}
}
/// Switch source and sink error.
pub fn reverse(self) -> StreamError<SinkErr, SourceErr> {
match self {
SourceError(e) => SinkError(e),
SinkError(e) => SourceError(e),
}
}
}
/// Convenient type alias for [`Result`] whose error is [`StreamError`].
pub type StreamResult<T, E1, E2> = Result<T, StreamError<E1, E2>>;
/// Additional methods for [`StreamResult`]
pub trait StreamResultExt<T, E1, E2>
where
E1: Error,
E2: Error,
{
/// Map the error if it is a [`SourceError`]
fn map_source_err<E, F>(self, f: F) -> StreamResult<T, E, E2>
where
E: Error,
F: FnOnce(E1) -> E;
/// Map the error if it is a [`SinkError`]
fn map_sink_err<E, F>(self, f: F) -> StreamResult<T, E1, E>
where
E: Error,
F: FnOnce(E2) -> E;
}
impl<T, E1, E2> StreamResultExt<T, E1, E2> for StreamResult<T, E1, E2>
where
E1: Error,
E2: Error,
{
fn map_source_err<E, F>(self, f: F) -> StreamResult<T, E, E2>
where
E: Error,
F: FnOnce(E1) -> E,
{
self.map_err(|err| err.map_source(f))
}
fn map_sink_err<E, F>(self, f: F) -> StreamResult<T, E1, E>
where
E: Error,
F: FnOnce(E2) -> E,
{
self.map_err(|err| err.map_sink(f))
}
}