Skip to main content

veilid_tools/
log_unwrap.rs

1//! Fork of `tracing-unwrap` crate, modified to also allow non-tracing loggers to function
2
3use super::*;
4use std::fmt;
5
6/// Extension trait for Result types.
7pub trait ResultExt<T, E> {
8    fn ok_or_log(self) -> Option<T>
9    where
10        E: fmt::Debug;
11
12    fn unwrap_or_log(self) -> T
13    where
14        E: fmt::Debug;
15
16    fn expect_or_log(self, msg: &str) -> T
17    where
18        E: fmt::Debug;
19
20    fn unwrap_err_or_log(self) -> E
21    where
22        T: fmt::Debug;
23
24    fn expect_err_or_log(self, msg: &str) -> E
25    where
26        T: fmt::Debug;
27}
28
29impl<T, E> ResultExt<T, E> for Result<T, E> {
30    #[inline]
31    #[track_caller]
32    fn ok_or_log(self) -> Option<T>
33    where
34        E: fmt::Debug,
35    {
36        match self {
37            Ok(t) => Some(t),
38            Err(e) => {
39                discarded_with("called `Result::ok_or_log` on an `Err` value", &e);
40                None
41            }
42        }
43    }
44
45    #[inline]
46    #[track_caller]
47    fn unwrap_or_log(self) -> T
48    where
49        E: fmt::Debug,
50    {
51        match self {
52            Ok(t) => t,
53            Err(e) => failed_with("called `Result::unwrap_or_log()` on an `Err` value", &e),
54        }
55    }
56
57    #[inline]
58    #[track_caller]
59    fn expect_or_log(self, msg: &str) -> T
60    where
61        E: fmt::Debug,
62    {
63        match self {
64            Ok(t) => t,
65            Err(e) => failed_with(msg, &e),
66        }
67    }
68
69    #[inline]
70    #[track_caller]
71    fn unwrap_err_or_log(self) -> E
72    where
73        T: fmt::Debug,
74    {
75        match self {
76            Ok(t) => failed_with("called `Result::unwrap_err_or_log()` on an `Ok` value", &t),
77            Err(e) => e,
78        }
79    }
80
81    #[inline]
82    #[track_caller]
83    fn expect_err_or_log(self, msg: &str) -> E
84    where
85        T: fmt::Debug,
86    {
87        match self {
88            Ok(t) => failed_with(msg, &t),
89            Err(e) => e,
90        }
91    }
92}
93
94/// Extension trait for Option types.
95pub trait OptionExt<T> {
96    fn unwrap_or_log(self) -> T;
97
98    fn expect_or_log(self, msg: &str) -> T;
99
100    fn unwrap_none_or_log(self)
101    where
102        T: fmt::Debug;
103
104    fn expect_none_or_log(self, msg: &str)
105    where
106        T: fmt::Debug;
107}
108
109impl<T> OptionExt<T> for Option<T> {
110    #[inline]
111    #[track_caller]
112    fn unwrap_or_log(self) -> T {
113        match self {
114            Some(val) => val,
115            None => failed("called `Option::unwrap_or_log()` on a `None` value"),
116        }
117    }
118
119    #[inline]
120    #[track_caller]
121    fn expect_or_log(self, msg: &str) -> T {
122        match self {
123            Some(val) => val,
124            None => failed(msg),
125        }
126    }
127
128    #[inline]
129    #[track_caller]
130    fn unwrap_none_or_log(self)
131    where
132        T: fmt::Debug,
133    {
134        if let Some(val) = self {
135            failed_with(
136                "called `Option::unwrap_none_or_log()` on a `Some` value",
137                &val,
138            );
139        }
140    }
141
142    #[inline]
143    #[track_caller]
144    fn expect_none_or_log(self, msg: &str)
145    where
146        T: fmt::Debug,
147    {
148        if let Some(val) = self {
149            failed_with(msg, &val);
150        }
151    }
152}
153
154//
155// Helper functions.
156//
157
158#[inline(never)]
159#[cold]
160#[track_caller]
161fn failed(msg: &str) -> ! {
162    #[cfg(not(feature = "log-location-quiet"))]
163    {
164        let location = std::panic::Location::caller();
165        #[cfg(feature = "tracing")]
166        error!(
167            unwrap.filepath = location.file(),
168            unwrap.lineno = location.line(),
169            unwrap.columnno = location.column(),
170            "{}",
171            msg
172        );
173        #[cfg(not(feature = "tracing"))]
174        error!(
175            "{}:{}:{} {}",
176            location.file(),
177            location.line(),
178            location.column(),
179            msg
180        );
181    }
182
183    #[cfg(feature = "log-location-quiet")]
184    error!("{}", msg);
185
186    #[cfg(feature = "panic-quiet")]
187    panic!();
188    #[cfg(not(feature = "panic-quiet"))]
189    panic!("{}", msg)
190}
191
192#[inline(never)]
193#[cold]
194#[track_caller]
195fn failed_with(msg: &str, value: &dyn fmt::Debug) -> ! {
196    #[cfg(not(feature = "log-location-quiet"))]
197    {
198        let location = std::panic::Location::caller();
199        #[cfg(feature = "tracing")]
200        error!(
201            unwrap.filepath = location.file(),
202            unwrap.lineno = location.line(),
203            unwrap.columnno = location.column(),
204            "{}: {:?}",
205            msg,
206            &value
207        );
208        #[cfg(not(feature = "tracing"))]
209        error!(
210            "{}:{}:{} {}: {:?}",
211            location.file(),
212            location.line(),
213            location.column(),
214            msg,
215            &value
216        );
217    }
218
219    #[cfg(feature = "log-location-quiet")]
220    error!("{}: {:?}", msg, &value);
221
222    #[cfg(feature = "panic-quiet")]
223    panic!();
224    #[cfg(not(feature = "panic-quiet"))]
225    panic!("{}: {:?}", msg, &value);
226}
227
228#[inline(never)]
229#[cold]
230#[track_caller]
231fn discarded_with(msg: &str, value: &dyn fmt::Debug) {
232    #[cfg(not(feature = "log-location-quiet"))]
233    {
234        let location = std::panic::Location::caller();
235
236        warn!(
237            "{}:{}:{} {}: {:?}",
238            location.file(),
239            location.line(),
240            location.column(),
241            msg,
242            &value
243        );
244    }
245
246    #[cfg(feature = "log-location-quiet")]
247    warn!("{}: {:?}", msg, &value);
248}