mqtt_tiny/
error.rs

1//! Error types and aggregate types
2
3use core::fmt::{Debug, Display, Formatter};
4
5/// Creates a new error with the given variant and description
6#[macro_export]
7macro_rules! err {
8    ($variant:expr, $desc:expr) => {{
9        $crate::error::Error::new($variant, $desc, file!(), line!())
10    }};
11}
12
13/// A slim, abstract error type
14#[derive(Debug, Clone)]
15pub struct Error<Variant> {
16    /// The error variant
17    pub variant: Variant,
18    /// A human readable error description
19    #[cfg(feature = "backtrace")]
20    pub description: &'static str,
21    /// The file where the error was created
22    #[cfg(feature = "backtrace")]
23    pub file: &'static str,
24    /// The line at which the error was created
25    #[cfg(feature = "backtrace")]
26    pub line: u32,
27    /// An informative error backtrace for debugging
28    #[cfg(all(feature = "backtrace", feature = "std"))]
29    pub backtrace: std::sync::Arc<std::backtrace::Backtrace>,
30}
31impl<Variant> Error<Variant> {
32    /// Creates a new error variant
33    #[doc(hidden)]
34    #[allow(unused, reason = "some args are unused, depending on feature flags")]
35    pub fn new(variant: Variant, description: &'static str, file: &'static str, line: u32) -> Self {
36        Self {
37            variant,
38            #[cfg(feature = "backtrace")]
39            description,
40            #[cfg(feature = "backtrace")]
41            file,
42            #[cfg(feature = "backtrace")]
43            line,
44            #[cfg(all(feature = "backtrace", feature = "std"))]
45            backtrace: std::sync::Arc::new(std::backtrace::Backtrace::capture()),
46        }
47    }
48
49    /// Converts `self` into a new error variant while retaining all other metadata
50    pub fn into_variant<NewVariant>(self, new_variant: NewVariant) -> Error<NewVariant> {
51        Error {
52            variant: new_variant,
53            #[cfg(feature = "backtrace")]
54            description: self.description,
55            #[cfg(feature = "backtrace")]
56            file: self.file,
57            #[cfg(feature = "backtrace")]
58            line: self.line,
59            #[cfg(all(feature = "backtrace", feature = "std"))]
60            backtrace: self.backtrace,
61        }
62    }
63}
64impl<T> Display for Error<T>
65where
66    T: Debug,
67{
68    #[cfg(not(feature = "backtrace"))]
69    fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
70        write!(f, "MQTT error: {:#?}", self.variant)
71    }
72
73    #[cfg(all(feature = "backtrace", not(feature = "std")))]
74    fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
75        write!(f, "MQTT error: {:#?} at {}:{}", self.variant, self.file, self.line)
76    }
77
78    #[cfg(all(feature = "backtrace", feature = "std"))]
79    fn fmt(&self, f: &mut Formatter) -> core::fmt::Result {
80        use std::backtrace::BacktraceStatus;
81
82        write!(f, "MQTT error: {:#?} at", self.variant)?;
83        if self.backtrace.status() == BacktraceStatus::Captured {
84            // Write backtrace if present
85            writeln!(f, "{}", self.backtrace)?;
86        }
87
88        Ok(())
89    }
90}
91#[cfg(feature = "std")]
92impl<T> std::error::Error for Error<T>
93where
94    T: Debug,
95{
96    // No members to implement yet
97}
98
99/// Some buffer is out of memory
100#[derive(Debug, Clone, PartialEq, Eq)]
101pub struct Memory;
102
103/// Some MQTT data is invalid
104#[derive(Debug, Clone, PartialEq, Eq)]
105pub enum Data {
106    /// The data is truncated
107    Truncated,
108    /// The data violates the specifications
109    SpecViolation,
110}
111
112/// A general decoding-related error
113#[derive(Debug, Clone, PartialEq, Eq)]
114pub enum Decoding {
115    /// [`Data::Truncated`]
116    Truncated,
117    /// [`Data::SpecViolation`]
118    SpecViolation,
119    /// [`Memory`]
120    Memory,
121}
122impl From<Error<Memory>> for Error<Decoding> {
123    fn from(error: Error<Memory>) -> Self {
124        error.into_variant(Decoding::Memory)
125    }
126}
127impl From<Error<Data>> for Error<Decoding> {
128    fn from(error: Error<Data>) -> Self {
129        match error.variant {
130            Data::Truncated => error.into_variant(Decoding::Truncated),
131            Data::SpecViolation => error.into_variant(Decoding::SpecViolation),
132        }
133    }
134}
135
136/// [`Error<Memory>`]
137pub type MemoryError = Error<Memory>;
138
139/// [`Error<Data>`]
140pub type DataError = Error<Data>;
141
142/// [`Error<Decoding>`]
143pub type DecoderError = Error<Decoding>;