trylog/
lib.rs

1//! This crate provides `inspect_or_log`, `unwrap_or_log` and `unwrap_or_default_log` methods
2//! on all types implemented [`Try`].
3//! They are useful if you want to log the error value.
4//!
5//! Different log levels are chosen by calling different methods.
6//!
7//! | method                   | level |
8//! | ------------------------ | ----- |
9//! | `inspect_or_log*`        | info  |
10//! | `unwrap_or_default_log*` | warn  |
11//! | `unwrap_or_log*`         | error |
12
13#![feature(decl_macro)]
14#![feature(try_trait_v2)]
15#![warn(missing_docs)]
16
17pub mod macros;
18
19#[doc(hidden)]
20pub use log as __log;
21
22use log::{error, info, warn};
23use std::{
24    fmt::{Debug, Display},
25    ops::{ControlFlow, Try},
26};
27
28/// This trait provides the or-log methods.
29pub trait TryLog<T, R: Debug> {
30    /// Log with [`log::Level::Info`] if the value is [`Err`] or [`None`].
31    fn inspect_or_log(self, msg: &str) -> Self;
32
33    /// Log with [`log::Level::Info`] if the value is [`Err`] or [`None`].
34    ///
35    /// The log message is returned by `f`.
36    fn inspect_or_log_with<M: Display>(self, f: impl FnOnce() -> M) -> Self;
37
38    /// Log with [`log::Level::Warn`] if the value is [`Err`] or [`None`],
39    /// and return a default value of `T`.
40    fn unwrap_or_default_log(self, msg: &str) -> T
41    where
42        T: Default;
43
44    /// Log with [`log::Level::Warn`] if the value is [`Err`] or [`None`],
45    /// and return a default value of `T`.
46    ///
47    /// The log message is returned by `f`.
48    fn unwrap_or_default_log_with<M: Display>(self, f: impl FnOnce() -> M) -> T
49    where
50        T: Default;
51
52    /// Log with [`log::Level::Error`] if the value is [`Err`] or [`None`],
53    /// and panic with the same error message.
54    fn unwrap_or_log(self, msg: &str) -> T;
55
56    /// Log with [`log::Level::Error`] if the value is [`Err`] or [`None`],
57    /// and panic with the same error message.
58    ///
59    /// The log message is returned by `f`.
60    fn unwrap_or_log_with<M: Display>(self, f: impl FnOnce() -> M) -> T;
61}
62
63#[inline(always)]
64fn inspect_or_and<T: Try>(t: T, f: impl FnOnce(&T::Residual)) -> T {
65    match t.branch() {
66        ControlFlow::Continue(v) => T::from_output(v),
67        ControlFlow::Break(e) => {
68            f(&e);
69            T::from_residual(e)
70        }
71    }
72}
73
74#[inline(always)]
75fn unwrap_or_default_and<T: Try>(t: T, f: impl FnOnce(&T::Residual)) -> T::Output
76where
77    T::Output: Default,
78{
79    match t.branch() {
80        ControlFlow::Continue(v) => v,
81        ControlFlow::Break(e) => {
82            f(&e);
83            Default::default()
84        }
85    }
86}
87
88#[inline(always)]
89fn unwrap_or_and<T: Try>(t: T, f: impl FnOnce(&T::Residual) -> String) -> T::Output {
90    match t.branch() {
91        ControlFlow::Continue(v) => v,
92        ControlFlow::Break(e) => {
93            let msg = f(&e);
94            error!("{}", msg);
95            panic!("{}", msg)
96        }
97    }
98}
99
100impl<T, R: Debug, Tr: Try<Output = T, Residual = R>> TryLog<T, R> for Tr {
101    #[inline(always)]
102    fn inspect_or_log(self, msg: &str) -> Self {
103        inspect_or_and(self, |e| info!("{msg}: {e:?}"))
104    }
105
106    #[inline(always)]
107    fn inspect_or_log_with<M: Display>(self, f: impl FnOnce() -> M) -> Self {
108        inspect_or_and(self, |e| info!("{}: {e:?}", f()))
109    }
110
111    #[inline(always)]
112    fn unwrap_or_default_log(self, msg: &str) -> T
113    where
114        T: Default,
115    {
116        unwrap_or_default_and(self, |e| warn!("{msg}: {e:?}"))
117    }
118
119    #[inline(always)]
120    fn unwrap_or_default_log_with<M: Display>(self, f: impl FnOnce() -> M) -> T
121    where
122        T: Default,
123    {
124        unwrap_or_default_and(self, |e| warn!("{}: {e:?}", f()))
125    }
126
127    #[inline(always)]
128    fn unwrap_or_log(self, msg: &str) -> T {
129        unwrap_or_and(self, |e| format!("{msg}: {e:?}"))
130    }
131
132    #[inline(always)]
133    fn unwrap_or_log_with<M: Display>(self, f: impl FnOnce() -> M) -> T {
134        unwrap_or_and(self, |e| format!("{}: {e:?}", f()))
135    }
136}