use std::fmt;
#[derive(Debug)]
pub enum StreamError<D> {
Database(D),
Deserialize(String)
}
impl<D> StreamError<D> {
pub const fn is_database(&self) -> bool {
matches!(self, Self::Database(_))
}
pub const fn is_deserialize(&self) -> bool {
matches!(self, Self::Deserialize(_))
}
}
impl<D: fmt::Display> fmt::Display for StreamError<D> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Database(e) => write!(f, "database error: {}", e),
Self::Deserialize(e) => write!(f, "deserialize error: {}", e)
}
}
}
impl<D: std::error::Error + 'static> std::error::Error for StreamError<D> {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Database(e) => Some(e),
Self::Deserialize(_) => None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Debug)]
struct TestError(&'static str);
impl fmt::Display for TestError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl std::error::Error for TestError {}
#[test]
fn stream_error_is_database() {
let err: StreamError<TestError> = StreamError::Database(TestError("db"));
assert!(err.is_database());
assert!(!err.is_deserialize());
}
#[test]
fn stream_error_is_deserialize() {
let err: StreamError<TestError> = StreamError::Deserialize("json".into());
assert!(err.is_deserialize());
assert!(!err.is_database());
}
#[test]
fn stream_error_display() {
let db: StreamError<TestError> = StreamError::Database(TestError("conn"));
assert_eq!(format!("{}", db), "database error: conn");
let de: StreamError<TestError> = StreamError::Deserialize("invalid".into());
assert_eq!(format!("{}", de), "deserialize error: invalid");
}
#[test]
fn stream_error_source() {
use std::error::Error;
let db: StreamError<TestError> = StreamError::Database(TestError("source"));
assert!(db.source().is_some());
let de: StreamError<TestError> = StreamError::Deserialize("no source".into());
assert!(de.source().is_none());
}
}