1use core::fmt;
35
36#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub struct BufferTooShort {
39 pub need: usize,
41 pub have: usize,
43 pub what: &'static str,
45}
46
47impl fmt::Display for BufferTooShort {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 write!(
50 f,
51 "buffer too short: need {} bytes, have {} (while parsing {})",
52 self.need, self.have, self.what
53 )
54 }
55}
56
57impl core::error::Error for BufferTooShort {}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
61pub struct OutputBufferTooSmall {
62 pub need: usize,
64 pub have: usize,
66}
67
68impl fmt::Display for OutputBufferTooSmall {
69 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
70 write!(
71 f,
72 "output buffer too small: need {}, have {}",
73 self.need, self.have
74 )
75 }
76}
77
78impl core::error::Error for OutputBufferTooSmall {}
79
80#[derive(Debug, Clone, Copy, PartialEq, Eq)]
82pub struct FieldOverflow {
83 pub field: &'static str,
85 pub value: u64,
87 pub max: u64,
89}
90
91impl fmt::Display for FieldOverflow {
92 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
93 write!(
94 f,
95 "{} = {} exceeds the field maximum {}",
96 self.field, self.value, self.max
97 )
98 }
99}
100
101impl core::error::Error for FieldOverflow {}
102
103#[derive(Debug, Clone, Copy, PartialEq, Eq)]
105pub struct CrcMismatch {
106 pub what: &'static str,
108 pub computed: u32,
110 pub expected: u32,
112}
113
114impl fmt::Display for CrcMismatch {
115 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
116 write!(
117 f,
118 "{} CRC-32 mismatch: computed {:#010x}, expected {:#010x}",
119 self.what, self.computed, self.expected
120 )
121 }
122}
123
124impl core::error::Error for CrcMismatch {}
125
126#[derive(Debug, Clone, Copy, PartialEq, Eq)]
131pub struct InvalidSync {
132 pub what: &'static str,
134 pub expected: u32,
136 pub found: u32,
138}
139
140impl fmt::Display for InvalidSync {
141 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
142 write!(
143 f,
144 "invalid {}: expected {:#x}, got {:#x}",
145 self.what, self.expected, self.found
146 )
147 }
148}
149
150impl core::error::Error for InvalidSync {}
151
152#[derive(Debug, Clone, Copy, PartialEq, Eq)]
155pub struct ReservedBits {
156 pub field: &'static str,
158 pub expected: u64,
160 pub found: u64,
162}
163
164impl fmt::Display for ReservedBits {
165 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166 write!(
167 f,
168 "reserved field {} must be {:#x}, found {:#x}",
169 self.field, self.expected, self.found
170 )
171 }
172}
173
174impl core::error::Error for ReservedBits {}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
178pub struct InvalidValue {
179 pub field: &'static str,
181 pub value: u64,
183 pub reason: &'static str,
185}
186
187impl fmt::Display for InvalidValue {
188 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189 write!(
190 f,
191 "field {} value {} invalid: {}",
192 self.field, self.value, self.reason
193 )
194 }
195}
196
197impl core::error::Error for InvalidValue {}
198
199#[derive(Debug, Clone, Copy, PartialEq, Eq)]
202pub struct InvalidField {
203 pub field: &'static str,
205 pub reason: &'static str,
207}
208
209impl fmt::Display for InvalidField {
210 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
211 write!(f, "invalid field {}: {}", self.field, self.reason)
212 }
213}
214
215impl core::error::Error for InvalidField {}
216
217#[derive(Debug, Clone, Copy, PartialEq, Eq)]
219pub struct UnsupportedVersion {
220 pub what: &'static str,
222 pub found: u8,
224}
225
226impl fmt::Display for UnsupportedVersion {
227 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228 write!(f, "unsupported {} version {}", self.what, self.found)
229 }
230}
231
232impl core::error::Error for UnsupportedVersion {}
233
234#[derive(Debug, Clone, Copy, PartialEq, Eq)]
237pub struct LengthMismatch {
238 pub what: &'static str,
240 pub declared: usize,
242 pub actual: usize,
244}
245
246impl fmt::Display for LengthMismatch {
247 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
248 write!(
249 f,
250 "length mismatch for {}: declared {}, actual {}",
251 self.what, self.declared, self.actual
252 )
253 }
254}
255
256impl core::error::Error for LengthMismatch {}
257
258#[cfg(test)]
259mod tests {
260 extern crate alloc;
261 use super::*;
262 use alloc::string::ToString;
263
264 #[test]
265 fn display_messages() {
266 assert_eq!(
267 BufferTooShort {
268 need: 4,
269 have: 1,
270 what: "PAT"
271 }
272 .to_string(),
273 "buffer too short: need 4 bytes, have 1 (while parsing PAT)"
274 );
275 assert_eq!(
276 OutputBufferTooSmall { need: 4, have: 1 }.to_string(),
277 "output buffer too small: need 4, have 1"
278 );
279 assert_eq!(
280 FieldOverflow {
281 field: "section_length",
282 value: 5000,
283 max: 4095
284 }
285 .to_string(),
286 "section_length = 5000 exceeds the field maximum 4095"
287 );
288 assert_eq!(
289 CrcMismatch {
290 what: "PSM",
291 computed: 0xAB,
292 expected: 0xCD
293 }
294 .to_string(),
295 "PSM CRC-32 mismatch: computed 0x000000ab, expected 0x000000cd"
296 );
297 assert_eq!(
298 InvalidSync {
299 what: "TS sync byte",
300 expected: 0x47,
301 found: 0
302 }
303 .to_string(),
304 "invalid TS sync byte: expected 0x47, got 0x0"
305 );
306 assert_eq!(
307 ReservedBits {
308 field: "reserved",
309 expected: 0x7,
310 found: 0x2
311 }
312 .to_string(),
313 "reserved field reserved must be 0x7, found 0x2"
314 );
315 assert_eq!(
316 InvalidValue {
317 field: "version",
318 value: 9,
319 reason: "out of range"
320 }
321 .to_string(),
322 "field version value 9 invalid: out of range"
323 );
324 assert_eq!(
325 InvalidField {
326 field: "pts",
327 reason: "missing"
328 }
329 .to_string(),
330 "invalid field pts: missing"
331 );
332 assert_eq!(
333 UnsupportedVersion {
334 what: "RTP",
335 found: 1
336 }
337 .to_string(),
338 "unsupported RTP version 1"
339 );
340 assert_eq!(
341 LengthMismatch {
342 what: "APDU",
343 declared: 9,
344 actual: 7
345 }
346 .to_string(),
347 "length mismatch for APDU: declared 9, actual 7"
348 );
349 }
350
351 #[test]
352 fn equality_distinguishes_every_field() {
353 let a = CrcMismatch {
354 what: "PSM",
355 computed: 1,
356 expected: 2,
357 };
358 assert_eq!(a, a);
359 assert_ne!(a, CrcMismatch { what: "SNDU", ..a });
360 assert_ne!(a, CrcMismatch { computed: 3, ..a });
361 assert_ne!(a, CrcMismatch { expected: 3, ..a });
362 let b = LengthMismatch {
363 what: "x",
364 declared: 1,
365 actual: 2,
366 };
367 assert_ne!(b, LengthMismatch { declared: 2, ..b });
368 assert_ne!(b, LengthMismatch { actual: 1, ..b });
369 }
370
371 #[test]
372 fn len_reexports_are_the_same_types() {
373 let e: BufferTooShort = crate::len::need_in(&[], 1, "x").unwrap_err();
374 assert_eq!(
375 e,
376 BufferTooShort {
377 need: 1,
378 have: 0,
379 what: "x"
380 }
381 );
382 let o: OutputBufferTooSmall = crate::len::need_out(&[], 1).unwrap_err();
383 assert_eq!(o, OutputBufferTooSmall { need: 1, have: 0 });
384 let _: FieldOverflow = crate::len::fit_bits(256, 8, "f").unwrap_err();
385 }
386
387 #[test]
388 fn kinds_are_core_errors() {
389 fn is_error<E: core::error::Error + Copy + Send + Sync + 'static>() {}
390 is_error::<BufferTooShort>();
391 is_error::<CrcMismatch>();
392 is_error::<InvalidSync>();
393 is_error::<ReservedBits>();
394 is_error::<InvalidValue>();
395 is_error::<InvalidField>();
396 is_error::<UnsupportedVersion>();
397 is_error::<LengthMismatch>();
398 }
399}