1use std::num::NonZeroUsize;
2
3use crate::error::{Error, Result};
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
14pub enum Endian {
15 Little,
17 Big,
19}
20
21impl Endian {
22 #[must_use]
24 pub const fn native() -> Self {
25 if cfg!(target_endian = "little") {
26 Self::Little
27 } else {
28 Self::Big
29 }
30 }
31}
32
33#[derive(Clone, Debug)]
35pub(crate) struct Cursor<'data> {
36 bytes: &'data [u8],
37 position: usize,
38 endian: Endian,
39}
40
41impl<'data> Cursor<'data> {
42 pub(crate) const fn new(bytes: &'data [u8], endian: Endian) -> Self {
43 Self {
44 bytes,
45 position: 0,
46 endian,
47 }
48 }
49
50 pub(crate) const fn at(bytes: &'data [u8], endian: Endian, position: usize) -> Result<Self> {
51 if position > bytes.len() {
52 return Err(Error::InvalidOffset {
53 offset: position as u64,
54 input_len: bytes.len(),
55 });
56 }
57 Ok(Self {
58 bytes,
59 position,
60 endian,
61 })
62 }
63
64 pub(crate) const fn endian(&self) -> Endian {
65 self.endian
66 }
67
68 pub(crate) const fn position(&self) -> usize {
69 self.position
70 }
71
72 pub(crate) const fn remaining(&self) -> usize {
73 self.bytes.len().saturating_sub(self.position)
74 }
75
76 pub(crate) const fn is_empty(&self) -> bool {
77 self.remaining() == 0
78 }
79
80 pub(crate) fn take(&mut self, count: usize) -> Result<&'data [u8]> {
81 let end = self
82 .position
83 .checked_add(count)
84 .ok_or(Error::Overflow("cursor end offset"))?;
85 let Some(bytes) = self.bytes.get(self.position..end) else {
86 return Err(Error::UnexpectedEof {
87 offset: self.position,
88 needed: count,
89 remaining: self.remaining(),
90 });
91 };
92 self.position = end;
93 Ok(bytes)
94 }
95
96 pub(crate) fn take_array<const N: usize>(&mut self) -> Result<[u8; N]> {
97 let offset = self.position;
98 let remaining = self.remaining();
99 let bytes = self
100 .bytes
101 .get(offset..)
102 .and_then(<[u8]>::first_chunk::<N>)
103 .ok_or(Error::UnexpectedEof {
104 offset,
105 needed: N,
106 remaining,
107 })?;
108 self.position = offset.saturating_add(N);
109 Ok(*bytes)
110 }
111
112 pub(crate) fn read_u8(&mut self) -> Result<u8> {
113 let [byte] = self.take_array()?;
114 Ok(byte)
115 }
116
117 pub(crate) fn read_u16(&mut self) -> Result<u16> {
118 let bytes = self.take_array()?;
119 Ok(match self.endian {
120 Endian::Little => u16::from_le_bytes(bytes),
121 Endian::Big => u16::from_be_bytes(bytes),
122 })
123 }
124
125 pub(crate) fn read_u32(&mut self) -> Result<u32> {
126 let bytes = self.take_array()?;
127 Ok(match self.endian {
128 Endian::Little => u32::from_le_bytes(bytes),
129 Endian::Big => u32::from_be_bytes(bytes),
130 })
131 }
132
133 pub(crate) fn read_u64(&mut self) -> Result<u64> {
134 let bytes = self.take_array()?;
135 Ok(match self.endian {
136 Endian::Little => u64::from_le_bytes(bytes),
137 Endian::Big => u64::from_be_bytes(bytes),
138 })
139 }
140
141 pub(crate) fn read_uint(&mut self, width: u8) -> Result<u64> {
142 match width {
143 1 => return self.read_u8().map(u64::from),
144 2 => return self.read_u16().map(u64::from),
145 4 => return self.read_u32().map(u64::from),
146 8 => return self.read_u64(),
147 3 | 5..=7 => {}
148 _ => {
149 return Err(Error::OutOfRange {
150 field: "integer width",
151 value: u64::from(width),
152 max: 8,
153 });
154 }
155 }
156 let count = usize::from(width);
157 let bytes = self.take(count)?;
158 let mut buffer = [0_u8; 8];
159 let window = match self.endian {
160 Endian::Little => buffer.get_mut(..count),
161 Endian::Big => buffer.get_mut(size_of::<u64>().saturating_sub(count)..),
162 };
163 window
164 .ok_or_else(|| Error::OutOfRange {
165 field: "integer width",
166 value: u64::from(width),
167 max: 8,
168 })?
169 .copy_from_slice(bytes);
170 Ok(match self.endian {
171 Endian::Little => u64::from_le_bytes(buffer),
172 Endian::Big => u64::from_be_bytes(buffer),
173 })
174 }
175}
176
177#[derive(Clone, Debug)]
179pub(crate) struct Encoder {
180 bytes: Vec<u8>,
181 endian: Endian,
182}
183
184impl Encoder {
185 #[cfg(test)]
186 pub(crate) const fn new(endian: Endian) -> Self {
187 Self {
188 bytes: Vec::new(),
189 endian,
190 }
191 }
192
193 pub(crate) fn with_capacity(endian: Endian, capacity: usize) -> Self {
194 Self {
195 bytes: Vec::with_capacity(capacity),
196 endian,
197 }
198 }
199
200 pub(crate) const fn len(&self) -> usize {
201 self.bytes.len()
202 }
203
204 #[cfg(test)]
205 pub(crate) fn as_slice(&self) -> &[u8] {
206 &self.bytes
207 }
208
209 pub(crate) fn into_inner(self) -> Vec<u8> {
210 self.bytes
211 }
212
213 pub(crate) fn write_u8(&mut self, value: u8) {
214 self.bytes.push(value);
215 }
216
217 pub(crate) fn write_u16(&mut self, value: u16) {
218 self.bytes.extend_from_slice(&match self.endian {
219 Endian::Little => value.to_le_bytes(),
220 Endian::Big => value.to_be_bytes(),
221 });
222 }
223
224 pub(crate) fn write_u32(&mut self, value: u32) {
225 self.bytes.extend_from_slice(&match self.endian {
226 Endian::Little => value.to_le_bytes(),
227 Endian::Big => value.to_be_bytes(),
228 });
229 }
230
231 pub(crate) fn write_u64(&mut self, value: u64) {
232 self.bytes.extend_from_slice(&match self.endian {
233 Endian::Little => value.to_le_bytes(),
234 Endian::Big => value.to_be_bytes(),
235 });
236 }
237
238 pub(crate) fn write_uint(&mut self, value: u64, width: u8) -> Result<()> {
239 if !(1..=8).contains(&width) {
240 return Err(Error::OutOfRange {
241 field: "integer width",
242 value: u64::from(width),
243 max: 8,
244 });
245 }
246 let count = usize::from(width);
247 if width < 8 {
248 let max = u64::MAX
249 .checked_shr(u32::from(8_u8.saturating_sub(width)).saturating_mul(8))
250 .unwrap_or(u64::MAX);
251 if value > max {
252 return Err(Error::OutOfRange {
253 field: "fixed-width integer",
254 value,
255 max,
256 });
257 }
258 }
259 let bytes = match self.endian {
260 Endian::Little => value.to_le_bytes(),
261 Endian::Big => value.to_be_bytes(),
262 };
263 let window = match self.endian {
264 Endian::Little => bytes.get(..count),
265 Endian::Big => bytes.get(size_of::<u64>().saturating_sub(count)..),
266 };
267 self.bytes
268 .extend_from_slice(window.ok_or_else(|| Error::OutOfRange {
269 field: "integer width",
270 value: u64::from(width),
271 max: 8,
272 })?);
273 Ok(())
274 }
275
276 pub(crate) fn write_bytes(&mut self, bytes: &[u8]) {
277 self.bytes.extend_from_slice(bytes);
278 }
279
280 pub(crate) fn align_to(&mut self, alignment: usize) -> Result<()> {
281 let alignment = NonZeroUsize::new(alignment).ok_or(Error::InvalidAlignment(alignment))?;
282 let remainder = self.bytes.len() % alignment;
283 if remainder != 0 {
284 let padding = alignment.get().saturating_sub(remainder);
285 let new_len = self
286 .bytes
287 .len()
288 .checked_add(padding)
289 .ok_or(Error::Overflow("aligned output length"))?;
290 self.bytes.resize(new_len, 0);
291 }
292 Ok(())
293 }
294
295 pub(crate) fn patch_u32(&mut self, offset: usize, value: u32) -> Result<()> {
296 let bytes = match self.endian {
297 Endian::Little => value.to_le_bytes(),
298 Endian::Big => value.to_be_bytes(),
299 };
300 let end = offset
301 .checked_add(bytes.len())
302 .ok_or(Error::Overflow("patch end offset"))?;
303 let remaining = self.bytes.len().saturating_sub(offset);
304 let destination = self
305 .bytes
306 .get_mut(offset..end)
307 .ok_or(Error::UnexpectedEof {
308 offset,
309 needed: bytes.len(),
310 remaining,
311 })?;
312 destination.copy_from_slice(&bytes);
313 Ok(())
314 }
315
316 #[cfg(test)]
317 pub(crate) fn patch_uint(&mut self, offset: usize, value: u64, width: u8) -> Result<()> {
318 let mut encoded = Self::new(self.endian);
319 encoded.write_uint(value, width)?;
320 let end = offset
321 .checked_add(usize::from(width))
322 .ok_or(Error::Overflow("patch end offset"))?;
323 let remaining = self.bytes.len().saturating_sub(offset);
324 let destination = self
325 .bytes
326 .get_mut(offset..end)
327 .ok_or_else(|| Error::UnexpectedEof {
328 offset,
329 needed: usize::from(width),
330 remaining,
331 })?;
332 destination.copy_from_slice(encoded.as_slice());
333 Ok(())
334 }
335}