drive/util/common/decode.rs
1//! Decoding.
2//!
3//! This module defines decoding functions.
4//!
5
6use byteorder::{BigEndian, ReadBytesExt};
7use std::io;
8
9/// Decoding error.
10#[derive(Debug, thiserror::Error)]
11pub enum DecodeError {
12 /// Slice passed to decode_u64 is not 8 bytes long.
13 #[error("can't create a u64 from &[u8]: expected size 8, got {0}")]
14 InvalidLength(usize),
15 /// Unexpected IO error.
16 #[error("can't create a u64 from &[u8]: expected size 8, got {0}")]
17 ReadFailed(io::Error),
18}
19
20/// Decodes an unsigned integer on 64 bits.
21pub fn decode_u64(val: &[u8]) -> Result<u64, DecodeError> {
22 if val.len() != 8 {
23 return Err(DecodeError::InvalidLength(val.len()));
24 }
25
26 // Flip the sign bit
27 // to deal with interaction between the domains
28 // 2's complement values have the sign bit set to 1
29 // this makes them greater than the positive domain in terms of sort order
30 // to fix this, we just flip the sign bit
31 // so positive integers have the high bit and negative integers have the low bit
32 // the relative order of elements in each domain is still maintained, as the
33 // change was uniform across all elements
34 let mut val = val.to_vec();
35 val[0] ^= 0b1000_0000;
36
37 // Decode the integer in big endian form
38 // This ensures that most significant bits are compared first
39 // a bigger positive number would be greater than a smaller one
40 // and a bigger negative number would be greater than a smaller one
41 // maintains sort order for each domain
42 let mut rdr = val.as_slice();
43 rdr.read_u64::<BigEndian>().map_err(DecodeError::ReadFailed)
44}