scannit_core/
conversion.rs1use std::fmt::Write;
2
3pub fn as_hex_string(bytes: &[u8]) -> String {
5 let mut string_buffer = String::new();
6 for &byte in bytes {
7 let _ = write!(&mut string_buffer, "{:x}", byte);
9 }
10 string_buffer
11}
12
13pub fn get_bits_as_u8(bytes: &[u8], bit_offset_index: usize, bit_length: usize) -> u8 {
14 get_bits_as_u64(bytes, bit_offset_index, bit_length) as u8
15}
16
17pub fn get_bits_as_u16(bytes: &[u8], bit_offset_index: usize, bit_length: usize) -> u16 {
18 get_bits_as_u64(bytes, bit_offset_index, bit_length) as u16
19}
20
21pub fn get_bits_as_u32(bytes: &[u8], bit_offset_index: usize, bit_length: usize) -> u32 {
22 get_bits_as_u64(bytes, bit_offset_index, bit_length) as u32
23}
24
25pub fn get_bits_as_u64(bytes: &[u8], bit_offset_index: usize, bit_length: usize) -> u64 {
26 let byte_offset = bit_offset_index / 8;
27 let end_byte_index = (bit_offset_index + bit_length - 1) / 8;
28 let num_relevant_bytes = (end_byte_index - byte_offset) + 1;
29 let num_bits_to_mask = bit_offset_index % 8;
30 let leading_and_value_bits = num_bits_to_mask + bit_length;
31 let num_bits_to_shift = if num_relevant_bytes * 8 > leading_and_value_bits {
32 (num_relevant_bytes * 8) - leading_and_value_bits
33 } else {
34 0
35 };
36 let mut and_mask = 0u64;
37 for _ in 0..num_bits_to_mask {
38 and_mask = (and_mask << 1) + 1;
39 }
40 if num_bits_to_mask > 0 {
42 and_mask <<= 64 - num_bits_to_mask;
43 }
44 and_mask = !and_mask;
45 let bytes = &bytes[byte_offset..=end_byte_index];
46
47 let bit_position = 56;
48 let mut welded_bytes = 0u64;
50 for (i, byte) in bytes.iter().enumerate() {
51 welded_bytes += u64::from(*byte) << (bit_position - (i * 8))
52 }
53
54 ((welded_bytes & and_mask) >> num_bits_to_shift) >> ((8 - num_relevant_bytes) * 8)
58}
59
60#[cfg(test)]
61mod test {
62 use crate::conversion::{get_bits_as_u16, get_bits_as_u32, get_bits_as_u64, get_bits_as_u8};
63
64 #[test]
65 fn to_bits_should_handle_trailing_and_leading_bits() {
66 let three_bytes: [u8; 3] = [0x00, 0x1F, 0xFC];
70 let expected = 2047u64;
71 let actual = get_bits_as_u64(&three_bytes, 11, 11);
72 assert_eq!(expected, actual);
73 }
74
75 #[test]
76 fn to_bits_should_handle_u8() {
77 let byte: [u8; 1] = [0b0011_0100];
78 let expected = 0b0000_1101;
79 let actual = get_bits_as_u8(&byte, 2, 4);
81 assert_eq!(expected, actual);
82 }
83
84 #[test]
85 fn to_bits_should_handle_u16() {
86 let bytes: [u8; 3] = [0b1111_0001, 0b0000_0001, 0b0010_0000];
88 let expected = 0b10001000_00001001;
89 let actual = get_bits_as_u16(&bytes, 3, 16);
90 assert_eq!(expected, actual);
91 }
92
93 #[rustfmt::skip]
94 #[test]
95 fn to_bits_should_handle_u32() {
96 let bytes: [u8; 5] = [0b1100_1001, 0b0000_1000, 0b0000_0001, 0b1101_0000, 0b0110_0011];
98 let expected: u32 = 0b10000100_00000000_11101000_00110001;
99 let actual = get_bits_as_u32(&bytes, 7, 32);
100 assert_eq!(expected, actual);
101 }
102
103 #[test]
104 fn to_bits_should_handle_values_that_dont_need_shifting() {
105 let bytes: [u8; 2] = [0x00, 0x12];
106 let expected = 0b0000_0010;
107 let actual = get_bits_as_u8(&bytes, 14, 2);
108 assert_eq!(expected, actual);
109 }
110
111 #[test]
112 fn to_bits_should_handle_straddled_values_at_end_of_array() {
113 let bytes: [u8; 3] = [0b1000_0010, 0b0101_1011, 0b0000_0101];
116 let expected = 0b0000_0010;
117 let actual = get_bits_as_u16(&bytes, 15, 2);
118 assert_eq!(expected, actual);
119 }
120}