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