1use {
40 bitvec::prelude::*,
41 num_derive::{FromPrimitive, ToPrimitive},
42 num_traits::FromPrimitive,
43};
44
45const VERSION_BYTE_LEN: usize = 1;
46const LENGTH_PREFIX_LEN: usize = 2;
47const HEADER_LEN: usize = VERSION_BYTE_LEN + LENGTH_PREFIX_LEN;
48
49#[derive(Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)]
51#[repr(u8)]
52pub enum Version {
53 Base2 = 0,
54 Base3 = 1,
55}
56
57#[derive(Debug, PartialEq, Eq)]
59pub enum EncodeError {
60 MismatchedLengths,
62 InvalidBitCombination,
64 LengthExceedsLimit,
66 ArithmeticOverflow,
68}
69
70const BASE3_SYMBOLS_PER_BYTE: usize = 5;
72
73pub fn encode_base2(bit_vec: &BitVec<u8, Lsb0>) -> Result<Vec<u8>, EncodeError> {
77 let num_bits = bit_vec.len();
78 if num_bits > u16::MAX as usize {
79 return Err(EncodeError::LengthExceedsLimit);
80 }
81
82 let raw_slice = bit_vec.as_raw_slice();
83 let capacity = HEADER_LEN
84 .checked_add(raw_slice.len())
85 .ok_or(EncodeError::ArithmeticOverflow)?;
86 let mut result = Vec::with_capacity(capacity);
87 result.push(Version::Base2 as u8);
88 result.extend_from_slice(&(num_bits as u16).to_le_bytes());
89 result.extend_from_slice(raw_slice);
90
91 Ok(result)
92}
93
94pub fn encode_base3(
100 bit_vec_base: &BitVec<u8, Lsb0>,
101 bit_vec_fallback: &BitVec<u8, Lsb0>,
102) -> Result<Vec<u8>, EncodeError> {
103 if bit_vec_base.len() != bit_vec_fallback.len() {
104 return Err(EncodeError::MismatchedLengths);
105 }
106 let num_bits = bit_vec_base.len();
107 if num_bits > u16::MAX as usize {
108 return Err(EncodeError::LengthExceedsLimit);
109 }
110
111 let base_bytes = bit_vec_base.as_raw_slice();
112 let fallback_bytes = bit_vec_fallback.as_raw_slice();
113
114 let num_chunks = num_bits.div_ceil(BASE3_SYMBOLS_PER_BYTE);
115 let capacity = HEADER_LEN
116 .checked_add(num_chunks)
117 .ok_or(EncodeError::ArithmeticOverflow)?;
118 let mut result = Vec::with_capacity(capacity);
119
120 result.push(Version::Base3 as u8);
121 result.extend_from_slice(&(num_bits as u16).to_le_bytes());
122
123 for chunk_index in 0..num_chunks {
124 let mut block_num: u8 = 0;
125 let start_bit = chunk_index
126 .checked_mul(BASE3_SYMBOLS_PER_BYTE)
127 .ok_or(EncodeError::ArithmeticOverflow)?;
128 let end_bit = start_bit
129 .checked_add(BASE3_SYMBOLS_PER_BYTE)
130 .ok_or(EncodeError::ArithmeticOverflow)?
131 .min(num_bits);
132
133 for i in (start_bit..end_bit).rev() {
135 let byte_idx = i / 8;
136 let bit_idx = i % 8;
137
138 let base_bit = (base_bytes.get(byte_idx).unwrap_or(&0) >> bit_idx) & 1 == 1;
139 let fallback_bit = (fallback_bytes.get(byte_idx).unwrap_or(&0) >> bit_idx) & 1 == 1;
140
141 let chunk_num = match (base_bit, fallback_bit) {
142 (false, false) => 0u8,
143 (true, false) => 1u8,
144 (false, true) => 2u8,
145 (true, true) => return Err(EncodeError::InvalidBitCombination),
146 };
147
148 block_num = block_num
149 .checked_mul(3)
150 .and_then(|n| n.checked_add(chunk_num))
151 .ok_or(EncodeError::ArithmeticOverflow)?;
152 }
153 result.push(block_num);
154 }
155 Ok(result)
156}
157
158#[derive(Debug, PartialEq, Eq)]
160pub enum Decoded {
161 Base2(BitVec<u8, Lsb0>),
163 Base3(BitVec<u8, Lsb0>, BitVec<u8, Lsb0>),
165}
166
167#[derive(Debug, PartialEq, Eq)]
169pub enum DecodeError {
170 InputTooShort,
172 UnsupportedEncoding,
174 CorruptDataPayload,
176 ArithmeticOverflow,
178}
179
180pub fn decode(bytes: &[u8], max_len: usize) -> Result<Decoded, DecodeError> {
185 if bytes.len() < 3 {
186 return Err(DecodeError::InputTooShort);
188 }
189
190 let version_byte = bytes[0];
191 let version = Version::from_u8(version_byte).ok_or(DecodeError::UnsupportedEncoding)?;
192
193 let mut len_arr = [0u8; 2];
194 len_arr.copy_from_slice(&bytes[1..3]);
195 let total_bits = u16::from_le_bytes(len_arr) as usize;
196
197 if total_bits > max_len {
198 return Err(DecodeError::CorruptDataPayload);
199 }
200
201 let data_bytes = &bytes[3..];
202
203 match version {
204 Version::Base2 => decode_impl_base2(data_bytes, total_bits),
205 Version::Base3 => decode_impl_base3(data_bytes, total_bits),
206 }
207}
208
209fn decode_impl_base2(data_bytes: &[u8], total_bits: usize) -> Result<Decoded, DecodeError> {
211 let expected_byte_len = total_bits.div_ceil(8);
212 if data_bytes.len() != expected_byte_len {
213 return Err(DecodeError::CorruptDataPayload);
214 }
215
216 let mut bit_vec = BitVec::from_slice(data_bytes);
217 bit_vec.truncate(total_bits);
218
219 Ok(Decoded::Base2(bit_vec))
220}
221
222fn decode_impl_base3(data_bytes: &[u8], total_bits: usize) -> Result<Decoded, DecodeError> {
224 let expected_num_chunks = total_bits.div_ceil(BASE3_SYMBOLS_PER_BYTE);
225
226 if data_bytes.len() != expected_num_chunks {
227 return Err(DecodeError::CorruptDataPayload);
228 }
229
230 let decoded_byte_len = total_bits.div_ceil(8);
231 let mut base_bytes = vec![0u8; decoded_byte_len];
232 let mut fallback_bytes = vec![0u8; decoded_byte_len];
233
234 for (chunk_index, &block_byte) in data_bytes.iter().enumerate() {
235 let mut block_num = block_byte;
236 let start_bit = chunk_index
237 .checked_mul(BASE3_SYMBOLS_PER_BYTE)
238 .ok_or(DecodeError::ArithmeticOverflow)?;
239 let end_bit = start_bit
240 .checked_add(BASE3_SYMBOLS_PER_BYTE)
241 .ok_or(DecodeError::ArithmeticOverflow)?
242 .min(total_bits);
243
244 for bit_index in start_bit..end_bit {
245 let remainder = block_num % 3;
246 block_num /= 3;
247
248 let byte_idx = bit_index / 8;
249 let bit_idx = bit_index % 8;
250
251 let (base_bit, fallback_bit) = match remainder {
252 0 => (false, false),
253 1 => (true, false),
254 2 => (false, true),
255 _ => unreachable!(), };
257
258 if base_bit {
259 base_bytes[byte_idx] |= 1 << bit_idx;
260 }
261 if fallback_bit {
262 fallback_bytes[byte_idx] |= 1 << bit_idx;
263 }
264 }
265 }
266
267 let mut base_vec = BitVec::from_vec(base_bytes);
268 base_vec.truncate(total_bits);
269 let mut fallback_vec = BitVec::from_vec(fallback_bytes);
270 fallback_vec.truncate(total_bits);
271
272 Ok(Decoded::Base3(base_vec, fallback_vec))
273}
274
275#[cfg(test)]
276mod tests {
277 use super::*;
278
279 fn create_base3_test_data(len: usize) -> (BitVec<u8, Lsb0>, BitVec<u8, Lsb0>) {
280 let mut base = BitVec::with_capacity(len);
281 let mut fallback = BitVec::with_capacity(len);
282 for i in 0..len {
283 match i % 3 {
284 0 => {
285 base.push(false);
287 fallback.push(false);
288 }
289 1 => {
290 base.push(true);
292 fallback.push(false);
293 }
294 _ => {
295 base.push(false);
297 fallback.push(true);
298 }
299 }
300 }
301 (base, fallback)
302 }
303
304 #[test]
305 fn test_base2_round_trip() {
306 let original = bitvec![u8, Lsb0; 0, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1];
307 let original_len = original.len();
308 let encoded = encode_base2(&original).unwrap();
309
310 assert_eq!(encoded[0], Version::Base2 as u8); assert_eq!(
313 u16::from_le_bytes(encoded[1..3].try_into().unwrap()),
314 original_len as u16
315 );
316
317 let decoded = decode(&encoded, original_len).unwrap();
318 if let Decoded::Base2(decoded_vec) = decoded {
319 assert_eq!(original, decoded_vec);
320 } else {
321 panic!("Decoded into the wrong type");
322 }
323 }
324
325 #[test]
326 fn test_base2_empty() {
327 let original = BitVec::<u8, Lsb0>::new();
328 let encoded = encode_base2(&original).unwrap();
329 assert_eq!(encoded, vec![Version::Base2 as u8, 0, 0]);
330 let decoded = decode(&encoded, 0).unwrap();
331 assert_eq!(decoded, Decoded::Base2(original));
332 }
333
334 #[test]
335 fn test_base3_round_trip() {
336 let (base, fallback) = create_base3_test_data(23); let original_len = base.len();
338 let encoded = encode_base3(&base, &fallback).unwrap();
339
340 assert_eq!(encoded[0], Version::Base3 as u8); assert_eq!(
343 u16::from_le_bytes(encoded[1..3].try_into().unwrap()),
344 original_len as u16
345 );
346
347 let decoded = decode(&encoded, original_len).unwrap();
348 if let Decoded::Base3(decoded_base, decoded_fallback) = decoded {
349 assert_eq!(base, decoded_base);
350 assert_eq!(fallback, decoded_fallback);
351 } else {
352 panic!("Decoded into the wrong type");
353 }
354 }
355
356 #[test]
357 fn test_base3_exact_bytes() {
358 let (base, fallback) = create_base3_test_data(10); let encoded = encode_base3(&base, &fallback).unwrap();
360 let decoded = decode(&encoded, 10).unwrap();
361 assert_eq!(decoded, Decoded::Base3(base, fallback));
362 }
363
364 #[test]
365 fn test_base3_empty() {
366 let (base, fallback) = create_base3_test_data(0);
367 let encoded = encode_base3(&base, &fallback).unwrap();
368 assert_eq!(encoded, vec![Version::Base3 as u8, 0, 0]);
369 let decoded = decode(&encoded, 0).unwrap();
370 assert_eq!(decoded, Decoded::Base3(base, fallback));
371 }
372
373 #[test]
374 fn test_encode_base3_invalid_combination() {
375 let base = bitvec![u8, Lsb0; 0, 1];
376 let fallback = bitvec![u8, Lsb0; 0, 1];
377 let result = encode_base3(&base, &fallback);
378 assert_eq!(result, Err(EncodeError::InvalidBitCombination));
379 }
380
381 #[test]
382 fn test_encode_length_limit() {
383 let long_vec = BitVec::repeat(false, (u16::MAX as usize) + 1);
384 let result = encode_base2(&long_vec);
385 assert_eq!(result, Err(EncodeError::LengthExceedsLimit));
386 }
387
388 #[test]
389 fn test_decode_unsupported_encoding() {
390 let bytes = vec![2, 0, 0, 1, 2, 3]; let result = decode(&bytes, 10);
392 assert_eq!(result, Err(DecodeError::UnsupportedEncoding));
393 }
394
395 #[test]
396 fn test_decode_input_too_short() {
397 let bytes = vec![1, 0]; let result = decode(&bytes, 10);
399 assert_eq!(result, Err(DecodeError::InputTooShort));
400 }
401
402 #[test]
403 fn test_decode_max_len_exceeded() {
404 let (base, fallback) = create_base3_test_data(20);
405 let encoded = encode_base3(&base, &fallback).unwrap();
406 let result = decode(&encoded, 19);
408 assert_eq!(result, Err(DecodeError::CorruptDataPayload));
409 }
410
411 #[test]
412 fn test_decode_corrupt_payload() {
413 let (base, fallback) = create_base3_test_data(10);
414 let mut encoded = encode_base3(&base, &fallback).unwrap();
415 encoded.pop(); let result = decode(&encoded, 10);
417 assert_eq!(result, Err(DecodeError::CorruptDataPayload));
418 }
419}