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