1#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
7pub enum ByteOrder {
8 LittleEndian = 1,
12 BigEndian = 0,
16}
17
18impl ByteOrder {
19 #[inline]
28 pub(crate) fn extract_bits(self, data: &[u8], start_bit: usize, length: usize) -> u64 {
29 match self {
30 ByteOrder::LittleEndian => {
31 let bit_offset = start_bit % 8;
33 let byte_idx = start_bit / 8;
34
35 if bit_offset == 0 {
36 match length {
38 8 => return data[byte_idx] as u64,
39 16 => {
40 return u16::from_le_bytes([data[byte_idx], data[byte_idx + 1]]) as u64;
42 }
43 32 => {
44 return u32::from_le_bytes([
45 data[byte_idx],
46 data[byte_idx + 1],
47 data[byte_idx + 2],
48 data[byte_idx + 3],
49 ]) as u64;
50 }
51 64 => {
52 return u64::from_le_bytes([
53 data[byte_idx],
54 data[byte_idx + 1],
55 data[byte_idx + 2],
56 data[byte_idx + 3],
57 data[byte_idx + 4],
58 data[byte_idx + 5],
59 data[byte_idx + 6],
60 data[byte_idx + 7],
61 ]);
62 }
63 _ => {} }
65 }
66
67 let mut value: u64 = 0;
69 let mut bits_remaining = length;
70 let mut current_bit = start_bit;
71
72 while bits_remaining > 0 {
73 let byte_idx = current_bit / 8;
74 let bit_in_byte = current_bit % 8;
75 let bits_to_take = bits_remaining.min(8 - bit_in_byte);
76
77 let byte = data[byte_idx] as u64;
78 let mask = ((1u64 << bits_to_take) - 1) << bit_in_byte;
79 let extracted = (byte & mask) >> bit_in_byte;
80
81 value |= extracted << (length - bits_remaining);
82
83 bits_remaining -= bits_to_take;
84 current_bit += bits_to_take;
85 }
86
87 value
88 }
89 ByteOrder::BigEndian => {
90 let mut value: u64 = 0;
96 let mut bits_remaining = length;
97 let mut signal_bit_offset = 0; while bits_remaining > 0 {
100 let be_bit = start_bit + signal_bit_offset;
102 let byte_num = be_bit / 8;
103 let bit_in_byte = be_bit % 8;
104
105 let available_in_byte = bit_in_byte + 1;
110 let bits_to_take = bits_remaining.min(available_in_byte);
111
112 let physical_start = 7 - bit_in_byte;
117 let byte = data[byte_num] as u64;
118
119 let mask = ((1u64 << bits_to_take) - 1) << physical_start;
121 let extracted = (byte & mask) >> physical_start;
122
123 let shift_amount = bits_remaining - bits_to_take;
125 value |= extracted << shift_amount;
126
127 bits_remaining -= bits_to_take;
128 signal_bit_offset += bits_to_take;
129 }
130
131 value
132 }
133 }
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::ByteOrder;
140 use core::hash::Hash;
141
142 #[test]
144 fn test_byte_order_variants() {
145 assert_eq!(ByteOrder::LittleEndian as u8, 1);
146 assert_eq!(ByteOrder::BigEndian as u8, 0);
147 }
148
149 #[test]
150 fn test_byte_order_equality() {
151 assert_eq!(ByteOrder::LittleEndian, ByteOrder::LittleEndian);
152 assert_eq!(ByteOrder::BigEndian, ByteOrder::BigEndian);
153 assert_ne!(ByteOrder::LittleEndian, ByteOrder::BigEndian);
154 }
155
156 #[test]
157 fn test_byte_order_clone() {
158 let original = ByteOrder::LittleEndian;
159 let cloned = original;
160 assert_eq!(original, cloned);
161
162 let original2 = ByteOrder::BigEndian;
163 let cloned2 = original2;
164 assert_eq!(original2, cloned2);
165 }
166
167 #[test]
168 fn test_byte_order_copy() {
169 let order = ByteOrder::LittleEndian;
170 let copied = order; assert_eq!(order, copied); }
173
174 #[test]
175 fn test_byte_order_hash_trait() {
176 fn _assert_hash<T: Hash>() {}
178 _assert_hash::<ByteOrder>();
179 }
180
181 #[test]
182 fn test_extract_bits_little_endian() {
183 let data = [0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
185 let raw_value = ByteOrder::LittleEndian.extract_bits(&data, 0, 16);
186 assert_eq!(raw_value, 0x1234);
187 }
188
189 #[test]
190 fn test_extract_bits_little_endian_8bit() {
191 let data = [0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
193 let raw_value = ByteOrder::LittleEndian.extract_bits(&data, 0, 8);
194 assert_eq!(raw_value, 0x42);
195 }
196
197 #[test]
198 fn test_extract_bits_little_endian_32bit() {
199 let data = [0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00];
201 let raw_value = ByteOrder::LittleEndian.extract_bits(&data, 0, 32);
202 assert_eq!(raw_value, 0x12345678);
203 }
204
205 #[test]
206 fn test_extract_bits_little_endian_64bit() {
207 let data = [0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01];
209 let raw_value = ByteOrder::LittleEndian.extract_bits(&data, 0, 64);
210 assert_eq!(raw_value, 0x0123456789ABCDEF);
211 }
212
213 #[test]
214 fn test_extract_bits_big_endian() {
215 let data = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
218 let raw_value = ByteOrder::BigEndian.extract_bits(&data, 0, 16);
219 assert!(raw_value <= 65535);
221 }
222
223 #[test]
224 fn test_extract_bits_mixed_positions_little_endian() {
225 let data = [0x00, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00];
227 let raw_value = ByteOrder::LittleEndian.extract_bits(&data, 8, 16);
228 assert_eq!(raw_value, 0x1234);
229 }
230
231 #[test]
232 fn test_extract_bits_mixed_positions_big_endian() {
233 let data = [0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
236 let raw_value = ByteOrder::BigEndian.extract_bits(&data, 8, 16);
237 assert!(raw_value <= 65535);
239 }
240
241 #[test]
242 fn test_byte_order_difference() {
243 let data = [0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
246
247 let le_value = ByteOrder::LittleEndian.extract_bits(&data, 0, 16);
248 let be_value = ByteOrder::BigEndian.extract_bits(&data, 0, 16);
249
250 assert_eq!(le_value, 0x1234);
252
253 assert_ne!(
255 le_value, be_value,
256 "Big-endian and little-endian should produce different values"
257 );
258 assert!(be_value <= 65535);
259 }
260
261 #[test]
262 fn test_extract_bits_non_aligned_little_endian() {
263 let data = [0xF0, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
266 let raw_value = ByteOrder::LittleEndian.extract_bits(&data, 4, 12);
267 assert_eq!(raw_value, 0x12F);
270 }
271
272 #[cfg(feature = "std")]
274 mod tests_std {
275 use super::*;
276 use core::hash::{Hash, Hasher};
277 use std::collections::hash_map::DefaultHasher;
278
279 #[test]
280 fn test_byte_order_debug() {
281 let little = format!("{:?}", ByteOrder::LittleEndian);
282 assert!(little.contains("LittleEndian"));
283
284 let big = format!("{:?}", ByteOrder::BigEndian);
285 assert!(big.contains("BigEndian"));
286 }
287
288 #[test]
289 fn test_byte_order_hash() {
290 let mut hasher1 = DefaultHasher::new();
291 let mut hasher2 = DefaultHasher::new();
292
293 ByteOrder::LittleEndian.hash(&mut hasher1);
294 ByteOrder::LittleEndian.hash(&mut hasher2);
295 assert_eq!(hasher1.finish(), hasher2.finish());
296
297 let mut hasher3 = DefaultHasher::new();
298 ByteOrder::BigEndian.hash(&mut hasher3);
299 assert_ne!(hasher1.finish(), hasher3.finish());
300 }
301 }
302}