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}