Skip to content

Commit 962f521

Browse files
committed
Introduce ErasableError for implementors to return arbitrary errors
1 parent ad62cd1 commit 962f521

21 files changed

+165
-66
lines changed

spdlog/examples/04_format.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -52,11 +52,12 @@ fn impl_manually() {
5252
let style_range_begin = dest.len();
5353

5454
dest.write_str(&record.level().as_str().to_ascii_uppercase())
55-
.map_err(spdlog::Error::FormatRecord)?;
55+
.map_err(|err| spdlog::Error::FormatRecord(err.into()))?;
5656

5757
let style_range_end = dest.len();
5858

59-
writeln!(dest, " {}", record.payload()).map_err(spdlog::Error::FormatRecord)?;
59+
writeln!(dest, " {}", record.payload())
60+
.map_err(|err| spdlog::Error::FormatRecord(err.into()))?;
6061

6162
ctx.set_style_range(Some(style_range_begin..style_range_end));
6263
Ok(())

spdlog/src/error.rs

+79-3
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
//! handler will be used, which will print the error to `stderr`.
77
88
use std::{
9+
error::Error as StdError,
910
fmt::{self, Display},
1011
io, result,
1112
};
@@ -18,6 +19,81 @@ use crate::utils::const_assert;
1819
#[cfg(feature = "multi-thread")]
1920
use crate::{sink::Task, RecordOwned};
2021

22+
/// Stores an error that can either be typed or erased.
23+
///
24+
/// This wrapper is mainly used for returning arbitrary errors from downstream
25+
/// implementors.
26+
///
27+
/// # Examples
28+
///
29+
/// ```
30+
/// use std::{error::Error, fmt, io};
31+
///
32+
/// use spdlog::{error::ErasableError, formatter::Formatter, prelude::*, sink::Sink, Record};
33+
///
34+
/// #[derive(Debug)]
35+
/// struct MyError;
36+
///
37+
/// impl Error for MyError {}
38+
///
39+
/// impl fmt::Display for MyError {
40+
/// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41+
/// write!(f, "MyError")
42+
/// }
43+
/// }
44+
///
45+
/// struct MySink;
46+
///
47+
/// impl Sink for MySink {
48+
/// fn log(&self, record: &Record) -> spdlog::Result<()> {
49+
/// let err: MyError = /* Something went wrong */
50+
/// # MyError;
51+
/// // `err` can not be converted to `io::Error`, so we use `Erased`
52+
/// Err(spdlog::Error::WriteRecord(ErasableError::erase(MyError)))
53+
/// }
54+
///
55+
/// fn flush(&self) -> spdlog::Result<()> {
56+
/// let err: io::Error = /* Something went wrong */
57+
/// # io::Error::new(io::ErrorKind::NotFound, "");
58+
/// // `err` is a `io::Error`, so we use `Typed`
59+
/// Err(spdlog::Error::FlushBuffer(err.into()))
60+
/// }
61+
///
62+
/// fn level_filter(&self) -> LevelFilter /* ... */
63+
/// # { unimplemented!() }
64+
/// fn set_level_filter(&self, level_filter: LevelFilter) /* ... */
65+
/// # { unimplemented!() }
66+
/// fn set_formatter(&self, formatter: Box<dyn Formatter>) /* ... */
67+
/// # { unimplemented!() }
68+
/// fn set_error_handler(&self, handler: Option<spdlog::ErrorHandler>) /* ... */
69+
/// # { unimplemented!() }
70+
/// }
71+
/// ```
72+
#[derive(Error, Debug)]
73+
pub enum ErasableError<E: StdError> {
74+
/// A concrete error type is held, and the user can access it.
75+
#[error("{0}")]
76+
Typed(E),
77+
/// The concrete type may not match, thus it is erased to a basic
78+
/// `dyn std::error::Error`.
79+
#[error("{0}")]
80+
Erased(Box<dyn StdError>),
81+
}
82+
83+
impl<E: StdError> ErasableError<E> {
84+
/// Erase a typed error to a basic `Box<dyn std::error::Error>`.
85+
#[must_use]
86+
pub fn erase<R: StdError + 'static>(err: R) -> ErasableError<E> {
87+
ErasableError::Erased(Box::new(err))
88+
}
89+
}
90+
91+
impl<E: StdError> From<E> for ErasableError<E> {
92+
fn from(err: E) -> Self {
93+
Self::Typed(err)
94+
}
95+
}
96+
2197
/// Contains most errors of this crate.
2298
#[derive(Error, Debug)]
2399
#[non_exhaustive]
@@ -26,20 +102,20 @@ pub enum Error {
26102
///
27103
/// [`Formatter`]: crate::formatter::Formatter
28104
#[error("format record error: {0}")]
29-
FormatRecord(fmt::Error),
105+
FormatRecord(ErasableError<fmt::Error>),
30106

31107
/// Returned by [`Sink`]s when an error occurs in writing a record to the
32108
/// target.
33109
///
34110
/// [`Sink`]: crate::sink::Sink
35111
#[error("write record error: {0}")]
36-
WriteRecord(io::Error),
112+
WriteRecord(ErasableError<io::Error>),
37113

38114
/// Returned by [`Sink`]s when an error occurs in flushing the buffer.
39115
///
40116
/// [`Sink`]: crate::sink::Sink
41117
#[error("flush buffer error: {0}")]
42-
FlushBuffer(io::Error),
118+
FlushBuffer(ErasableError<io::Error>),
43119

44120
/// Returned by [`Sink`]s when an error occurs in creating a directory.
45121
///

spdlog/src/formatter/full_formatter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ impl Formatter for FullFormatter {
111111
ctx: &mut FormatterContext,
112112
) -> crate::Result<()> {
113113
self.format_impl(record, dest, ctx)
114-
.map_err(Error::FormatRecord)
114+
.map_err(|err| Error::FormatRecord(err.into()))
115115
}
116116
}
117117

