use std::fmt;
use std::io;
pub type Result<T> = core::result::Result<T, Error>;
#[derive(Debug)]
#[non_exhaustive]
pub enum Error {
Io(io::Error),
Format(fmt::Error),
Configuration(&'static str),
Closed,
Custom(Box<dyn std::error::Error + Send + Sync + 'static>),
}
impl Error {
pub fn custom<E>(error: E) -> Self
where
E: Into<Box<dyn std::error::Error + Send + Sync + 'static>>,
{
Self::Custom(error.into())
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(e) => write!(f, "log sink I/O error: {e}"),
Self::Format(_) => f.write_str("log record formatting failed"),
Self::Configuration(msg) => write!(f, "log sink configuration error: {msg}"),
Self::Closed => f.write_str("log sink is closed and no longer accepts records"),
Self::Custom(e) => write!(f, "log sink error: {e}"),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::Format(e) => Some(e),
Self::Custom(e) => Some(&**e),
Self::Configuration(_) | Self::Closed => None,
}
}
}
impl From<io::Error> for Error {
fn from(value: io::Error) -> Self {
Self::Io(value)
}
}
impl From<fmt::Error> for Error {
fn from(value: fmt::Error) -> Self {
Self::Format(value)
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::error::Error as _;
#[test]
fn test_error_display_has_context_for_every_variant() {
let cases: [(Error, &str); 5] = [
(
io::Error::other("disk full").into(),
"log sink I/O error: disk full",
),
(fmt::Error.into(), "log record formatting failed"),
(
Error::Configuration("bad"),
"log sink configuration error: bad",
),
(
Error::Closed,
"log sink is closed and no longer accepts records",
),
(Error::custom("boom"), "log sink error: boom"),
];
for (err, expected) in cases {
assert_eq!(err.to_string(), expected);
}
}
#[test]
fn test_error_source_chain() {
assert!(Error::from(io::Error::other("x")).source().is_some());
assert!(Error::from(fmt::Error).source().is_some());
assert!(Error::custom("x").source().is_some());
assert!(Error::Configuration("x").source().is_none());
assert!(Error::Closed.source().is_none());
}
}