use crate::error::DisplayError;
pub trait IntoResult: Sized {
type Value;
type Error;
fn internal_into_result(self) -> Result<Self::Value, Self::Error>;
fn with_err<F: FnOnce(&Self::Error)>(self, fun: F) -> Result<Self::Value, Self::Error> {
self.internal_into_result().map_err(|error| { fun(&error); error })
}
}
pub trait UnwrapOrExit: IntoResult {
fn unwrap_or_exit_custom<F: FnOnce(Self::Error)>(self, printer: F) -> Self::Value {
self.internal_into_result().unwrap_or_else(|error| {
printer(error);
std::process::exit(2);
})
}
fn unwrap_or_exit(self) -> Self::Value where Self::Error: 'static + std::error::Error {
self.unwrap_or_exit_custom(|error| {
eprintln!("Error: {}", error.join_sources(": "));
})
}
fn unwrap_or_exit_display(self) -> Self::Value where Self::Error: std::fmt::Display {
self.unwrap_or_exit_custom(|error| eprintln!("Error: {}", error))
}
fn unwrap_or_exit_debug(self) -> Self::Value where Self::Error: std::fmt::Debug {
self.unwrap_or_exit_custom(|error| eprintln!("Error: {:?}", error))
}
fn unwrap_or_exit_log<L: LogOwned>(self, mut logger: L) -> Self::Value where Self::Error: 'static + std::error::Error {
self.unwrap_or_exit_custom(|error| logger.log_error_owned("Error", error))
}
}
impl<T, E> IntoResult for Result<T, E> {
type Value = T;
type Error = E;
fn internal_into_result(self) -> Self {
self
}
}
impl<T, E> UnwrapOrExit for Result<T, E> {}
pub trait LogResult: IntoResult where <Self as IntoResult>::Error: 'static + std::error::Error {
fn convert_and_consume_err<E, ConvF, ConsF>(self, convert: ConvF, consume: ConsF) -> Result<Self::Value, E> where ConvF: FnOnce(&Self::Error) -> E, ConsF: FnOnce(Self::Error) {
self.internal_into_result().map_err(|error| {
let converted = convert(&error);
consume(error);
converted
})
}
fn log_error<L: Log>(self, mut logger: L, message: &str) -> Result<Self::Value, Self::Error> {
self.with_err(|error| logger.log_error(message, error))
}
fn log_warning<L: Log>(self, mut logger: L, message: &str) -> Result<Self::Value, Self::Error> {
self.with_err(|error| logger.log_warning(message, error))
}
fn log_info<L: Log>(self, mut logger: L, message: &str) -> Result<Self::Value, Self::Error> {
self.with_err(|error| logger.log_info(message, error))
}
fn log_debug<L: Log>(self, mut logger: L, message: &str) -> Result<Self::Value, Self::Error> {
self.with_err(|error| logger.log_debug(message, error))
}
fn log_trace<L: Log>(self, mut logger: L, message: &str) -> Result<Self::Value, Self::Error> {
self.with_err(|error| logger.log_trace(message, error))
}
fn log_error_and_replace<E, L: LogOwned>(self, logger: L, message: &str, replacement: E) -> Result<Self::Value, E> {
self.log_error_and_replace_with(logger, message, move |_| replacement)
}
fn log_warning_and_replace<E, L: LogOwned>(self, logger: L, message: &str, replacement: E) -> Result<Self::Value, E> {
self.log_warning_and_replace_with(logger, message, move |_| replacement)
}
fn log_info_and_replace<E, L: LogOwned>(self, logger: L, message: &str, replacement: E) -> Result<Self::Value, E> {
self.log_info_and_replace_with(logger, message, move |_| replacement)
}
fn log_debug_and_replace<E, L: LogOwned>(self, logger: L, message: &str, replacement: E) -> Result<Self::Value, E> {
self.log_debug_and_replace_with(logger, message, move |_| replacement)
}
fn log_trace_and_replace<E, L: LogOwned>(self, logger: L, message: &str, replacement: E) -> Result<Self::Value, E> {
self.log_trace_and_replace_with(logger, message, move |_| replacement)
}
fn log_error_and_replace_with<E, F, L: LogOwned>(self, mut logger: L, message: &str, convert: F) -> Result<Self::Value, E> where F: FnOnce(&Self::Error) -> E {
self.convert_and_consume_err(convert, |error| logger.log_error_owned(message, error))
}
fn log_warning_and_replace_with<E, F, L: LogOwned>(self, mut logger: L, message: &str, convert: F) -> Result<Self::Value, E> where F: FnOnce(&Self::Error) -> E {
self.convert_and_consume_err(convert, |error| logger.log_warning_owned(message, error))
}
fn log_info_and_replace_with<E, F, L: LogOwned>(self, mut logger: L, message: &str, convert: F) -> Result<Self::Value, E> where F: FnOnce(&Self::Error) -> E {
self.convert_and_consume_err(convert, |error| logger.log_info_owned(message, error))
}
fn log_debug_and_replace_with<E, F, L: LogOwned>(self, mut logger: L, message: &str, convert: F) -> Result<Self::Value, E> where F: FnOnce(&Self::Error) -> E {
self.convert_and_consume_err(convert, |error| logger.log_debug_owned(message, error))
}
fn log_trace_and_replace_with<E, F, L: LogOwned>(self, mut logger: L, message: &str, convert: F) -> Result<Self::Value, E> where F: FnOnce(&Self::Error) -> E {
self.convert_and_consume_err(convert, |error| logger.log_trace_owned(message, error))
}
}
impl<T, E: 'static + std::error::Error> LogResult for Result<T, E> {}
pub trait LogOwned {
fn log_error_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E);
fn log_warning_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E);
fn log_info_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E);
fn log_debug_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E);
fn log_trace_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E);
}
pub trait Log: LogOwned {
fn log_error(&mut self, message: &str, error: &(dyn 'static + std::error::Error));
fn log_warning(&mut self, message: &str, error: &(dyn 'static + std::error::Error));
fn log_info(&mut self, message: &str, error: &(dyn 'static + std::error::Error));
fn log_debug(&mut self, message: &str, error: &(dyn 'static + std::error::Error));
fn log_trace(&mut self, message: &str, error: &(dyn 'static + std::error::Error));
}
impl<T: LogOwned> LogOwned for &mut T {
fn log_error_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
(*self).log_error_owned(message, error);
}
fn log_warning_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
(*self).log_warning_owned(message, error);
}
fn log_info_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
(*self).log_info_owned(message, error);
}
fn log_debug_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
(*self).log_debug_owned(message, error);
}
fn log_trace_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
(*self).log_trace_owned(message, error);
}
}
#[macro_export]
macro_rules! impl_log_owned {
($type:ty) => {
impl LogOwned for $type {
fn log_error_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
$crate::result::Log::log_error(self, message, &error);
}
fn log_warning_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
$crate::result::Log::log_warning(self, message, &error);
}
fn log_info_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
$crate::result::Log::log_info(self, message, &error);
}
fn log_debug_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
$crate::result::Log::log_debug(self, message, &error);
}
fn log_trace_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
$crate::result::Log::log_trace(self, message, &error);
}
}
}
}
impl<T: Log> Log for &mut T {
fn log_error(&mut self, message: &str, error: &(dyn 'static + std::error::Error)) {
(*self).log_error(message, error);
}
fn log_warning(&mut self, message: &str, error: &(dyn 'static + std::error::Error)) {
(*self).log_warning(message, error);
}
fn log_info(&mut self, message: &str, error: &(dyn 'static + std::error::Error)) {
(*self).log_info(message, error);
}
fn log_debug(&mut self, message: &str, error: &(dyn 'static + std::error::Error)) {
(*self).log_debug(message, error);
}
fn log_trace(&mut self, message: &str, error: &(dyn 'static + std::error::Error)) {
(*self).log_trace(message, error);
}
}
#[cfg(feature = "log")]
#[derive(Copy, Clone)]
pub struct GlobalLogger;
#[cfg(feature = "log")]
impl Log for GlobalLogger {
fn log_error(&mut self, message: &str, error: &(dyn 'static + std::error::Error)) {
log::error!("{}: {}", message, error.join_sources(": "));
}
fn log_warning(&mut self, message: &str, error: &(dyn 'static + std::error::Error)) {
log::warn!("{}: {}", message, error.join_sources(": "));
}
fn log_info(&mut self, message: &str, error: &(dyn 'static + std::error::Error)) {
log::info!("{}: {}", message, error.join_sources(": "));
}
fn log_debug(&mut self, message: &str, error: &(dyn 'static + std::error::Error)) {
log::debug!("{}: {}", message, error.join_sources(": "));
}
fn log_trace(&mut self, message: &str, error: &(dyn 'static + std::error::Error)) {
log::trace!("{}: {}", message, error.join_sources(": "));
}
}
#[cfg(feature = "log")]
impl_log_owned!(GlobalLogger);
#[cfg(feature = "slog")]
impl LogOwned for &slog::Logger {
fn log_error_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
slog::error!(self, "{}", message; "error" => #error);
}
fn log_warning_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
slog::warn!(self, "{}", message; "error" => #error);
}
fn log_info_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
slog::info!(self, "{}", message; "error" => #error);
}
fn log_debug_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
slog::debug!(self, "{}", message; "error" => #error);
}
fn log_trace_owned<E: 'static + std::error::Error>(&mut self, message: &str, error: E) {
slog::trace!(self, "{}", message; "error" => #error);
}
}
pub type MultilineTerminator = Result<(), crate::error::TerminatingError<crate::error::MultilineTerminator, crate::error::BoxedError>>;