rusmpp_core/decode/
error.rs

1use crate::fields::SmppField;
2
3/// An error that can occur when decoding `SMPP` values.
4#[derive(Debug)]
5pub struct DecodeError {
6    kind: DecodeErrorKind,
7    #[cfg(feature = "verbose")]
8    source: Option<alloc::boxed::Box<DecodeErrorSource>>,
9}
10
11impl DecodeError {
12    #[inline]
13    pub const fn new(kind: DecodeErrorKind) -> Self {
14        #[cfg(feature = "verbose")]
15        return Self { kind, source: None };
16
17        #[cfg(not(feature = "verbose"))]
18        Self { kind }
19    }
20
21    #[inline]
22    #[cold]
23    #[cfg(feature = "verbose")]
24    #[cfg_attr(docsrs, doc(cfg(feature = "verbose")))]
25    pub fn with_source(mut self, field: SmppField, error: DecodeError) -> Self {
26        self.source = Some(alloc::boxed::Box::new(DecodeErrorSource { field, error }));
27        self
28    }
29
30    #[inline]
31    #[cold]
32    #[cfg(feature = "verbose")]
33    #[cfg_attr(docsrs, doc(cfg(feature = "verbose")))]
34    pub fn as_source(self, field: SmppField) -> DecodeError {
35        DecodeError::new(self.kind).with_source(field, self)
36    }
37
38    #[inline]
39    #[cfg(feature = "verbose")]
40    #[cfg_attr(docsrs, doc(cfg(feature = "verbose")))]
41    pub fn source(&self) -> Option<&DecodeErrorSource> {
42        self.source.as_deref()
43    }
44
45    #[inline]
46    pub const fn kind(&self) -> DecodeErrorKind {
47        self.kind
48    }
49
50    #[inline]
51    pub const fn unexpected_eof() -> Self {
52        Self::new(DecodeErrorKind::UnexpectedEof)
53    }
54
55    #[inline]
56    pub const fn c_octet_string_decode_error(error: COctetStringDecodeError) -> Self {
57        Self::new(DecodeErrorKind::COctetStringDecodeError(error))
58    }
59
60    #[inline]
61    pub const fn octet_string_decode_error(error: OctetStringDecodeError) -> Self {
62        Self::new(DecodeErrorKind::OctetStringDecodeError(error))
63    }
64
65    #[inline]
66    pub const fn unsupported_key(key: u32) -> Self {
67        Self::new(DecodeErrorKind::UnsupportedKey { key })
68    }
69
70    #[inline]
71    pub const fn too_many_elements(max: usize) -> Self {
72        Self::new(DecodeErrorKind::TooManyElements { max })
73    }
74
75    /// Checks recursively if the field exists in the sources tree.
76    #[cfg(feature = "verbose")]
77    #[cfg_attr(docsrs, doc(cfg(feature = "verbose")))]
78    pub fn field_exists(&self, field: SmppField) -> bool {
79        if let Some(source) = &self.source {
80            if source.field == field {
81                return true;
82            }
83
84            return source.error.field_exists(field);
85        }
86
87        false
88    }
89}
90
91/// Source of [`DecodeError`].
92#[derive(Debug)]
93#[cfg(feature = "verbose")]
94#[cfg_attr(docsrs, doc(cfg(feature = "verbose")))]
95pub struct DecodeErrorSource {
96    field: SmppField,
97    error: DecodeError,
98}
99
100#[cfg(feature = "verbose")]
101impl DecodeErrorSource {
102    pub const fn field(&self) -> SmppField {
103        self.field
104    }
105
106    pub const fn error(&self) -> &DecodeError {
107        &self.error
108    }
109}
110
111/// Kind of [`DecodeError`].
112#[derive(Debug, Copy, Clone)]
113#[non_exhaustive]
114pub enum DecodeErrorKind {
115    UnexpectedEof,
116    COctetStringDecodeError(COctetStringDecodeError),
117    OctetStringDecodeError(OctetStringDecodeError),
118    UnsupportedKey {
119        key: u32,
120    },
121    /// An error that can occur when decoding a fixed size of elements.
122    ///
123    /// E.g. decoding `[T; N]` where `N` is the fixed size. Mostly while decoding arrays of `TLVs`.
124    TooManyElements {
125        max: usize,
126    },
127}
128
129/// An error that can occur when decoding a `COctetString`.
130#[derive(Debug, Copy, Clone)]
131#[non_exhaustive]
132pub enum COctetStringDecodeError {
133    TooFewBytes { actual: usize, min: usize },
134    NotAscii,
135    NotNullTerminated,
136}
137
138/// An error that can occur when decoding an `OctetString`.
139#[derive(Debug, Copy, Clone)]
140#[non_exhaustive]
141pub enum OctetStringDecodeError {
142    TooManyBytes { actual: usize, max: usize },
143    TooFewBytes { actual: usize, min: usize },
144}
145
146#[cfg(feature = "verbose")]
147impl core::fmt::Display for DecodeErrorSource {
148    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
149        write!(f, "field: {:?}, error: {}", self.field, self.error)
150    }
151}
152
153#[cfg(feature = "verbose")]
154impl core::error::Error for DecodeErrorSource {
155    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
156        Some(&self.error)
157    }
158
159    fn cause(&self) -> Option<&dyn core::error::Error> {
160        self.source()
161    }
162}
163
164impl core::fmt::Display for DecodeError {
165    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
166        #[cfg(feature = "verbose")]
167        return match &self.source {
168            Some(source) => {
169                write!(f, "Decode error. kind: {}, source: [{source}]", self.kind,)
170            }
171            None => write!(f, "Decode error. kind: {}", self.kind),
172        };
173
174        #[cfg(not(feature = "verbose"))]
175        write!(f, "Decode error. kind: {}", self.kind)
176    }
177}
178
179impl core::error::Error for DecodeError {
180    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
181        #[cfg(feature = "verbose")]
182        return match &self.source {
183            Some(source) => Some(source.as_ref()),
184            None => None,
185        };
186
187        #[cfg(not(feature = "verbose"))]
188        None
189    }
190
191    fn cause(&self) -> Option<&dyn core::error::Error> {
192        core::error::Error::source(self)
193    }
194}
195
196impl core::fmt::Display for DecodeErrorKind {
197    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
198        match self {
199            DecodeErrorKind::UnexpectedEof => write!(f, "Unexpected EOF"),
200            DecodeErrorKind::COctetStringDecodeError(e) => write!(f, "COctetString error: {e}"),
201            DecodeErrorKind::OctetStringDecodeError(e) => write!(f, "OctetString error: {e}"),
202            DecodeErrorKind::UnsupportedKey { key } => write!(f, "Unsupported key: {key}"),
203            DecodeErrorKind::TooManyElements { max } => {
204                write!(f, "Too many elements. max: {max}")
205            }
206        }
207    }
208}
209
210impl core::fmt::Display for COctetStringDecodeError {
211    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
212        match self {
213            COctetStringDecodeError::TooFewBytes { actual, min } => {
214                write!(f, "Too few bytes. actual: {actual}, min: {min}")
215            }
216            COctetStringDecodeError::NotAscii => write!(f, "Not ASCII"),
217            COctetStringDecodeError::NotNullTerminated => write!(f, "Not null terminated"),
218        }
219    }
220}
221
222impl core::error::Error for COctetStringDecodeError {}
223
224impl core::fmt::Display for OctetStringDecodeError {
225    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
226        match self {
227            OctetStringDecodeError::TooManyBytes { actual, max } => {
228                write!(f, "Too many bytes. actual: {actual}, max: {max}")
229            }
230            OctetStringDecodeError::TooFewBytes { actual, min } => {
231                write!(f, "Too few bytes. actual: {actual}, min: {min}")
232            }
233        }
234    }
235}
236
237impl core::error::Error for OctetStringDecodeError {}
238
239#[doc(hidden)]
240pub trait DecodeResultExt<T, E> {
241    fn map_decoded<F, U>(self, op: F) -> Result<(U, usize), E>
242    where
243        F: FnOnce(T) -> U;
244}
245
246impl<T, E> DecodeResultExt<T, E> for Result<(T, usize), E> {
247    fn map_decoded<F, U>(self, op: F) -> Result<(U, usize), E>
248    where
249        F: FnOnce(T) -> U,
250    {
251        self.map(|(this, size)| (op(this), size))
252    }
253}
254
255#[doc(hidden)]
256pub trait DecodeErrorExt<T> {
257    fn map_as_source(self, field: SmppField) -> Result<T, DecodeError>;
258}
259
260impl<T> DecodeErrorExt<T> for Result<T, DecodeError> {
261    #[cold]
262    fn map_as_source(self, _field: SmppField) -> Result<T, DecodeError> {
263        #[cfg(feature = "verbose")]
264        return self.map_err(|error| error.as_source(_field));
265
266        #[cfg(not(feature = "verbose"))]
267        self
268    }
269}