1use std::io::{Read, Write};
4
5use thiserror::Error;
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
7#[error("Undetermined byte order")]
8pub struct UndertminedByteOrder;
9pub trait ByteOrder: Clone + Copy {
11 fn u16_from_bytes(self, bytes: [u8; 2]) -> u16;
13 fn u16_to_bytes(self, value: u16) -> [u8; 2];
14 fn u32_from_bytes(self, bytes: [u8; 4]) -> u32;
16 fn u32_to_bytes(self, value: u32) -> [u8; 4];
17 fn u64_from_bytes(self, bytes: [u8; 8]) -> u64;
18}
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq)]
21pub struct BigEndian;
22impl ByteOrder for BigEndian {
23 fn u16_from_bytes(self, bytes: [u8; 2]) -> u16 {
24 u16::from_be_bytes(bytes)
25 }
26 fn u16_to_bytes(self, value: u16) -> [u8; 2] {
27 value.to_be_bytes()
28 }
29 fn u32_from_bytes(self, bytes: [u8; 4]) -> u32 {
30 u32::from_be_bytes(bytes)
31 }
32 fn u32_to_bytes(self, value: u32) -> [u8; 4] {
33 value.to_be_bytes()
34 }
35 fn u64_from_bytes(self, bytes: [u8; 8]) -> u64 {
36 u64::from_be_bytes(bytes)
37 }
38}
39#[derive(Debug, Clone, Copy, PartialEq, Eq)]
40pub struct LittleEndian;
41impl ByteOrder for LittleEndian {
42 fn u16_from_bytes(self, bytes: [u8; 2]) -> u16 {
43 u16::from_le_bytes(bytes)
44 }
45 fn u16_to_bytes(self, value: u16) -> [u8; 2] {
46 value.to_le_bytes()
47 }
48 fn u32_from_bytes(self, bytes: [u8; 4]) -> u32 {
49 u32::from_le_bytes(bytes)
50 }
51 fn u32_to_bytes(self, value: u32) -> [u8; 4] {
52 value.to_le_bytes()
53 }
54 fn u64_from_bytes(self, bytes: [u8; 8]) -> u64 {
55 u64::from_le_bytes(bytes)
56 }
57}
58
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
65pub enum Endianness {
66 LittleEndian,
68 BigEndian,
70}
71#[cfg(target_endian = "little")]
72#[allow(clippy::derivable_impls)]
73impl Default for Endianness {
74 fn default() -> Self {
75 Endianness::LittleEndian
76 }
77}
78
79#[cfg(target_endian = "big")]
80#[allow(clippy::derivable_impls)]
81impl Default for Endianness {
82 fn default() -> Self {
83 Endianness::BigEndian
84 }
85}
86impl ByteOrder for Endianness {
87 fn u16_from_bytes(self, bytes: [u8; 2]) -> u16 {
88 match self {
89 Endianness::BigEndian => BigEndian.u16_from_bytes(bytes),
90 Endianness::LittleEndian => LittleEndian.u16_from_bytes(bytes),
91 }
92 }
93 fn u16_to_bytes(self, value: u16) -> [u8; 2] {
94 match self {
95 Endianness::BigEndian => BigEndian.u16_to_bytes(value),
96 Endianness::LittleEndian => LittleEndian.u16_to_bytes(value),
97 }
98 }
99 fn u32_from_bytes(self, bytes: [u8; 4]) -> u32 {
100 match self {
101 Endianness::BigEndian => BigEndian.u32_from_bytes(bytes),
102 Endianness::LittleEndian => LittleEndian.u32_from_bytes(bytes),
103 }
104 }
105 fn u32_to_bytes(self, value: u32) -> [u8; 4] {
106 match self {
107 Endianness::BigEndian => BigEndian.u32_to_bytes(value),
108 Endianness::LittleEndian => LittleEndian.u32_to_bytes(value),
109 }
110 }
111 fn u64_from_bytes(self, bytes: [u8; 8]) -> u64 {
112 match self {
113 Endianness::BigEndian => BigEndian.u64_from_bytes(bytes),
114 Endianness::LittleEndian => LittleEndian.u64_from_bytes(bytes),
115 }
116 }
117}
118
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Error)]
120#[error("Unexpected Size for {name}: expected {expected}, got {got}")]
121pub struct UnexpectedSize {
122 pub name: &'static str,
123 pub expected: usize,
124 pub got: usize,
125}
126pub(crate) trait ExtendedByteOrder: ByteOrder {
127 #[allow(dead_code)]
129 fn try_u16_from_bytes(self, bytes: &[u8]) -> Result<u16, UnexpectedSize>;
130
131 fn try_u32_from_bytes(self, bytes: &[u8]) -> Result<u32, UnexpectedSize>;
133}
134impl<B: ByteOrder> ExtendedByteOrder for B {
135 fn try_u16_from_bytes(self, bytes: &[u8]) -> Result<u16, UnexpectedSize> {
136 if bytes.len() != 2 {
137 return Err(UnexpectedSize {
138 name: "u16",
139 expected: 2,
140 got: bytes.len(),
141 });
142 }
143 Ok(self.u16_from_bytes([bytes[0], bytes[1]]))
144 }
145
146 fn try_u32_from_bytes(self, bytes: &[u8]) -> Result<u32, UnexpectedSize> {
147 if bytes.len() != 4 {
148 return Err(UnexpectedSize {
149 name: "u32",
150 expected: 4,
151 got: bytes.len(),
152 });
153 }
154 Ok(self.u32_from_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]))
155 }
156}
157pub trait ReadExt {
158 fn read_u16<B: ByteOrder>(&mut self, byte_order: B) -> Result<u16, std::io::Error>;
160
161 fn read_u32<B: ByteOrder>(&mut self, byte_order: B) -> Result<u32, std::io::Error>;
163 fn read_bytes<const SIZE: usize>(&mut self) -> Result<[u8; SIZE], std::io::Error>;
167}
168impl<R: Read> ReadExt for R {
169 fn read_u16<B: ByteOrder>(&mut self, byte_order: B) -> Result<u16, std::io::Error> {
170 let mut buffer = [0u8; 2];
171 self.read_exact(&mut buffer)?;
172 Ok(byte_order.u16_from_bytes(buffer))
173 }
174 fn read_u32<B: ByteOrder>(&mut self, byte_order: B) -> Result<u32, std::io::Error> {
175 let mut buffer = [0u8; 4];
176 self.read_exact(&mut buffer)?;
177 Ok(byte_order.u32_from_bytes(buffer))
178 }
179 fn read_bytes<const SIZE: usize>(&mut self) -> Result<[u8; SIZE], std::io::Error> {
180 let mut buffer = [0u8; SIZE];
181 self.read_exact(&mut buffer)?;
182 Ok(buffer)
183 }
184}
185
186pub trait WriteExt {
187 fn write_u16<B: ByteOrder>(&mut self, value: u16, byte_order: B) -> Result<(), std::io::Error>;
189
190 fn write_u32<B: ByteOrder>(&mut self, value: u32, byte_order: B) -> Result<(), std::io::Error>;
191}
192impl<R: Write> WriteExt for R {
193 fn write_u16<B: ByteOrder>(&mut self, value: u16, byte_order: B) -> Result<(), std::io::Error> {
194 let value = byte_order.u16_to_bytes(value);
195 self.write_all(&value)?;
196 Ok(())
197 }
198 fn write_u32<B: ByteOrder>(&mut self, value: u32, byte_order: B) -> Result<(), std::io::Error> {
199 let value = byte_order.u32_to_bytes(value);
200 self.write_all(&value)?;
201 Ok(())
202 }
203}
204#[cfg(test)]
205mod tests {
206 use super::*;
207 #[test]
208 fn test_big_endian() {
209 let bytes: [u8; 2] = [0x12, 0x34];
210 assert_eq!(BigEndian.u16_from_bytes(bytes), 0x1234);
211 let bytes: [u8; 4] = [0x12, 0x34, 0x56, 0x78];
212 assert_eq!(BigEndian.u32_from_bytes(bytes), 0x12345678);
213 }
214 #[test]
215 fn test_little_endian() {
216 let bytes: [u8; 2] = [0x34, 0x12];
217 assert_eq!(LittleEndian.u16_from_bytes(bytes), 0x1234);
218 let bytes: [u8; 4] = [0x78, 0x56, 0x34, 0x12];
219 assert_eq!(LittleEndian.u32_from_bytes(bytes), 0x12345678);
220 }
221}