1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
use crate::{
    private::{
        PopBits,
        PopBuffer,
        PushBits,
        PushBuffer,
    },
    Specifier,
};

/// Creates a new push buffer with all bits initialized to 0.
#[inline]
fn push_buffer<T>() -> PushBuffer<<T as Specifier>::Bytes>
where
    T: Specifier,
    PushBuffer<T::Bytes>: Default,
{
    <PushBuffer<<T as Specifier>::Bytes> as Default>::default()
}

#[doc(hidden)]
#[inline]
pub fn read_specifier<T>(bytes: &[u8], offset: usize) -> <T as Specifier>::Bytes
where
    T: Specifier,
    PushBuffer<T::Bytes>: Default + PushBits,
{
    let end = offset + <T as Specifier>::BITS;
    let ls_byte = offset / 8; // compile-time
    let ms_byte = (end - 1) / 8; // compile-time
    let lsb_offset = offset % 8; // compile-time
    let msb_offset = end % 8; // compile-time
    let msb_offset = if msb_offset == 0 { 8 } else { msb_offset };

    let mut buffer = push_buffer::<T>();

    if lsb_offset == 0 && msb_offset == 8 {
        // Edge-case for whole bytes manipulation.
        for byte in bytes[ls_byte..(ms_byte + 1)].iter().rev() {
            buffer.push_bits(8, *byte)
        }
    } else {
        if ls_byte != ms_byte {
            // Most-significant byte
            buffer.push_bits(msb_offset as u32, bytes[ms_byte]);
        }
        if ms_byte - ls_byte >= 2 {
            // Middle bytes
            for byte in bytes[(ls_byte + 1)..ms_byte].iter().rev() {
                buffer.push_bits(8, *byte);
            }
        }
        if ls_byte == ms_byte {
            buffer.push_bits(<T as Specifier>::BITS as u32, bytes[ls_byte] >> lsb_offset);
        } else {
            buffer.push_bits(8 - lsb_offset as u32, bytes[ls_byte] >> lsb_offset);
        }
    }
    buffer.into_bytes()
}

#[doc(hidden)]
#[inline]
pub fn write_specifier<T>(
    bytes: &mut [u8],
    offset: usize,
    new_val: <T as Specifier>::Bytes,
) where
    T: Specifier,
    PopBuffer<T::Bytes>: PopBits,
{
    let end = offset + <T as Specifier>::BITS;
    let ls_byte = offset / 8; // compile-time
    let ms_byte = (end - 1) / 8; // compile-time
    let lsb_offset = offset % 8; // compile-time
    let msb_offset = end % 8; // compile-time
    let msb_offset = if msb_offset == 0 { 8 } else { msb_offset };

    let mut buffer = <PopBuffer<T::Bytes>>::from_bytes(new_val);

    if lsb_offset == 0 && msb_offset == 8 {
        // Edge-case for whole bytes manipulation.
        for byte in bytes[ls_byte..(ms_byte + 1)].iter_mut() {
            *byte = buffer.pop_bits(8);
        }
    } else {
        // Least-significant byte
        let stays_same = bytes[ls_byte]
            & (if ls_byte == ms_byte && msb_offset != 8 {
                !((0x01 << msb_offset) - 1)
            } else {
                0u8
            } | ((0x01 << lsb_offset as u32) - 1));
        let overwrite = buffer.pop_bits(8 - lsb_offset as u32);
        bytes[ls_byte] = stays_same | (overwrite << lsb_offset as u32);
        if ms_byte - ls_byte >= 2 {
            // Middle bytes
            for byte in bytes[(ls_byte + 1)..ms_byte].iter_mut() {
                *byte = buffer.pop_bits(8);
            }
        }
        if ls_byte != ms_byte {
            // Most-significant byte
            if msb_offset == 8 {
                // We don't need to respect what was formerly stored in the byte.
                bytes[ms_byte] = buffer.pop_bits(msb_offset as u32);
            } else {
                // All bits that do not belong to this field should be preserved.
                let stays_same = bytes[ms_byte] & !((0x01 << msb_offset) - 1);
                let overwrite = buffer.pop_bits(msb_offset as u32);
                bytes[ms_byte] = stays_same | overwrite;
            }
        }
    }
}