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    #[inline]
76    pub const fn udh_decode_error(error: UdhDecodeError) -> Self {
77        Self::new(DecodeErrorKind::UdhDecodeError(error))
78    }
79
80    #[inline]
81    pub const fn concatenated_short_message_decode_error(
82        error: ConcatenatedShortMessageDecodeError,
83    ) -> Self {
84        Self::new(DecodeErrorKind::UdhDecodeError(
85            UdhDecodeError::ConcatenatedShortMessageDecodeError(error),
86        ))
87    }
88
89    /// Checks recursively if the field exists in the sources tree.
90    #[cfg(feature = "verbose")]
91    #[cfg_attr(docsrs, doc(cfg(feature = "verbose")))]
92    pub fn field_exists(&self, field: SmppField) -> bool {
93        if let Some(source) = &self.source {
94            if source.field == field {
95                return true;
96            }
97
98            return source.error.field_exists(field);
99        }
100
101        false
102    }
103}
104
105/// Source of [`DecodeError`].
106#[derive(Debug)]
107#[cfg(feature = "verbose")]
108#[cfg_attr(docsrs, doc(cfg(feature = "verbose")))]
109pub struct DecodeErrorSource {
110    field: SmppField,
111    error: DecodeError,
112}
113
114#[cfg(feature = "verbose")]
115impl DecodeErrorSource {
116    pub const fn field(&self) -> SmppField {
117        self.field
118    }
119
120    pub const fn error(&self) -> &DecodeError {
121        &self.error
122    }
123}
124
125/// Kind of [`DecodeError`].
126#[derive(Debug, Copy, Clone)]
127#[non_exhaustive]
128pub enum DecodeErrorKind {
129    UnexpectedEof,
130    COctetStringDecodeError(COctetStringDecodeError),
131    OctetStringDecodeError(OctetStringDecodeError),
132    UnsupportedKey {
133        key: u32,
134    },
135    /// An error that can occur when decoding a fixed size of elements.
136    ///
137    /// E.g. decoding `[T; N]` where `N` is the fixed size. Mostly while decoding arrays of `TLVs`.
138    TooManyElements {
139        max: usize,
140    },
141    UdhDecodeError(UdhDecodeError),
142}
143
144/// An error that can occur when decoding a `COctetString`.
145#[derive(Debug, Copy, Clone)]
146#[non_exhaustive]
147pub enum COctetStringDecodeError {
148    TooFewBytes { actual: usize, min: usize },
149    NotAscii,
150    NotNullTerminated,
151}
152
153/// An error that can occur when decoding an `OctetString`.
154#[derive(Debug, Copy, Clone)]
155#[non_exhaustive]
156pub enum OctetStringDecodeError {
157    TooManyBytes { actual: usize, max: usize },
158    TooFewBytes { actual: usize, min: usize },
159}
160
161/// An error that can occur when decoding a `UDH`.
162#[derive(Debug, Copy, Clone)]
163#[non_exhaustive]
164pub enum UdhDecodeError {
165    ConcatenatedShortMessageDecodeError(ConcatenatedShortMessageDecodeError),
166}
167
168/// An error that can occur when decoding a `ConcatenatedShortMessage` UDH.
169#[derive(Debug, Copy, Clone)]
170#[non_exhaustive]
171pub enum ConcatenatedShortMessageDecodeError {
172    /// The length of the information element is invalid.
173    InvalidInformationElementLength {
174        actual: u8,
175        expected: u8,
176    },
177    /// The total number of parts is zero.
178    TotalPartsZero,
179    /// The part number is zero.
180    PartNumberZero,
181    /// The part number exceeds the total number of parts.
182    PartNumberExceedsTotalParts {
183        part_number: u8,
184        total_parts: u8,
185    },
186    TooFewBytes {
187        actual: usize,
188        min: usize,
189    },
190}
191
192#[cfg(feature = "verbose")]
193impl core::fmt::Display for DecodeErrorSource {
194    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
195        write!(f, "field: {:?}, error: {}", self.field, self.error)
196    }
197}
198
199#[cfg(feature = "verbose")]
200impl core::error::Error for DecodeErrorSource {
201    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
202        Some(&self.error)
203    }
204
205    fn cause(&self) -> Option<&dyn core::error::Error> {
206        self.source()
207    }
208}
209
210impl core::fmt::Display for DecodeError {
211    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
212        #[cfg(feature = "verbose")]
213        return match &self.source {
214            Some(source) => {
215                write!(f, "Decode error. kind: {}, source: [{source}]", self.kind,)
216            }
217            None => write!(f, "Decode error. kind: {}", self.kind),
218        };
219
220        #[cfg(not(feature = "verbose"))]
221        write!(f, "Decode error. kind: {}", self.kind)
222    }
223}
224
225impl core::error::Error for DecodeError {
226    fn source(&self) -> Option<&(dyn core::error::Error + 'static)> {
227        #[cfg(feature = "verbose")]
228        return match &self.source {
229            Some(source) => Some(source.as_ref()),
230            None => None,
231        };
232
233        #[cfg(not(feature = "verbose"))]
234        None
235    }
236
237    fn cause(&self) -> Option<&dyn core::error::Error> {
238        core::error::Error::source(self)
239    }
240}
241
242impl core::fmt::Display for DecodeErrorKind {
243    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
244        match self {
245            DecodeErrorKind::UnexpectedEof => write!(f, "Unexpected EOF"),
246            DecodeErrorKind::COctetStringDecodeError(e) => write!(f, "COctetString error: {e}"),
247            DecodeErrorKind::OctetStringDecodeError(e) => write!(f, "OctetString error: {e}"),
248            DecodeErrorKind::UnsupportedKey { key } => write!(f, "Unsupported key: {key}"),
249            DecodeErrorKind::TooManyElements { max } => {
250                write!(f, "Too many elements. max: {max}")
251            }
252            DecodeErrorKind::UdhDecodeError(e) => write!(f, "UDH decode error: {e}"),
253        }
254    }
255}
256
257impl core::fmt::Display for COctetStringDecodeError {
258    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
259        match self {
260            COctetStringDecodeError::TooFewBytes { actual, min } => {
261                write!(f, "Too few bytes. actual: {actual}, min: {min}")
262            }
263            COctetStringDecodeError::NotAscii => write!(f, "Not ASCII"),
264            COctetStringDecodeError::NotNullTerminated => write!(f, "Not null terminated"),
265        }
266    }
267}
268
269impl core::error::Error for COctetStringDecodeError {}
270
271impl core::fmt::Display for OctetStringDecodeError {
272    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
273        match self {
274            OctetStringDecodeError::TooManyBytes { actual, max } => {
275                write!(f, "Too many bytes. actual: {actual}, max: {max}")
276            }
277            OctetStringDecodeError::TooFewBytes { actual, min } => {
278                write!(f, "Too few bytes. actual: {actual}, min: {min}")
279            }
280        }
281    }
282}
283
284impl core::error::Error for OctetStringDecodeError {}
285
286impl core::fmt::Display for UdhDecodeError {
287    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
288        match self {
289            UdhDecodeError::ConcatenatedShortMessageDecodeError(e) => {
290                write!(f, "ConcatenatedShortMessage decode error: {e}")
291            }
292        }
293    }
294}
295
296impl core::error::Error for UdhDecodeError {}
297
298impl core::fmt::Display for ConcatenatedShortMessageDecodeError {
299    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
300        match self {
301            ConcatenatedShortMessageDecodeError::InvalidInformationElementLength {
302                actual,
303                expected,
304            } => {
305                write!(
306                    f,
307                    "Invalid information element length. actual: {actual}, expected: {expected}"
308                )
309            }
310            ConcatenatedShortMessageDecodeError::PartNumberZero => {
311                write!(f, "Part number cannot be zero")
312            }
313            ConcatenatedShortMessageDecodeError::PartNumberExceedsTotalParts {
314                part_number,
315                total_parts,
316            } => {
317                write!(
318                    f,
319                    "Part number {} exceeds total parts {}",
320                    part_number, total_parts
321                )
322            }
323            ConcatenatedShortMessageDecodeError::TotalPartsZero => {
324                write!(f, "Total parts cannot be zero")
325            }
326            ConcatenatedShortMessageDecodeError::TooFewBytes { actual, min } => {
327                write!(f, "Too few bytes. actual: {actual}, min: {min}")
328            }
329        }
330    }
331}
332
333impl core::error::Error for ConcatenatedShortMessageDecodeError {}
334
335#[doc(hidden)]
336pub trait DecodeResultExt<T, E> {
337    fn map_decoded<F, U>(self, op: F) -> Result<(U, usize), E>
338    where
339        F: FnOnce(T) -> U;
340}
341
342impl<T, E> DecodeResultExt<T, E> for Result<(T, usize), E> {
343    fn map_decoded<F, U>(self, op: F) -> Result<(U, usize), E>
344    where
345        F: FnOnce(T) -> U,
346    {
347        self.map(|(this, size)| (op(this), size))
348    }
349}
350
351#[doc(hidden)]
352pub trait DecodeErrorExt<T> {
353    fn map_as_source(self, field: SmppField) -> Result<T, DecodeError>;
354}
355
356impl<T> DecodeErrorExt<T> for Result<T, DecodeError> {
357    #[cold]
358    fn map_as_source(self, _field: SmppField) -> Result<T, DecodeError> {
359        #[cfg(feature = "verbose")]
360        return self.map_err(|error| error.as_source(_field));
361
362        #[cfg(not(feature = "verbose"))]
363        self
364    }
365}