1use std::fmt;
4
5pub type WireResult<T> = Result<T, DecodeError>;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10#[non_exhaustive]
11pub enum DecodeError {
12 PacketTooSmall { actual: usize, required: usize },
14
15 InvalidMagic { found: u32 },
17
18 UnsupportedVersion { found: u16 },
20
21 InvalidFlags { flags: u16 },
23
24 InvalidBaselineTick { baseline_tick: u32, flags: u16 },
26
27 PayloadLengthMismatch { header_len: u32, actual_len: usize },
29
30 UnknownSectionTag { tag: u8 },
32
33 LimitsExceeded {
35 kind: LimitKind,
36 limit: usize,
37 actual: usize,
38 },
39
40 SectionFraming(SectionFramingError),
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq)]
46pub enum LimitKind {
47 PacketBytes,
48 SectionCount,
49 SectionLength,
50}
51
52#[derive(Debug, Clone, PartialEq, Eq)]
54pub enum SectionFramingError {
55 InvalidVarint,
56 LengthOverflow { value: u64 },
57 Truncated { needed: usize, available: usize },
58}
59
60#[derive(Debug, Clone, PartialEq, Eq)]
62pub enum EncodeError {
63 BufferTooSmall { needed: usize, available: usize },
64 LengthOverflow { length: usize },
65}
66
67impl fmt::Display for DecodeError {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 match self {
70 Self::PacketTooSmall { actual, required } => {
71 write!(
72 f,
73 "packet too small: {actual} bytes, need at least {required}"
74 )
75 }
76 Self::InvalidMagic { found } => {
77 write!(f, "invalid magic number: 0x{found:08X}")
78 }
79 Self::UnsupportedVersion { found } => {
80 write!(f, "unsupported wire version: {found}")
81 }
82 Self::InvalidFlags { flags } => {
83 write!(f, "invalid flags: 0x{flags:04X}")
84 }
85 Self::InvalidBaselineTick {
86 baseline_tick,
87 flags,
88 } => {
89 write!(
90 f,
91 "invalid baseline tick {baseline_tick} for flags 0x{flags:04X}"
92 )
93 }
94 Self::PayloadLengthMismatch {
95 header_len,
96 actual_len,
97 } => {
98 write!(
99 f,
100 "payload length mismatch: header {header_len} bytes but {actual_len} available"
101 )
102 }
103 Self::UnknownSectionTag { tag } => {
104 write!(f, "unknown section tag: {tag}")
105 }
106 Self::LimitsExceeded {
107 kind,
108 limit,
109 actual,
110 } => {
111 write!(f, "{kind} limit exceeded: {actual} > {limit}")
112 }
113 Self::SectionFraming(err) => write!(f, "section framing error: {err}"),
114 }
115 }
116}
117
118impl fmt::Display for LimitKind {
119 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
120 let name = match self {
121 Self::PacketBytes => "packet bytes",
122 Self::SectionCount => "section count",
123 Self::SectionLength => "section length",
124 };
125 write!(f, "{name}")
126 }
127}
128
129impl fmt::Display for SectionFramingError {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 match self {
132 Self::InvalidVarint => write!(f, "invalid varint"),
133 Self::LengthOverflow { value } => write!(f, "length overflow: {value}"),
134 Self::Truncated { needed, available } => {
135 write!(
136 f,
137 "truncated section: need {needed} bytes, have {available}"
138 )
139 }
140 }
141 }
142}
143
144impl fmt::Display for EncodeError {
145 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
146 match self {
147 Self::BufferTooSmall { needed, available } => {
148 write!(f, "buffer too small: need {needed}, have {available}")
149 }
150 Self::LengthOverflow { length } => {
151 write!(f, "length overflow: {length}")
152 }
153 }
154 }
155}
156
157impl std::error::Error for DecodeError {}
158
159impl std::error::Error for EncodeError {}
160
161#[cfg(test)]
162mod tests {
163 use super::*;
164
165 #[test]
166 fn decode_error_display_invalid_magic() {
167 let err = DecodeError::InvalidMagic { found: 0xDEAD_BEEF };
168 let msg = err.to_string();
169 assert!(msg.contains("DEADBEEF"));
170 }
171
172 #[test]
173 fn decode_error_display_limits_exceeded() {
174 let err = DecodeError::LimitsExceeded {
175 kind: LimitKind::SectionCount,
176 limit: 4,
177 actual: 10,
178 };
179 let msg = err.to_string();
180 assert!(msg.contains("section count"));
181 assert!(msg.contains("10"));
182 }
183
184 #[test]
185 fn section_framing_display() {
186 let err = SectionFramingError::Truncated {
187 needed: 10,
188 available: 4,
189 };
190 let msg = err.to_string();
191 assert!(msg.contains("truncated"));
192 assert!(msg.contains("10"));
193 }
194
195 #[test]
196 fn encode_error_display() {
197 let err = EncodeError::BufferTooSmall {
198 needed: 10,
199 available: 4,
200 };
201 let msg = err.to_string();
202 assert!(msg.contains("buffer too small"));
203 }
204}