Skip to main content

rkg_utils/
byte_handler.rs

1#[derive(thiserror::Error, Debug)]
2pub enum ByteHandlerError {
3    /// The input slice was longer than 4 bytes and cannot fit in a `ByteHandler`.
4    #[error("Couldn't convert type to ByteHandler: Too Long")]
5    ConversionErrorTooLong,
6}
7
8/// Internal union to handle reading bits
9#[repr(C)]
10#[derive(Clone, Copy)]
11pub(crate) union ByteHandler {
12    dword: u32,
13    words: [u16; 2],
14    bytes: [u8; 4],
15}
16
17impl ByteHandler {
18    pub const fn copy_dword(self) -> u32 {
19        unsafe { self.dword }
20    }
21
22    pub const fn copy_word(self, idx: usize) -> u16 {
23        if idx > 1 {
24            return 0;
25        }
26
27        #[cfg(target_endian = "little")]
28        let idx = 1 - idx;
29
30        unsafe { self.words[idx] }
31    }
32
33    pub const fn copy_byte(self, idx: usize) -> u8 {
34        if idx > 3 {
35            return 0;
36        }
37
38        #[cfg(target_endian = "little")]
39        let idx = 3 - idx;
40
41        unsafe { self.bytes[idx] }
42    }
43
44    pub const fn shift_right(&mut self, d: u8) {
45        unsafe {
46            self.dword >>= d;
47        }
48    }
49
50    pub const fn shift_left(&mut self, d: u8) {
51        unsafe {
52            self.dword <<= d;
53        }
54    }
55
56    /// Reads the nth bit from the right counting from 0
57    pub const fn read_bool(&self, d: u8) -> bool {
58        if d >= 32 {
59            return false;
60        }
61
62        #[cfg(target_endian = "little")]
63        return (unsafe { self.dword } & (1u32 << ((d % 8) + 8 * (3 - (d / 8))))) != 0;
64
65        #[cfg(target_endian = "big")]
66        return (unsafe { self.dword } & (1u32 << d)) != 0;
67    }
68}
69
70impl From<[u8; 4]> for ByteHandler {
71    fn from(value: [u8; 4]) -> Self {
72        ByteHandler {
73            #[cfg(target_endian = "big")]
74            bytes: [value[0], value[1], value[2], value[3]],
75            #[cfg(target_endian = "little")]
76            bytes: [value[3], value[2], value[1], value[0]],
77        }
78    }
79}
80
81impl From<[u8; 3]> for ByteHandler {
82    fn from(value: [u8; 3]) -> Self {
83        ByteHandler {
84            #[cfg(target_endian = "big")]
85            bytes: [value[0], value[1], value[2], 0],
86            #[cfg(target_endian = "little")]
87            bytes: [0, value[2], value[1], value[0]],
88        }
89    }
90}
91
92impl From<[u8; 2]> for ByteHandler {
93    fn from(value: [u8; 2]) -> Self {
94        ByteHandler {
95            #[cfg(target_endian = "big")]
96            bytes: [value[0], value[1], 0, 0],
97            #[cfg(target_endian = "little")]
98            bytes: [0, 0, value[1], value[0]],
99        }
100    }
101}
102
103impl From<u8> for ByteHandler {
104    fn from(value: u8) -> Self {
105        ByteHandler {
106            #[cfg(target_endian = "big")]
107            bytes: [value, 0, 0, 0],
108            #[cfg(target_endian = "little")]
109            bytes: [0, 0, 0, value],
110        }
111    }
112}
113
114impl From<u32> for ByteHandler {
115    fn from(value: u32) -> Self {
116        ByteHandler { dword: value }
117    }
118}
119
120impl From<[u16; 2]> for ByteHandler {
121    fn from(value: [u16; 2]) -> Self {
122        ByteHandler {
123            #[cfg(target_endian = "big")]
124            words: [value[0], value[1]],
125            #[cfg(target_endian = "little")]
126            words: [value[1], value[0]],
127        }
128    }
129}
130
131impl From<u16> for ByteHandler {
132    fn from(value: u16) -> Self {
133        ByteHandler {
134            #[cfg(target_endian = "big")]
135            words: [value, 0],
136            #[cfg(target_endian = "little")]
137            words: [0, value],
138        }
139    }
140}
141
142macro_rules! shorten_syntax {
143    ($num:literal $value:ident $type:ty) => {
144        Ok(From::from(unsafe {
145            TryInto::<[$type; $num]>::try_into($value).unwrap_unchecked()
146        }))
147    };
148}
149
150impl TryFrom<&[u8]> for ByteHandler {
151    type Error = ByteHandlerError;
152
153    fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
154        match value.len() {
155            0 => Ok(From::from(0u32)),
156            1 => Ok(From::from(value[0])),
157            2 => shorten_syntax!(2 value u8),
158            3 => shorten_syntax!(3 value u8),
159            4 => shorten_syntax!(4 value u8),
160            _ => Err(ByteHandlerError::ConversionErrorTooLong),
161        }
162    }
163}
164
165impl TryFrom<&[u16]> for ByteHandler {
166    type Error = ByteHandlerError;
167
168    fn try_from(value: &[u16]) -> Result<Self, Self::Error> {
169        match value.len() {
170            0 => Ok(From::from(0u32)),
171            1 => Ok(From::from(value[0])),
172            2 => shorten_syntax!(2 value u16),
173            _ => Err(ByteHandlerError::ConversionErrorTooLong),
174        }
175    }
176}
177
178pub(crate) trait FromByteHandler: Sized {
179    type Err;
180
181    fn from_byte_handler<T>(handler: T) -> Result<Self, Self::Err>
182    where
183        T: TryInto<ByteHandler>,
184        Self::Err: From<T::Error>;
185}