Skip to main content

rm_frame/
error.rs

1//! Error types for the binframe crate.
2
3use core::error::Error as StdError;
4use core::fmt::{Display, Formatter, Result as FmtResult};
5
6/// Errors returned by
7///     [`Marshaler::marshal`](crate::Marshaler::marshal),
8///     [`Marshaler::unmarshal`](crate::Marshaler::unmarshal),
9/// and [`RawFrame::unmarshal`](crate::RawFrame::unmarshal).
10#[derive(Debug)]
11#[cfg_attr(feature = "defmt", derive(defmt::Format))]
12pub enum MarshalerError {
13    /// The frame's command ID does not match the expected type.
14    ///
15    /// Returned by
16    ///     [`RawFrame::unmarshal`](crate::RawFrame::unmarshal)
17    /// when [`M::CMD_ID`](crate::Marshaler::CMD_ID) differs from the
18    /// command ID in the decoded frame.
19    InvalidCmdID { expected: u16, found: u16 },
20
21    /// The payload length does not match [`Marshaler::PAYLOAD_SIZE`](crate::Marshaler::PAYLOAD_SIZE).
22    ///
23    /// Returned by
24    ///     [`RawFrame::unmarshal`](crate::RawFrame::unmarshal)
25    /// when the payload size in the frame differs from the size the target type expects.
26    InvalidDataLength { expected: usize, found: usize },
27
28    /// The destination buffer is too small to hold the serialized payload.
29    ///
30    /// `need` is the minimum buffer size required, in bytes.
31    BufferTooSmall { need: usize },
32
33    /// An error specific to the payload type prevented successful marshaling or unmarshaling.
34    ///
35    /// This is a catch-all variant for errors that do not fit into the above categories.
36    /// The inner error type and message are determined by the specific implementation of
37    /// [`Marshaler::marshal`](crate::Marshaler::marshal) or
38    /// [`Marshaler::unmarshal`](crate::Marshaler::unmarshal).
39    Unexpected { code: usize, message: &'static str },
40}
41
42impl From<()> for MarshalerError {
43    fn from(_: ()) -> Self {
44        Self::Unexpected {
45            code: 0,
46            message: "Unit Type Error",
47        }
48    }
49}
50
51impl From<usize> for MarshalerError {
52    fn from(code: usize) -> Self {
53        Self::Unexpected {
54            code,
55            message: "Unexpected Error",
56        }
57    }
58}
59
60impl From<(usize,)> for MarshalerError {
61    fn from((code,): (usize,)) -> Self {
62        Self::Unexpected {
63            code,
64            message: "Unexpected Error",
65        }
66    }
67}
68
69impl From<(&'static str, usize)> for MarshalerError {
70    fn from((message, code): (&'static str, usize)) -> Self {
71        Self::Unexpected { code, message }
72    }
73}
74
75impl From<(usize, &'static str)> for MarshalerError {
76    fn from((code, message): (usize, &'static str)) -> Self {
77        Self::Unexpected { code, message }
78    }
79}
80
81/// Errors returned by [`Messager::pack`](crate::Messager::pack).
82#[derive(Debug)]
83#[cfg_attr(feature = "defmt", derive(defmt::Format))]
84pub enum PackError {
85    /// The destination buffer is too small to hold the complete frame.
86    ///
87    /// `need` is the minimum required size in bytes:
88    /// `5 (header) + 2 (CMD_ID) + PAYLOAD_SIZE + 2 (CRC16)`.
89    BufferTooSmall { need: usize },
90
91    /// The marshaler returned a byte count that does not equal
92    /// [`Marshaler::PAYLOAD_SIZE`](crate::Marshaler::PAYLOAD_SIZE).
93    ///
94    /// This indicates a broken [`Marshaler`](crate::Marshaler) implementation.
95    InvalidPayloadSize { expected: usize, found: usize },
96
97    /// The marshaler returned an error.
98    MarshalerError(MarshalerError),
99}
100
101impl From<MarshalerError> for PackError {
102    fn from(err: MarshalerError) -> Self {
103        Self::MarshalerError(err)
104    }
105}
106
107/// Errors returned by
108///     [`Messager::unpack`](crate::Messager::unpack)
109/// and [`Messager::unmarshal`](crate::Messager::unmarshal).
110#[derive(Debug)]
111#[cfg_attr(feature = "defmt", derive(defmt::Format))]
112pub enum UnPackError {
113    /// The input does not start with the SOF byte (`0xA5`), but a SOF byte
114    /// was found later in the buffer.
115    ///
116    /// `skip` is the byte offset of the first SOF byte found.
117    /// Discard that many bytes from the input, then retry.
118    ReSync { skip: usize },
119
120    /// No SOF byte was found anywhere in the input buffer.
121    ///
122    /// `skip` equals the buffer length.
123    /// Discard the entire buffer and wait for more data before retrying.
124    MissingHeader { skip: usize },
125
126    /// The frame is truncated; more bytes are needed to complete it.
127    ///
128    /// `read` is the number of bytes currently available.
129    /// Keep the existing bytes and wait for more data before retrying.
130    UnexpectedEnd { read: usize },
131
132    /// CRC validation failed (header CRC8 or frame CRC16).
133    ///
134    /// `at` is the cursor position when the failure was detected.
135    /// Call [`UnPackError::skip`] to determine how many bytes to discard.
136    InvalidChecksum { at: usize },
137
138    /// The payload could not be decoded into the target type.
139    ///
140    /// Wraps a [`MarshalerError`] from [`RawFrame::unmarshal`](crate::RawFrame::unmarshal).
141    MarshalerError(MarshalerError),
142}
143
144impl UnPackError {
145    /// Returns the number of bytes to discard before retrying a parse.
146    ///
147    /// Use this when processing a continuous byte stream to advance the read
148    /// position past invalid or incomplete data:
149    ///
150    /// | Variant | Returned value | Action |
151    /// |---------|----------------|--------|
152    /// | [`ReSync`](Self::ReSync) | offset of next SOF | discard bytes, retry |
153    /// | [`MissingHeader`](Self::MissingHeader) | buffer length | discard all, wait for data |
154    /// | [`UnexpectedEnd`](Self::UnexpectedEnd) | `0` | wait for more data at current position |
155    /// | [`InvalidChecksum`](Self::InvalidChecksum) | cursor at failure | discard frame, retry |
156    /// | [`MarshalerError`](Self::MarshalerError) | `0` | frame was consumed; handle decode error |
157    pub fn skip(&self) -> usize {
158        match self {
159            Self::MissingHeader { skip } => *skip,
160            Self::ReSync { skip } => *skip,
161            Self::UnexpectedEnd { .. } => 0,
162            Self::InvalidChecksum { at } => *at,
163            Self::MarshalerError(_) => 0,
164        }
165    }
166}
167
168impl From<MarshalerError> for UnPackError {
169    fn from(err: MarshalerError) -> Self {
170        Self::MarshalerError(err)
171    }
172}
173
174impl StdError for MarshalerError {}
175impl Display for MarshalerError {
176    fn fmt(&self, f: &mut Formatter) -> FmtResult {
177        match self {
178            Self::InvalidCmdID { expected, found } => write!(
179                f,
180                "Invalid Command ID: expected {}, found {}",
181                expected, found
182            ),
183            Self::InvalidDataLength { expected, found } => {
184                write!(
185                    f,
186                    "Invalid Data Length: expected {} bytes, found {} bytes",
187                    expected, found
188                )
189            }
190            Self::BufferTooSmall { need } => {
191                write!(f, "Buffer too Small: need {} bytes", need)
192            }
193            Self::Unexpected { code, message } => {
194                write!(
195                    f,
196                    "Unexpected Marshaler Error: code {}, message: {}",
197                    code, message
198                )
199            }
200        }
201    }
202}
203
204impl Display for PackError {
205    fn fmt(&self, f: &mut Formatter) -> FmtResult {
206        match self {
207            Self::BufferTooSmall { need } => {
208                write!(f, "Buffer too Small: need {} bytes", need)
209            }
210            Self::InvalidPayloadSize { expected, found } => {
211                write!(
212                    f,
213                    "Invalid Payload Size: expected {}, found {}",
214                    expected, found
215                )
216            }
217            Self::MarshalerError(e) => {
218                write!(f, "Marshaler Error: {}", e)
219            }
220        }
221    }
222}
223impl StdError for PackError {
224    fn source(&self) -> Option<&(dyn StdError + 'static)> {
225        match self {
226            Self::MarshalerError(e) => Some(e),
227            _ => None,
228        }
229    }
230}
231
232impl Display for UnPackError {
233    fn fmt(&self, f: &mut Formatter) -> FmtResult {
234        match self {
235            Self::ReSync { skip } => write!(f, "ReSync Needed: skip {} bytes", skip),
236            Self::MissingHeader { skip } => write!(f, "Missing Header: skip {} bytes", skip),
237            Self::UnexpectedEnd { read } => write!(f, "Unexpected End: read {} bytes", read),
238            Self::InvalidChecksum { at } => write!(f, "Invalid Checksum: at {} bytes", at),
239            Self::MarshalerError(e) => write!(f, "Marshaler Error: {}", e),
240        }
241    }
242}
243impl StdError for UnPackError {
244    fn source(&self) -> Option<&(dyn StdError + 'static)> {
245        match self {
246            Self::MarshalerError(e) => Some(e),
247            _ => None,
248        }
249    }
250}