1use std::fmt;
4
5pub type BitResult<T> = Result<T, BitError>;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
10pub enum BitError {
11 UnexpectedEof {
13 requested: usize,
15 available: usize,
17 },
18
19 WriteOverflow {
21 attempted: usize,
23 available: usize,
25 },
26
27 InvalidBitCount {
29 bits: u8,
31 max_bits: u8,
33 },
34
35 ValueOutOfRange {
37 value: u64,
39 bits: u8,
41 },
42
43 InvalidVarint,
45
46 MisalignedAccess {
48 bit_position: usize,
50 },
51}
52
53impl fmt::Display for BitError {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 match self {
56 Self::UnexpectedEof {
57 requested,
58 available,
59 } => {
60 write!(
61 f,
62 "unexpected EOF: requested {requested} bits, {available} available"
63 )
64 }
65 Self::WriteOverflow {
66 attempted,
67 available,
68 } => {
69 write!(
70 f,
71 "write overflow: attempted {attempted} bits, {available} available"
72 )
73 }
74 Self::InvalidBitCount { bits, max_bits } => {
75 write!(f, "invalid bit count {bits}, maximum allowed is {max_bits}")
76 }
77 Self::ValueOutOfRange { value, bits } => {
78 write!(f, "value {value} cannot be represented in {bits} bits")
79 }
80 Self::InvalidVarint => {
81 write!(f, "invalid varint encoding")
82 }
83 Self::MisalignedAccess { bit_position } => {
84 write!(f, "misaligned access at bit position {bit_position}")
85 }
86 }
87 }
88}
89
90impl std::error::Error for BitError {}
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 #[test]
97 fn error_display_unexpected_eof() {
98 let err = BitError::UnexpectedEof {
99 requested: 8,
100 available: 3,
101 };
102 let msg = err.to_string();
103 assert!(msg.contains("8"), "should mention requested bits");
104 assert!(msg.contains("3"), "should mention available bits");
105 assert!(msg.contains("EOF"), "should mention EOF");
106 }
107
108 #[test]
109 fn error_display_write_overflow() {
110 let err = BitError::WriteOverflow {
111 attempted: 100,
112 available: 64,
113 };
114 let msg = err.to_string();
115 assert!(msg.contains("100"), "should mention attempted bits");
116 assert!(msg.contains("64"), "should mention available bits");
117 assert!(msg.contains("overflow"), "should mention overflow");
118 }
119
120 #[test]
121 fn error_display_invalid_bit_count() {
122 let err = BitError::InvalidBitCount {
123 bits: 128,
124 max_bits: 64,
125 };
126 let msg = err.to_string();
127 assert!(msg.contains("128"), "should mention invalid count");
128 assert!(msg.contains("64"), "should mention maximum");
129 }
130
131 #[test]
132 fn error_display_value_out_of_range() {
133 let err = BitError::ValueOutOfRange {
134 value: 256,
135 bits: 8,
136 };
137 let msg = err.to_string();
138 assert!(msg.contains("256"), "should mention the value");
139 assert!(msg.contains("8"), "should mention bit count");
140 }
141
142 #[test]
143 fn error_display_invalid_varint() {
144 let err = BitError::InvalidVarint;
145 assert!(err.to_string().contains("varint"));
146 }
147
148 #[test]
149 fn error_display_misaligned_access() {
150 let err = BitError::MisalignedAccess { bit_position: 3 };
151 let msg = err.to_string();
152 assert!(msg.contains("3"), "should mention bit position");
153 assert!(msg.contains("misaligned"));
154 }
155
156 #[test]
157 fn error_equality() {
158 let err1 = BitError::UnexpectedEof {
159 requested: 8,
160 available: 3,
161 };
162 let err2 = BitError::UnexpectedEof {
163 requested: 8,
164 available: 3,
165 };
166 let err3 = BitError::UnexpectedEof {
167 requested: 8,
168 available: 4,
169 };
170 assert_eq!(err1, err2);
171 assert_ne!(err1, err3);
172 }
173
174 #[test]
175 fn error_clone() {
176 let err = BitError::InvalidBitCount {
177 bits: 65,
178 max_bits: 64,
179 };
180 let cloned = err.clone();
181 assert_eq!(err, cloned);
182 }
183
184 #[test]
185 fn error_debug() {
186 let err = BitError::UnexpectedEof {
187 requested: 1,
188 available: 0,
189 };
190 let debug = format!("{err:?}");
191 assert!(debug.contains("UnexpectedEof"));
192 }
193
194 #[test]
195 fn error_is_std_error() {
196 fn assert_error<E: std::error::Error>() {}
197 assert_error::<BitError>();
198 }
199}