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 #[inline]
147 pub(crate) fn insert_bits(self, data: &mut [u8], start_bit: usize, length: usize, value: u64) {
148 match self {
149 ByteOrder::LittleEndian => {
150 let bit_offset = start_bit % 8;
152 let byte_idx = start_bit / 8;
153
154 if bit_offset == 0 {
155 match length {
157 8 => {
158 data[byte_idx] = value as u8;
159 return;
160 }
161 16 => {
162 let bytes = (value as u16).to_le_bytes();
163 data[byte_idx] = bytes[0];
164 data[byte_idx + 1] = bytes[1];
165 return;
166 }
167 32 => {
168 let bytes = (value as u32).to_le_bytes();
169 data[byte_idx] = bytes[0];
170 data[byte_idx + 1] = bytes[1];
171 data[byte_idx + 2] = bytes[2];
172 data[byte_idx + 3] = bytes[3];
173 return;
174 }
175 64 => {
176 let bytes = value.to_le_bytes();
177 data[byte_idx..byte_idx + 8].copy_from_slice(&bytes);
178 return;
179 }
180 _ => {} }
182 }
183
184 let mut bits_remaining = length;
186 let mut current_bit = start_bit;
187 let mut value_offset = 0;
188
189 while bits_remaining > 0 {
190 let byte_idx = current_bit / 8;
191 let bit_in_byte = current_bit % 8;
192 let bits_to_write = bits_remaining.min(8 - bit_in_byte);
193
194 let bits_mask = (1u64 << bits_to_write) - 1;
196 let bits_to_insert = ((value >> value_offset) & bits_mask) as u8;
197
198 let target_mask = (bits_mask as u8) << bit_in_byte;
200
201 data[byte_idx] =
203 (data[byte_idx] & !target_mask) | (bits_to_insert << bit_in_byte);
204
205 bits_remaining -= bits_to_write;
206 current_bit += bits_to_write;
207 value_offset += bits_to_write;
208 }
209 }
210 ByteOrder::BigEndian => {
211 let mut bits_remaining = length;
214 let mut signal_bit_offset = 0; while bits_remaining > 0 {
217 let be_bit = start_bit + signal_bit_offset;
219 let byte_num = be_bit / 8;
220 let bit_in_byte = be_bit % 8;
221
222 let available_in_byte = bit_in_byte + 1;
225 let bits_to_write = bits_remaining.min(available_in_byte);
226
227 let physical_start = 7 - bit_in_byte;
230
231 let shift_amount = bits_remaining - bits_to_write;
233 let bits_mask = (1u64 << bits_to_write) - 1;
234 let bits_to_insert = ((value >> shift_amount) & bits_mask) as u8;
235
236 let target_mask = (bits_mask as u8) << physical_start;
238
239 data[byte_num] =
241 (data[byte_num] & !target_mask) | (bits_to_insert << physical_start);
242
243 bits_remaining -= bits_to_write;
244 signal_bit_offset += bits_to_write;
245 }
246 }
247 }
248 }
249}
250
251#[cfg(test)]
252mod tests {
253 use super::ByteOrder;
254 use core::hash::Hash;
255
256 #[test]
258 fn test_byte_order_variants() {
259 assert_eq!(ByteOrder::LittleEndian as u8, 1);
260 assert_eq!(ByteOrder::BigEndian as u8, 0);
261 }
262
263 #[test]
264 fn test_byte_order_equality() {
265 assert_eq!(ByteOrder::LittleEndian, ByteOrder::LittleEndian);
266 assert_eq!(ByteOrder::BigEndian, ByteOrder::BigEndian);
267 assert_ne!(ByteOrder::LittleEndian, ByteOrder::BigEndian);
268 }
269
270 #[test]
271 fn test_byte_order_clone() {
272 let original = ByteOrder::LittleEndian;
273 let cloned = original;
274 assert_eq!(original, cloned);
275
276 let original2 = ByteOrder::BigEndian;
277 let cloned2 = original2;
278 assert_eq!(original2, cloned2);
279 }
280
281 #[test]
282 fn test_byte_order_copy() {
283 let order = ByteOrder::LittleEndian;
284 let copied = order; assert_eq!(order, copied); }
287
288 #[test]
289 fn test_byte_order_hash_trait() {
290 fn _assert_hash<T: Hash>() {}
292 _assert_hash::<ByteOrder>();
293 }
294
295 #[test]
296 fn test_extract_bits_little_endian() {
297 let data = [0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
299 let raw_value = ByteOrder::LittleEndian.extract_bits(&data, 0, 16);
300 assert_eq!(raw_value, 0x1234);
301 }
302
303 #[test]
304 fn test_extract_bits_little_endian_8bit() {
305 let data = [0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
307 let raw_value = ByteOrder::LittleEndian.extract_bits(&data, 0, 8);
308 assert_eq!(raw_value, 0x42);
309 }
310
311 #[test]
312 fn test_extract_bits_little_endian_32bit() {
313 let data = [0x78, 0x56, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00];
315 let raw_value = ByteOrder::LittleEndian.extract_bits(&data, 0, 32);
316 assert_eq!(raw_value, 0x12345678);
317 }
318
319 #[test]
320 fn test_extract_bits_little_endian_64bit() {
321 let data = [0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01];
323 let raw_value = ByteOrder::LittleEndian.extract_bits(&data, 0, 64);
324 assert_eq!(raw_value, 0x0123456789ABCDEF);
325 }
326
327 #[test]
328 fn test_extract_bits_big_endian() {
329 let data = [0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
332 let raw_value = ByteOrder::BigEndian.extract_bits(&data, 0, 16);
333 assert!(raw_value <= 65535);
335 }
336
337 #[test]
338 fn test_extract_bits_mixed_positions_little_endian() {
339 let data = [0x00, 0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00];
341 let raw_value = ByteOrder::LittleEndian.extract_bits(&data, 8, 16);
342 assert_eq!(raw_value, 0x1234);
343 }
344
345 #[test]
346 fn test_extract_bits_mixed_positions_big_endian() {
347 let data = [0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
350 let raw_value = ByteOrder::BigEndian.extract_bits(&data, 8, 16);
351 assert!(raw_value <= 65535);
353 }
354
355 #[test]
356 fn test_byte_order_difference() {
357 let data = [0x34, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
360
361 let le_value = ByteOrder::LittleEndian.extract_bits(&data, 0, 16);
362 let be_value = ByteOrder::BigEndian.extract_bits(&data, 0, 16);
363
364 assert_eq!(le_value, 0x1234);
366
367 assert_ne!(
369 le_value, be_value,
370 "Big-endian and little-endian should produce different values"
371 );
372 assert!(be_value <= 65535);
373 }
374
375 #[test]
376 fn test_extract_bits_non_aligned_little_endian() {
377 let data = [0xF0, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
380 let raw_value = ByteOrder::LittleEndian.extract_bits(&data, 4, 12);
381 assert_eq!(raw_value, 0x12F);
384 }
385
386 #[test]
391 fn test_insert_bits_little_endian_8bit() {
392 let mut data = [0x00; 8];
393 ByteOrder::LittleEndian.insert_bits(&mut data, 0, 8, 0x42);
394 assert_eq!(data[0], 0x42);
395 }
396
397 #[test]
398 fn test_insert_bits_little_endian_16bit() {
399 let mut data = [0x00; 8];
400 ByteOrder::LittleEndian.insert_bits(&mut data, 0, 16, 0x1234);
401 assert_eq!(data[0], 0x34);
403 assert_eq!(data[1], 0x12);
404 }
405
406 #[test]
407 fn test_insert_bits_little_endian_32bit() {
408 let mut data = [0x00; 8];
409 ByteOrder::LittleEndian.insert_bits(&mut data, 0, 32, 0x12345678);
410 assert_eq!(data[0], 0x78);
411 assert_eq!(data[1], 0x56);
412 assert_eq!(data[2], 0x34);
413 assert_eq!(data[3], 0x12);
414 }
415
416 #[test]
417 fn test_insert_bits_little_endian_64bit() {
418 let mut data = [0x00; 8];
419 ByteOrder::LittleEndian.insert_bits(&mut data, 0, 64, 0x0123456789ABCDEF);
420 assert_eq!(data, [0xEF, 0xCD, 0xAB, 0x89, 0x67, 0x45, 0x23, 0x01]);
421 }
422
423 #[test]
424 fn test_insert_bits_little_endian_non_aligned() {
425 let mut data = [0x00; 8];
426 ByteOrder::LittleEndian.insert_bits(&mut data, 4, 12, 0x12F);
428 let extracted = ByteOrder::LittleEndian.extract_bits(&data, 4, 12);
430 assert_eq!(extracted, 0x12F);
431 }
432
433 #[test]
434 fn test_insert_extract_roundtrip_little_endian() {
435 let test_cases = [
437 (0, 8, 0x42u64),
438 (0, 16, 0x1234),
439 (8, 16, 0xABCD),
440 (4, 12, 0x123),
441 (0, 32, 0x12345678),
442 (0, 64, 0x0123456789ABCDEF),
443 ];
444
445 for (start_bit, length, value) in test_cases {
446 let mut data = [0x00; 8];
447 ByteOrder::LittleEndian.insert_bits(&mut data, start_bit, length, value);
448 let extracted = ByteOrder::LittleEndian.extract_bits(&data, start_bit, length);
449 assert_eq!(
450 extracted, value,
451 "Round-trip failed for start_bit={}, length={}, value=0x{:X}",
452 start_bit, length, value
453 );
454 }
455 }
456
457 #[test]
458 fn test_insert_extract_roundtrip_big_endian() {
459 let test_cases = [
461 (7, 8, 0x42u64), (7, 16, 0x1234), (15, 16, 0xABCD), ];
465
466 for (start_bit, length, value) in test_cases {
467 let mut data = [0x00; 8];
468 ByteOrder::BigEndian.insert_bits(&mut data, start_bit, length, value);
469 let extracted = ByteOrder::BigEndian.extract_bits(&data, start_bit, length);
470 assert_eq!(
471 extracted, value,
472 "BE round-trip failed for start_bit={}, length={}, value=0x{:X}",
473 start_bit, length, value
474 );
475 }
476 }
477
478 #[test]
479 fn test_insert_bits_preserves_other_bits() {
480 let mut data = [0xFF; 8];
482 ByteOrder::LittleEndian.insert_bits(&mut data, 8, 8, 0x00);
483 assert_eq!(data[0], 0xFF);
485 assert_eq!(data[1], 0x00);
486 assert_eq!(data[2], 0xFF);
487 }
488
489 #[test]
490 fn test_insert_bits_at_offset() {
491 let mut data = [0x00; 8];
492 ByteOrder::LittleEndian.insert_bits(&mut data, 16, 16, 0x5678);
494 assert_eq!(data[0], 0x00);
495 assert_eq!(data[1], 0x00);
496 assert_eq!(data[2], 0x78);
497 assert_eq!(data[3], 0x56);
498 }
499
500 #[cfg(feature = "std")]
502 mod tests_std {
503 use super::*;
504 use core::hash::{Hash, Hasher};
505 use std::collections::hash_map::DefaultHasher;
506
507 #[test]
508 fn test_byte_order_debug() {
509 let little = format!("{:?}", ByteOrder::LittleEndian);
510 assert!(little.contains("LittleEndian"));
511
512 let big = format!("{:?}", ByteOrder::BigEndian);
513 assert!(big.contains("BigEndian"));
514 }
515
516 #[test]
517 fn test_byte_order_hash() {
518 let mut hasher1 = DefaultHasher::new();
519 let mut hasher2 = DefaultHasher::new();
520
521 ByteOrder::LittleEndian.hash(&mut hasher1);
522 ByteOrder::LittleEndian.hash(&mut hasher2);
523 assert_eq!(hasher1.finish(), hasher2.finish());
524
525 let mut hasher3 = DefaultHasher::new();
526 ByteOrder::BigEndian.hash(&mut hasher3);
527 assert_ne!(hasher1.finish(), hasher3.finish());
528 }
529 }
530}