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}