bcder/decode/
error.rs

1//! Error Handling.
2//!
3//! This is a private module. Its public content is being re-exported by the
4//! parent module.
5
6use std::{error, fmt};
7use std::convert::Infallible;
8use super::source::Pos;
9
10
11//------------ ContentError --------------------------------------------------
12
13/// An error happened while interpreting BER-encoded data.
14pub struct ContentError {
15    /// The error message.
16    message: ErrorMessage,
17}
18
19impl ContentError {
20    /// Creates a content error from a static str.
21    pub fn from_static(msg: &'static str) -> Self {
22        ContentError {
23            message: ErrorMessage::Static(msg)
24        }
25    }
26
27    /// Creates a content error from a boxed trait object.
28    pub fn from_boxed(
29        msg: Box<dyn fmt::Display + Send + Sync + 'static>
30    ) -> Self {
31        ContentError {
32            message: ErrorMessage::Boxed(msg)
33        }
34    }
35}
36
37impl From<&'static str> for ContentError {
38    fn from(msg: &'static str) -> Self {
39        Self::from_static(msg)
40    }
41}
42
43impl From<String> for ContentError {
44    fn from(msg: String) -> Self {
45        Self::from_boxed(Box::new(msg))
46    }
47}
48
49impl From<DecodeError<Infallible>> for ContentError {
50    fn from(err: DecodeError<Infallible>) -> Self {
51        match err.inner {
52            DecodeErrorKind::Source(_) => unreachable!(),
53            DecodeErrorKind::Content { error, .. } => error,
54        }
55    }
56}
57
58
59impl fmt::Display for ContentError {
60    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61        self.message.fmt(f)
62    }
63}
64
65impl fmt::Debug for ContentError {
66    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
67        f.debug_tuple("ContentError")
68            .field(&self.message)
69            .finish()
70    }
71}
72
73
74//------------ ErrorMessage --------------------------------------------------
75
76/// The actual error message as a hidden enum.
77enum ErrorMessage {
78    /// The error message is a static str.
79    Static(&'static str),
80
81    /// The error message is a boxed trait object.
82    Boxed(Box<dyn fmt::Display + Send + Sync + 'static>),
83}
84
85impl fmt::Display for ErrorMessage {
86    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
87        match self {
88            ErrorMessage::Static(msg) => f.write_str(msg),
89            ErrorMessage::Boxed(ref msg) => msg.fmt(f),
90        }
91    }
92}
93
94impl fmt::Debug for ErrorMessage {
95    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96        match self {
97            ErrorMessage::Static(msg) => f.write_str(msg),
98            ErrorMessage::Boxed(ref msg) => msg.fmt(f),
99        }
100    }
101}
102
103
104//------------ DecodeError ---------------------------------------------------
105
106/// An error happened while decoding data.
107///
108/// This can either be a source error – which the type is generic over – or a
109/// content error annotated with the position in the source where it happened.
110#[derive(Debug)]
111pub struct DecodeError<S> {
112    inner: DecodeErrorKind<S>,
113}
114
115#[derive(Debug)]
116enum DecodeErrorKind<S> {
117    Source(S),
118    Content {
119        error: ContentError,
120        pos: Pos,
121    }
122}
123
124impl<S> DecodeError<S> {
125    /// Creates a decode error from a content error and a position.
126    pub fn content(error: impl Into<ContentError>, pos: Pos) -> Self {
127        DecodeError {
128            inner: DecodeErrorKind::Content { error: error.into(), pos },
129        }
130    }
131}
132
133impl DecodeError<Infallible> {
134    /// Converts a decode error from an infallible source into another error.
135    pub fn convert<S>(self) -> DecodeError<S> {
136        match self.inner {
137            DecodeErrorKind::Source(_) => unreachable!(),
138            DecodeErrorKind::Content { error, pos } => {
139                DecodeError::content(error, pos)
140            }
141        }
142    }
143}
144
145impl<S> From<S> for DecodeError<S> {
146    fn from(err: S) -> Self {
147        DecodeError { inner: DecodeErrorKind::Source(err) }
148    }
149}
150
151impl<S: fmt::Display> fmt::Display for DecodeError<S> {
152    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
153        match self.inner {
154            DecodeErrorKind::Source(ref err) => err.fmt(f),
155            DecodeErrorKind::Content { ref error, pos } => {
156                write!(f, "{} (at position {})", error, pos)
157            }
158        }
159    }
160}
161
162impl<S: fmt::Display + fmt::Debug> error::Error for DecodeError<S> { }
163