1use std::fmt;
4
5#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum DecodeError {
11 Truncated { needed: usize, available: usize },
13 ArrayTooLarge { kind: &'static str, count: usize, limit: usize },
15 CountExceedsBuffer { count: usize, min_bytes: usize, available: usize },
18 MessageTooLarge { total: usize, limit: usize },
20 UnexpectedSegment { flags: u8 },
23 SegmentInterrupted { expected: u8, got: u8 },
25 SegmentCommandMismatch { expected: u8, got: u8 },
27 UnknownTypeTag(u8),
29 UnresolvedTypeId(u16),
32 UnknownUnionSelector { selector: usize, len: usize },
34 Malformed(&'static str),
36}
37
38impl fmt::Display for DecodeError {
39 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
40 match self {
41 Self::Truncated { needed, available } => {
42 write!(f, "truncated: need {needed} bytes, {available} available")
43 }
44 Self::ArrayTooLarge { kind, count, limit } => {
45 write!(f, "{kind} of {count} elements exceeds the limit of {limit}")
46 }
47 Self::CountExceedsBuffer { count, min_bytes, available } => write!(
48 f,
49 "element count {count} needs at least {min_bytes} bytes, {available} available"
50 ),
51 Self::MessageTooLarge { total, limit } => {
52 write!(f, "reassembled message of {total} bytes exceeds the limit of {limit}")
53 }
54 Self::UnexpectedSegment { flags } => {
55 write!(f, "unexpected segment, flags 0x{flags:02x}")
56 }
57 Self::SegmentInterrupted { expected, got } => write!(
58 f,
59 "reassembly of command {expected} interrupted by unsegmented command {got}"
60 ),
61 Self::SegmentCommandMismatch { expected, got } => {
62 write!(f, "segment command mismatch: expected {expected}, got {got}")
63 }
64 Self::UnknownTypeTag(tag) => write!(f, "unknown type tag 0x{tag:02x}"),
65 Self::UnresolvedTypeId(id) => {
66 write!(f, "unresolved introspection id {id}: decoder not reused across connection?")
67 }
68 Self::UnknownUnionSelector { selector, len } => {
69 write!(f, "union selector {selector} out of range for {len} fields")
70 }
71 Self::Malformed(what) => write!(f, "malformed: {what}"),
72 }
73 }
74}
75
76impl std::error::Error for DecodeError {}
77
78pub type DecodeResult<T> = Result<T, DecodeError>;
80
81#[cfg(test)]
82mod tests {
83 use super::*;
84
85 #[test]
86 fn display_names_the_offending_values() {
87 let e = DecodeError::ArrayTooLarge { kind: "string array", count: 900_000, limit: 65_536 };
88 assert_eq!(
89 e.to_string(),
90 "string array of 900000 elements exceeds the limit of 65536"
91 );
92 }
93
94 #[test]
95 fn errors_compare_by_value() {
96 let a = DecodeError::Truncated { needed: 12, available: 4 };
97 let b = DecodeError::Truncated { needed: 12, available: 4 };
98 let c = DecodeError::Truncated { needed: 12, available: 5 };
99 assert_eq!(a, b);
100 assert_ne!(a, c);
101 }
102
103 #[test]
104 fn implements_std_error() {
105 fn assert_error<E: std::error::Error>(_: &E) {}
106 assert_error(&DecodeError::Malformed("bad tag"));
107 }
108}