hlctl/src/logerr.rs

101 lines
2.4 KiB
Rust

use std::{error::Error, fmt::Debug};
use log::{debug, error};
// So we still get a useful panic when logs are filtered
macro_rules! error_and_panic {
($($arg:tt)*) => {
log::error!($($arg)*);
panic!($($arg)*);
};
}
pub trait UnwrapLog {
type Target;
fn unwrap_or_log(self, default: Self::Target) -> Self::Target;
fn unwrap_log(self) -> Self::Target;
fn expect_log(self, expect: &str) -> Self::Target;
}
impl<T, E> UnwrapLog for Result<T, E>
where
T: Debug,
E: Error,
{
type Target = T;
fn unwrap_or_log(self, default: Self::Target) -> Self::Target {
match self {
Ok(val) => val,
Err(err) => {
error!(
"[{}] unwrap_or_log got error: {err}",
std::any::type_name::<Self::Target>()
);
debug!("^ defaulting to {default:#?}");
default
}
}
}
fn unwrap_log(self) -> Self::Target {
match self {
Ok(target) => target,
Err(err) => {
error_and_panic!("called `Result::unwrap_log()` on an `Err` value: {err}");
}
}
}
fn expect_log(self, expect: &str) -> Self::Target {
match self {
Ok(target) => target,
Err(err) => {
error_and_panic!(
"[{expect}] called `Result::expect_log()` on an `Err` value: {err}"
);
}
}
}
}
impl<T> UnwrapLog for Option<T>
where
T: Debug,
{
type Target = T;
fn unwrap_or_log(self, default: Self::Target) -> Self::Target {
match self {
Some(v) => v,
None => {
error!(
"[{}] unwrap_or_log was None",
std::any::type_name::<Self::Target>()
);
debug!("^ defaulting to {default:#?}");
default
}
}
}
fn unwrap_log(self) -> Self::Target {
match self {
Some(target) => target,
None => {
error_and_panic!("called `Option::unwrap_log()` on a `None` value");
}
}
}
fn expect_log(self, expect: &str) -> Self::Target {
match self {
Some(target) => target,
None => {
error_and_panic!("[{expect}] called `Option::expect_log()` on an `None` value");
}
}
}
}