Skip to main content

kmip_ttlv/
error.rs

1//! Information about the (de)serialization failure and the location at which it failed.
2
3use std::{convert::TryFrom, fmt::Debug, fmt::Display};
4
5use crate::types::{self, ByteOffset, FieldType, TtlvTag, TtlvType};
6
7pub type Result<T> = std::result::Result<T, Error>;
8
9// --- Error ----------------------------------------------------------------------------------------------------------
10
11/// Details of a (de)serialization failure and the location in the data where the problem occured.
12///
13/// An error consists of an [ErrorKind] that identifies the kind of error that occured, and an [ErrorLocation] that
14/// describes where in the data the problem occurred.
15#[derive(Debug)]
16#[non_exhaustive]
17pub struct Error {
18    kind: ErrorKind,
19    location: ErrorLocation,
20}
21
22impl Error {
23    pub(crate) fn new(kind: ErrorKind, location: ErrorLocation) -> Self {
24        Self { kind, location }
25    }
26
27    pub(crate) fn into_inner(self) -> (ErrorKind, ErrorLocation) {
28        (self.kind, self.location)
29    }
30
31    /// Get details about the kind of error that occurred.
32    pub fn kind(&self) -> &ErrorKind {
33        &self.kind
34    }
35
36    /// Get details about where in the data the error occurred.
37    pub fn location(&self) -> &ErrorLocation {
38        &self.location
39    }
40}
41
42impl std::error::Error for Error {}
43
44impl Display for Error {
45    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
46        match &self.kind {
47            ErrorKind::IoError(error) => f.write_fmt(format_args!(
48                "IO error {:?}: {} (at {})",
49                error.kind(),
50                error,
51                self.location
52            )),
53            ErrorKind::ResponseSizeExceedsLimit(size) => {
54                f.write_fmt(format_args!("Response size {} exceeds the configured limit", size))
55            }
56            ErrorKind::MalformedTtlv(error) => {
57                f.write_fmt(format_args!("Malformed TTLV: {:?} (at {})", error, self.location))
58            }
59            ErrorKind::SerdeError(error) => {
60                f.write_fmt(format_args!("Serde error : {:?} (at {})", error, self.location))
61            }
62        }
63    }
64}
65
66impl Error {
67    pub(crate) fn pinpoint<T, L>(error: T, location: L) -> Self
68    where
69        ErrorKind: From<T>,
70        ErrorLocation: From<L>,
71    {
72        Self {
73            kind: error.into(),
74            location: location.into(),
75        }
76    }
77
78    pub(crate) fn pinpoint_with_tag<T, L>(error: T, location: L, tag: TtlvTag) -> Self
79    where
80        ErrorKind: From<T>,
81        ErrorLocation: From<L>,
82    {
83        Self {
84            kind: error.into(),
85            location: ErrorLocation::from(location).with_tag(tag),
86        }
87    }
88
89    pub(crate) fn pinpoint_with_tag_and_type<T, L>(error: T, location: L, tag: TtlvTag, r#type: TtlvType) -> Self
90    where
91        ErrorKind: From<T>,
92        ErrorLocation: From<L>,
93    {
94        Self {
95            kind: error.into(),
96            location: ErrorLocation::from(location).with_tag(tag).with_type(r#type),
97        }
98    }
99}
100
101// --- ErrorKind ------------------------------------------------------------------------------------------------------
102
103// Errors raised by the inner guts of the (de)serialization process may occur in code that has no notion of the context
104// of or position within those bytes and so no way to indicate the location of the bytes relevant to the error, either
105// as a byte position or in terms of TTLV tag sequence. Hence why we separate out location of error from type of error.
106
107/// Details about the kind of error that occurred.
108///
109/// Errors can be roughly split into the following categories:
110///   - Errors while reading/writing, i.e. [ErrorKind::IoError] and [ErrorKind::ResponseSizeExceedsLimit].
111///   - Errors while parsing/generating TTLV bytes, i.e. [ErrorKind::MalformedTtlv].
112///   - Errors while (de)serializing from/to Rust data structures, i.e. [ErrorKind::SerdeError].
113#[derive(Debug)]
114#[non_exhaustive]
115pub enum ErrorKind {
116    IoError(std::io::Error),
117    ResponseSizeExceedsLimit(usize),
118    MalformedTtlv(MalformedTtlvError),
119    SerdeError(SerdeError),
120}
121
122impl From<std::io::Error> for ErrorKind {
123    fn from(err: std::io::Error) -> Self {
124        Self::IoError(err)
125    }
126}
127
128impl From<types::Error> for ErrorKind {
129    fn from(err: types::Error) -> Self {
130        match err {
131            types::Error::IoError(e) => Self::IoError(e),
132            types::Error::UnexpectedTtlvField { expected, actual } => {
133                Self::MalformedTtlv(MalformedTtlvError::UnexpectedTtlvField { expected, actual })
134            }
135            types::Error::InvalidTtlvTag(v) => Self::SerdeError(SerdeError::InvalidTag(v)),
136            types::Error::UnsupportedTtlvType(v) => Self::MalformedTtlv(MalformedTtlvError::UnsupportedType(v)),
137            types::Error::InvalidTtlvType(v) => Self::MalformedTtlv(MalformedTtlvError::InvalidType(v)),
138            types::Error::InvalidTtlvValueLength {
139                expected,
140                actual,
141                r#type,
142            } => Self::MalformedTtlv(MalformedTtlvError::InvalidLength {
143                expected,
144                actual,
145                r#type,
146            }),
147            types::Error::InvalidTtlvValue(r#type) => Self::MalformedTtlv(MalformedTtlvError::InvalidValue { r#type }),
148            types::Error::InvalidStateMachineOperation => Self::SerdeError(SerdeError::Other(
149                "Internal error: invalid state machine operaiton".into(),
150            )),
151        }
152    }
153}
154
155impl From<MalformedTtlvError> for ErrorKind {
156    fn from(err: MalformedTtlvError) -> Self {
157        Self::MalformedTtlv(err)
158    }
159}
160
161impl From<SerdeError> for ErrorKind {
162    fn from(err: SerdeError) -> Self {
163        Self::SerdeError(err)
164    }
165}
166
167// --- ErrorLocation --------------------------------------------------------------------------------------------------
168
169/// Details about where in the data the error occurred.
170#[derive(Clone, Debug, Default)]
171pub struct ErrorLocation {
172    offset: Option<ByteOffset>,
173    parent_tags: Vec<TtlvTag>,
174    tag: Option<TtlvTag>,
175    r#type: Option<TtlvType>,
176}
177
178impl From<ByteOffset> for ErrorLocation {
179    fn from(offset: ByteOffset) -> Self {
180        Self {
181            offset: Some(offset),
182            ..Default::default()
183        }
184    }
185}
186
187impl From<u8> for ErrorLocation {
188    fn from(offset: u8) -> Self {
189        Self::from(ByteOffset(offset.into()))
190    }
191}
192
193impl From<u16> for ErrorLocation {
194    fn from(offset: u16) -> Self {
195        Self::from(ByteOffset(offset.into()))
196    }
197}
198
199impl From<u32> for ErrorLocation {
200    fn from(offset: u32) -> Self {
201        Self::from(ByteOffset(offset.into()))
202    }
203}
204
205impl From<u64> for ErrorLocation {
206    fn from(offset: u64) -> Self {
207        Self::from(ByteOffset(offset))
208    }
209}
210
211impl From<usize> for ErrorLocation {
212    fn from(value: usize) -> ErrorLocation {
213        match ByteOffset::try_from(value) {
214            Ok(offset) => ErrorLocation::from(offset),
215            Err(_) => ErrorLocation::unknown(),
216        }
217    }
218}
219
220impl<T> From<std::io::Cursor<T>> for ErrorLocation {
221    fn from(cursor: std::io::Cursor<T>) -> Self {
222        Self {
223            offset: Some(cursor.position().into()),
224            ..Default::default()
225        }
226    }
227}
228
229impl<T> From<&std::io::Cursor<T>> for ErrorLocation {
230    fn from(cursor: &std::io::Cursor<T>) -> Self {
231        Self {
232            offset: Some(cursor.position().into()),
233            ..Default::default()
234        }
235    }
236}
237
238impl<T> From<&mut std::io::Cursor<T>> for ErrorLocation {
239    fn from(cursor: &mut std::io::Cursor<T>) -> Self {
240        Self {
241            offset: Some(cursor.position().into()),
242            ..Default::default()
243        }
244    }
245}
246
247impl Display for ErrorLocation {
248    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249        if self.is_unknown() {
250            return f.write_str("Unknown");
251        }
252
253        let mut sep_str = "";
254
255        #[rustfmt::skip]
256        let mut sep = || { let s = sep_str; sep_str = ", "; s };
257
258        if let Some(offset) = self.offset {
259            f.write_fmt(format_args!("{}pos: {} bytes", sep(), *offset))?;
260        }
261        if !self.parent_tags.is_empty() {
262            let mut iter = self.parent_tags.iter();
263            f.write_fmt(format_args!("{}parent tags: {}", sep(), iter.next().unwrap()))?;
264            for tag in iter {
265                f.write_fmt(format_args!(" > {}", tag))?
266            }
267        }
268        if let Some(tag) = self.tag {
269            f.write_fmt(format_args!("{}tag: {}", sep(), tag))?;
270        }
271        if let Some(r#type) = self.r#type {
272            f.write_fmt(format_args!("{}type: {}", sep(), r#type))?;
273        }
274
275        Ok(())
276    }
277}
278
279impl ErrorLocation {
280    pub(crate) fn at(offset: ByteOffset) -> Self {
281        Self {
282            offset: Some(offset),
283            ..Default::default()
284        }
285    }
286
287    // Use `at()` instead. Don't use this if you actually have a relevant byte offset and/or TTLV location for the error.
288    pub(crate) fn unknown() -> Self {
289        Self::default()
290    }
291
292    pub(crate) fn with_offset(mut self, offset: ByteOffset) -> Self {
293        let _ = self.offset.get_or_insert(offset);
294        self
295    }
296
297    pub(crate) fn with_parent_tags(mut self, parent_tags: &[TtlvTag]) -> Self {
298        if self.parent_tags.is_empty() {
299            self.parent_tags.extend(parent_tags);
300        }
301        self
302    }
303
304    pub(crate) fn with_tag(mut self, tag: TtlvTag) -> Self {
305        let _ = self.tag.get_or_insert(tag);
306        self
307    }
308
309    pub(crate) fn with_type(mut self, r#type: TtlvType) -> Self {
310        let _ = self.r#type.get_or_insert(r#type);
311        self
312    }
313
314    pub(crate) fn merge(mut self, loc: ErrorLocation) -> Self {
315        if let Some(offset) = loc.offset {
316            self = self.with_offset(offset);
317        }
318        self = self.with_parent_tags(&loc.parent_tags);
319        if let Some(tag) = loc.tag {
320            self = self.with_tag(tag);
321        }
322        if let Some(r#type) = loc.r#type {
323            self = self.with_type(r#type);
324        }
325        self
326    }
327
328    pub fn is_unknown(&self) -> bool {
329        matches!(
330            (self.offset, self.parent_tags.is_empty(), self.tag, self.r#type),
331            (None, true, None, None)
332        )
333    }
334
335    pub fn offset(&self) -> Option<ByteOffset> {
336        self.offset
337    }
338
339    pub fn parent_tags(&self) -> &[TtlvTag] {
340        &self.parent_tags
341    }
342
343    pub fn tag(&self) -> Option<TtlvTag> {
344        self.tag
345    }
346
347    pub fn r#type(&self) -> Option<TtlvType> {
348        self.r#type
349    }
350}
351
352// --- MalformedTtlvError ---------------------------------------------------------------------------------------------
353
354/// (De)serialization failure due to writing/reading byte values that do not conform to the TTLV specification.
355#[derive(Debug)]
356#[non_exhaustive]
357pub enum MalformedTtlvError {
358    /// The value in the TTLV type byte is not one of the known valid values.
359    InvalidType(u8),
360
361    /// The value in the TTLV length bytes are invalid for the type being read/written.
362    InvalidLength {
363        expected: u32,
364        actual: u32,
365        r#type: TtlvType,
366    },
367
368    /// The value in the TTLV value bytes is not valid for the type being read/written.
369    InvalidValue { r#type: TtlvType },
370
371    /// A TTLV value being read/written is too large for the TTLV Structure that contains it.
372    Overflow { field_end: ByteOffset },
373
374    /// The TTLV field being read/written is out of sequence (e.g. TLVV, VLTL, etc.).
375    UnexpectedTtlvField { expected: FieldType, actual: FieldType },
376
377    /// The TTLV type being read/written is not correct at this location.
378    ///
379    /// For example, all TTLV sequences must start with a TTLV Structure.
380    UnexpectedType { expected: TtlvType, actual: TtlvType },
381
382    /// The TTLV type byte value being read/written is valid but not supported.
383    UnsupportedType(u8),
384
385    /// The length of the TTLV Structure being read/written could not be determined.
386    ///
387    /// For example this can occur when TTLV serialization failed for some reason to return and rewrite the length
388    /// bytes of a TTLV structure once its length was known and this was detected during serialization or later during
389    /// deserialization.
390    UnknownStructureLength,
391}
392
393impl MalformedTtlvError {
394    pub fn overflow<T>(field_end: T) -> Self
395    where
396        ByteOffset: From<T>,
397    {
398        Self::Overflow {
399            field_end: field_end.into(),
400        }
401    }
402}
403
404// --- SerdeError -----------------------------------------------------------------------------------------------------
405
406/// Errors while (de)serializing from/to Rust data structures.
407#[derive(Debug)]
408#[non_exhaustive]
409pub enum SerdeError {
410    /// An enum variant name is neither a hexadecimal string value nor valid matcher syntax.
411    ///
412    /// Valid enum variant names must be set using `#[serde(rename = "...")]` and must either be a hexadecimal string
413    /// value such as `"0x01ABEF"` or must be valid variant matcher syntax such as `"if 0xABCDEF==0x123456"`. See the
414    /// [crate] level documentation for more details.
415    InvalidVariant(&'static str),
416
417    /// An enum variant name is not valid matcher syntax. See the [crate] level documentation for more details.
418    InvalidVariantMatcherSyntax(String),
419
420    /// The `#[serde(rename = "...")]` name assigned to a Rust data type is not a valid TTLV six character hexadecimal
421    /// value such as `0x12ABEF`.
422    InvalidTag(String),
423
424    /// None of the `#[serde(rename = "...")]` named fields in the Rust struct being deserialized into matches the TTLV
425    /// tag value being deserialized.
426    MissingIdentifier,
427
428    /// A problem occurred during (de)serialization that is not described by one of the other [SerdeError] enum
429    /// variants. This primarily occurs when Serde Derive generated code or Serde library code fails internally and
430    /// does not provide a more specific dedicated error type for the situation at hand.
431    Other(String),
432
433    /// The TTLV tag value being deserialized does not match the `#[serde(rename = "...")]` name assigned to any of the
434    /// candidate Rust struct members currently being deserialized into. This can happen when the field is not always
435    /// present in the data stream and so should be wrapped in `Option<...>` in the Rust data structure, or when the
436    /// order of the fields in the Rust structure does not match the order of the fields in the TTLV Structure.
437    UnexpectedTag { expected: TtlvTag, actual: TtlvTag },
438
439    /// The TTLV type of the value being deserialized does not match the type of the Rust data structure field being
440    /// deserialized into.
441    UnexpectedType { expected: TtlvType, actual: TtlvType },
442
443    /// The TTLV type of the value being deserialized is not supported yet by the deserializer.
444    UnsupportedRustType(&'static str),
445}