spdlog/src/formatter/journald_formatter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ impl Formatter for JournaldFormatter {
6363
ctx: &mut FormatterContext,
6464
) -> crate::Result<()> {
6565
self.format_impl(record, dest, ctx)
66-
.map_err(Error::FormatRecord)
66+
.map_err(|err| Error::FormatRecord(err.into()))
6767
}
6868
}
6969

spdlog/src/formatter/json_formatter.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ impl From<serde_json::Error> for JsonFormatterError {
7878
impl From<JsonFormatterError> for crate::Error {
7979
fn from(value: JsonFormatterError) -> Self {
8080
match value {
81-
JsonFormatterError::Fmt(e) => Error::FormatRecord(e),
81+
JsonFormatterError::Fmt(e) => Error::FormatRecord(e.into()),
8282
JsonFormatterError::Serialization(e) => Error::SerializeRecord(e.into()),
8383
}
8484
}

spdlog/src/formatter/pattern_formatter/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ use crate::{
161161
///
162162
/// impl Pattern for MyPattern {
163163
/// fn format(&self, record: &Record, dest: &mut StringBuf, _: &mut PatternContext) -> spdlog::Result<()> {
164-
/// write!(dest, "My own pattern").map_err(spdlog::Error::FormatRecord)
164+
/// write!(dest, "My own pattern").map_err(|err| spdlog::Error::FormatRecord(err.into()))
165165
/// }
166166
/// }
167167
///
@@ -225,7 +225,7 @@ use crate::{
225225
///
226226
/// impl Pattern for MyPattern {
227227
/// fn format(&self, record: &Record, dest: &mut StringBuf, _: &mut PatternContext) -> spdlog::Result<()> {
228-
/// write!(dest, "{}", self.id).map_err(spdlog::Error::FormatRecord)
228+
/// write!(dest, "{}", self.id).map_err(|err| spdlog::Error::FormatRecord(err.into()))
229229
/// }
230230
/// }
231231
///
@@ -472,7 +472,8 @@ impl Pattern for str {
472472
dest: &mut StringBuf,
473473
_ctx: &mut PatternContext,
474474
) -> crate::Result<()> {
475-
dest.write_str(self).map_err(Error::FormatRecord)
475+
dest.write_str(self)
476+
.map_err(|err| Error::FormatRecord(err.into()))
476477
}
477478
}
478479

0 commit comments

Comments
 (0)