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 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 #[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#[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#[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 TooManyElements {
120 max: usize,
121 },
122}
123
124#[derive(Debug, Copy, Clone)]
126#[non_exhaustive]
127pub enum COctetStringDecodeError {
128 TooFewBytes { actual: usize, min: usize },
129 NotAscii,
130 NotNullTerminated,
131}
132
133#[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}