1use crate::fields::SmppField;
2
3#[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 #[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#[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#[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 TooManyElements {
139 max: usize,
140 },
141 UdhDecodeError(UdhDecodeError),
142}
143
144#[derive(Debug, Copy, Clone)]
146#[non_exhaustive]
147pub enum COctetStringDecodeError {
148 TooFewBytes { actual: usize, min: usize },
149 NotAscii,
150 NotNullTerminated,
151}
152
153#[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#[derive(Debug, Copy, Clone)]
163#[non_exhaustive]
164pub enum UdhDecodeError {
165 ConcatenatedShortMessageDecodeError(ConcatenatedShortMessageDecodeError),
166}
167
168#[derive(Debug, Copy, Clone)]
170#[non_exhaustive]
171pub enum ConcatenatedShortMessageDecodeError {
172 InvalidInformationElementLength {
174 actual: u8,
175 expected: u8,
176 },
177 TotalPartsZero,
179 PartNumberZero,
181 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}