crabka_protocol/records/
error.rs1use thiserror::Error;
4
5#[derive(Debug, Error)]
6#[non_exhaustive]
7pub enum RecordsError {
8 #[error("buffer too short for batch header (need {needed} more bytes)")]
9 HeaderTooShort { needed: usize },
10
11 #[error("batch magic byte {found} unsupported (only v2 supported)")]
12 UnsupportedMagic { found: i8 },
13
14 #[error("CRC mismatch: expected {expected:#010x}, computed {computed:#010x}")]
15 CrcMismatch { expected: u32, computed: u32 },
16
17 #[error("batch body truncated (need {needed} more bytes)")]
18 BodyTooShort { needed: usize },
19
20 #[error("record parse failed: {0}")]
21 RecordParse(String),
22
23 #[error("compression: {0}")]
24 Compression(#[from] crabka_compression::CompressionError),
25
26 #[error("zerocopy reinterpretation failed")]
27 ZerocopyFailure,
28}
29
30impl From<RecordsError> for crate::ProtocolError {
31 fn from(e: RecordsError) -> Self {
32 crate::ProtocolError::InvalidValue(match e {
33 RecordsError::HeaderTooShort { .. } => "records: header too short",
34 RecordsError::UnsupportedMagic { .. } => "records: unsupported magic",
35 RecordsError::CrcMismatch { .. } => "records: CRC mismatch",
36 RecordsError::BodyTooShort { .. } => "records: body truncated",
37 RecordsError::RecordParse(_) => "records: record parse failed",
38 RecordsError::Compression(_) => "records: compression error",
39 RecordsError::ZerocopyFailure => "records: zerocopy failure",
40 })
41 }
42}
43
44#[cfg(test)]
45mod tests {
46 use assert2::assert;
47
48 use super::*;
49
50 #[test]
51 fn display_messages() {
52 let cases: &[(RecordsError, &str)] = &[
53 (
54 RecordsError::HeaderTooShort { needed: 4 },
55 "buffer too short for batch header",
56 ),
57 (
58 RecordsError::UnsupportedMagic { found: 1 },
59 "batch magic byte 1 unsupported",
60 ),
61 (
62 RecordsError::CrcMismatch {
63 expected: 0xDEAD_BEEF,
64 computed: 0x1234_5678,
65 },
66 "CRC mismatch: expected 0xdeadbeef",
67 ),
68 (
69 RecordsError::BodyTooShort { needed: 17 },
70 "batch body truncated",
71 ),
72 (
73 RecordsError::RecordParse("bad varint".into()),
74 "record parse failed",
75 ),
76 (
77 RecordsError::ZerocopyFailure,
78 "zerocopy reinterpretation failed",
79 ),
80 ];
81 for (err, contains) in cases {
82 assert!(
83 err.to_string().contains(contains),
84 "{err} did not contain {contains:?}",
85 );
86 }
87 }
88
89 #[test]
90 fn into_protocol_error_is_invalid_value() {
91 let e: crate::ProtocolError = RecordsError::UnsupportedMagic { found: 0 }.into();
92 assert!(matches!(e, crate::ProtocolError::InvalidValue(_)));
93 }
94}