hclog/
error.rs

1use crate::{
2    task::TaskLocalErr,
3};
4use log::SetLoggerError;
5use std::{
6    panic::Location,
7    error::Error as StdError,
8    io::{Error as IoError, ErrorKind as IoErrorKind},
9    ffi::NulError,
10    sync::PoisonError,
11    fmt,
12};
13
14/// Result type for this crate
15pub type Result<T> = std::result::Result<T, ErrorKind>;
16
17/// A list of possible errors that can occur in this library
18///
19/// This list is intended to be grow over time and is not recommended to
20/// be exhaustively matched.
21///
22/// It is used with the [`Result`](type@crate::Result) type to signal that an error occurred.
23///
24/// The `IoError` variant is used to catch any underlying [`std::io::Errors`](std::io::Error)
25/// without mapping them to internal error(s). This allows a better control over underling
26/// errors instead of "hiding" them.
27///
28/// # Handling errors and matching `ErrorKind`
29///
30/// In application code `match` against the expected `ErrorKind`, use `_` to match all
31/// other Errors.
32///
33/// ```rust
34/// use hclog::{ErrorKind};
35///
36/// match hclog::dump(&mut std::io::stdout()) {
37///    Ok(_) => {},
38///    Err(ErrorKind::IoError(e)) => eprintln!("I/O Error: {:?}", e),
39///    Err(_) => panic!("Unexpected error"),
40/// }
41/// ```
42#[derive(PartialEq, Eq, Ord, PartialOrd)]
43pub enum ErrorKind {
44    /// Failed to lock the context
45    ContextLock,
46    /// Context is inconsistent
47    ContextInconsistent,
48    /// Log-Module isn't initialized
49    ScopeNotInitialized,
50    /// Submodule is not initialized
51    KeyNotInitialized,
52    /// Parse environment variable failed
53    ParseEnv,
54    /// Parse commandline argument string failed
55    ParseArg,
56    /// Environment variable has unexpected type
57    EnvType,
58    /// Loglevel is unknown
59    UnknownLogLevel,
60    /// Failed to write logstring via [`Facade`](type@crate::FacadeVariant)
61    WriteFailed,
62    /// Logging string contained non utf8 characters
63    InvalFmtString,
64    /// Log Compat is already initialized
65    LogCompatInitialized,
66    /// Error in task local access
67    TaskLocal(TaskLocalErr),
68    /// I/O Error while writing
69    ///
70    /// Wraps the [`std::io::ErrorKind`] thrown by the underlying I/O operation.
71    IoError(IoErrorKind),
72}
73impl StdError for ErrorKind {}
74impl fmt::Display for ErrorKind {
75    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76        match *self {
77            Self::ContextLock => write!(f, "Failed to lock Context"),
78            Self::ContextInconsistent => write!(f, "Context is inconsistent"),
79            Self::ScopeNotInitialized => f.write_str("Scope not initialized"),
80            Self::KeyNotInitialized => write!(f, "LogKey is not initialized"),
81            Self::ParseEnv => write!(f, "Parse environment variable failed"),
82            Self::ParseArg => write!(f, "Parse argument string failed"),
83            Self::EnvType => write!(f, "Environment variable has unexpected type"),
84            Self::UnknownLogLevel => write!(f, "Loglevel is unknown"),
85            Self::WriteFailed => write!(f, "Failed to write logstring"),
86            Self::InvalFmtString => write!(f, "Logging string contained non utf8 characters"),
87            Self::LogCompatInitialized => write!(f, "Log Compat is already initialized"),
88            Self::TaskLocal(ref e) => write!(f, "Error '{}' in task local access", e),
89            Self::IoError(ref i) => write!(f, "IoError while writing: {:?}", i),
90        }
91    }
92}
93impl fmt::Debug for ErrorKind {
94    #[track_caller]
95    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
96        match *self {
97            Self::TaskLocal(ref e) => write!(f, "{}", e),
98            _ => write!(f, "{} in {}", self, Location::caller()),
99        }
100    }
101}
102/*
103 * map every other possible error to its according ErrorKind Variant
104 */
105impl From<TaskLocalErr> for ErrorKind {
106    fn from(tle: TaskLocalErr) -> Self {
107        Self::TaskLocal(tle)
108    }
109}
110impl From<IoError> for ErrorKind {
111    fn from(io: IoError) -> Self {
112        Self::IoError(io.kind())
113    }
114}
115impl<T: 'static> From<PoisonError<T>> for ErrorKind {
116    fn from(_: PoisonError<T>) -> Self {
117        Self::ContextLock
118    }
119}
120impl From<NulError> for ErrorKind {
121    fn from(_: NulError) -> Self {
122        Self::InvalFmtString
123    }
124}
125impl From<SetLoggerError> for ErrorKind {
126    fn from(_: SetLoggerError) -> Self {
127        Self::LogCompatInitialized
128    }
129}
130
131#[cfg(test)]
132mod test {
133    use super::ErrorKind::{self, *};
134    use crate::task::TaskLocalErr::*;
135    use std::io::{Error as IoError, ErrorKind::BrokenPipe};
136
137    #[test]
138    fn error_eq() {
139        assert_eq!(ParseEnv == ParseEnv, true);
140        assert_eq!(TaskLocal(BorrowError) == TaskLocal(BorrowError), true);
141    }
142
143    #[test]
144    fn error_ne() {
145        assert_eq!(ParseEnv == EnvType, false);
146        assert_eq!(TaskLocal(AccessError) == TaskLocal(BorrowError), false);
147    }
148
149    #[test]
150    fn from_other_error() {
151        assert_eq!(ErrorKind::from(IoError::from(BrokenPipe)), IoError(BrokenPipe));
152    }
153}