1 | /* |
2 | * Copyright (c) 2023. |
3 | * |
4 | * This software is free software; |
5 | * |
6 | * You can redistribute it or modify it under terms of the MIT, Apache License or Zlib license |
7 | */ |
8 | |
9 | use core::mem::size_of; |
10 | |
11 | enum Mode { |
12 | // Big endian |
13 | BE, |
14 | // Little Endian |
15 | LE |
16 | } |
17 | |
18 | static ERROR_MSG: &str = "No more space" ; |
19 | |
20 | /// Encapsulates a simple Byte writer with |
21 | /// support for Endian aware writes |
22 | pub struct ZByteWriter<'a> { |
23 | buffer: &'a mut [u8], |
24 | position: usize |
25 | } |
26 | |
27 | impl<'a> ZByteWriter<'a> { |
28 | /// Write bytes from the buf into the bytestream |
29 | /// and return how many bytes were written |
30 | /// |
31 | /// # Arguments |
32 | /// - `buf`: The bytes to be written to the bytestream |
33 | /// |
34 | /// # Returns |
35 | /// - `Ok(usize)` - Number of bytes written |
36 | /// This number may be less than `buf.len()` if the length of the buffer is greater |
37 | /// than the internal bytestream length |
38 | /// |
39 | /// If you want to be sure that all bytes were written, see [`write_all`](Self::write_all) |
40 | /// |
41 | #[inline ] |
42 | pub fn write(&mut self, buf: &[u8]) -> Result<usize, &'static str> { |
43 | let min = buf.len().min(self.bytes_left()); |
44 | // write |
45 | self.buffer[self.position..self.position + min].copy_from_slice(&buf[0..min]); |
46 | self.position += min; |
47 | |
48 | Ok(min) |
49 | } |
50 | /// Write all bytes from `buf` into the bytestream and return |
51 | /// and panic if not all bytes were written to the bytestream |
52 | /// |
53 | /// # Arguments |
54 | /// - `buf`: The bytes to be written into the bytestream |
55 | /// |
56 | ///# Returns |
57 | /// - `Ok(())`: Indicates all bytes were written into the bytestream |
58 | /// - `Err(&static str)`: In case all the bytes could not be written |
59 | /// to the stream |
60 | pub fn write_all(&mut self, buf: &[u8]) -> Result<(), &'static str> { |
61 | let size = self.write(buf)?; |
62 | |
63 | if size != buf.len() { |
64 | return Err("Could not write the whole buffer" ); |
65 | } |
66 | Ok(()) |
67 | } |
68 | /// Create a new bytestream writer |
69 | /// Bytes are written from the start to the end and not assumptions |
70 | /// are made of the nature of the underlying stream |
71 | /// |
72 | /// # Arguments |
73 | pub fn new(data: &'a mut [u8]) -> ZByteWriter<'a> { |
74 | ZByteWriter { |
75 | buffer: data, |
76 | position: 0 |
77 | } |
78 | } |
79 | /// Return number of unwritten bytes in this stream |
80 | /// |
81 | /// # Example |
82 | /// ``` |
83 | /// use zune_core::bytestream::ZByteWriter; |
84 | /// let mut storage = [0;10]; |
85 | /// |
86 | /// let writer = ZByteWriter::new(&mut storage); |
87 | /// assert_eq!(writer.bytes_left(),10); // no bytes were written |
88 | /// ``` |
89 | pub const fn bytes_left(&self) -> usize { |
90 | self.buffer.len().saturating_sub(self.position) |
91 | } |
92 | |
93 | /// Return the number of bytes the writer has written |
94 | /// |
95 | /// ``` |
96 | /// use zune_core::bytestream::ZByteWriter; |
97 | /// let mut stream = ZByteWriter::new(&mut []); |
98 | /// assert_eq!(stream.position(),0); |
99 | /// ``` |
100 | pub const fn position(&self) -> usize { |
101 | self.position |
102 | } |
103 | |
104 | /// Write a single byte into the bytestream or error out |
105 | /// if there is not enough space |
106 | /// |
107 | /// # Example |
108 | /// ``` |
109 | /// use zune_core::bytestream::ZByteWriter; |
110 | /// let mut buf = [0;10]; |
111 | /// let mut stream = ZByteWriter::new(&mut buf); |
112 | /// assert!(stream.write_u8_err(34).is_ok()); |
113 | /// ``` |
114 | /// No space |
115 | /// ``` |
116 | /// use zune_core::bytestream::ZByteWriter; |
117 | /// let mut stream = ZByteWriter::new(&mut []); |
118 | /// assert!(stream.write_u8_err(32).is_err()); |
119 | /// ``` |
120 | /// |
121 | pub fn write_u8_err(&mut self, byte: u8) -> Result<(), &'static str> { |
122 | match self.buffer.get_mut(self.position) { |
123 | Some(m_byte) => { |
124 | self.position += 1; |
125 | *m_byte = byte; |
126 | |
127 | Ok(()) |
128 | } |
129 | None => Err(ERROR_MSG) |
130 | } |
131 | } |
132 | |
133 | /// Write a single byte in the stream or don't write |
134 | /// anything if the buffer is full and cannot support the byte read |
135 | /// |
136 | /// Should be combined with [`has`](Self::has) |
137 | pub fn write_u8(&mut self, byte: u8) { |
138 | if let Some(m_byte) = self.buffer.get_mut(self.position) { |
139 | self.position += 1; |
140 | *m_byte = byte; |
141 | } |
142 | } |
143 | /// Check if the byte writer can support |
144 | /// the following write |
145 | /// |
146 | /// # Example |
147 | /// ``` |
148 | /// use zune_core::bytestream::ZByteWriter; |
149 | /// let mut data = [0;10]; |
150 | /// let mut stream = ZByteWriter::new(&mut data); |
151 | /// assert!(stream.has(5)); |
152 | /// assert!(!stream.has(100)); |
153 | /// ``` |
154 | pub const fn has(&self, bytes: usize) -> bool { |
155 | self.position.saturating_add(bytes) <= self.buffer.len() |
156 | } |
157 | |
158 | /// Get length of the underlying buffer. |
159 | #[inline ] |
160 | pub const fn len(&self) -> usize { |
161 | self.buffer.len() |
162 | } |
163 | /// Return true if the underlying buffer stream is empty |
164 | #[inline ] |
165 | pub const fn is_empty(&self) -> bool { |
166 | self.len() == 0 |
167 | } |
168 | |
169 | /// Return true whether or not we read to the end of the |
170 | /// buffer and have no more bytes left. |
171 | /// |
172 | /// If this is true, all non error variants will silently discard the |
173 | /// byte and all error variants will return an error on writing a byte |
174 | /// if any write occurs |
175 | /// |
176 | /// |
177 | #[inline ] |
178 | pub const fn eof(&self) -> bool { |
179 | self.position >= self.len() |
180 | } |
181 | |
182 | /// Rewind the position of the internal cursor back by `by` bytes |
183 | /// |
184 | /// The position saturates at zero |
185 | /// |
186 | /// # Example |
187 | /// ``` |
188 | /// use zune_core::bytestream::ZByteWriter; |
189 | /// let bytes = &mut [1,2,4]; |
190 | /// let mut stream = ZByteWriter::new(bytes); |
191 | /// stream.write_u16_be(23); |
192 | /// // now internal cursor is at position 2. |
193 | /// // lets rewind it |
194 | /// stream.rewind(usize::MAX); |
195 | /// assert_eq!(stream.position(),0); |
196 | /// ``` |
197 | #[inline ] |
198 | pub fn rewind(&mut self, by: usize) { |
199 | self.position = self.position.saturating_sub(by); |
200 | } |
201 | /// Move the internal cursor forward some bytes |
202 | /// |
203 | /// |
204 | /// This saturates at maximum value of usize in your platform. |
205 | #[inline ] |
206 | pub fn skip(&mut self, by: usize) { |
207 | self.position = self.position.saturating_add(by); |
208 | } |
209 | |
210 | /// Look ahead position bytes and return a reference |
211 | /// to num_bytes from that position, or an error if the |
212 | /// peek would be out of bounds. |
213 | /// |
214 | /// This doesn't increment the position, bytes would have to be discarded |
215 | /// at a later point. |
216 | #[inline ] |
217 | pub fn peek_at(&'a self, position: usize, num_bytes: usize) -> Result<&'a [u8], &'static str> { |
218 | let start = self.position + position; |
219 | let end = self.position + position + num_bytes; |
220 | |
221 | match self.buffer.get(start..end) { |
222 | Some(bytes) => Ok(bytes), |
223 | None => Err(ERROR_MSG) |
224 | } |
225 | } |
226 | |
227 | /// Set position for the internal cursor |
228 | /// |
229 | /// Further calls to write bytes will proceed from the |
230 | /// position set |
231 | pub fn set_position(&mut self, position: usize) { |
232 | self.position = position; |
233 | } |
234 | } |
235 | |
236 | macro_rules! write_single_type { |
237 | ($name:tt,$name2:tt,$name3:tt,$name4:tt,$name5:tt,$name6:tt,$int_type:tt) => { |
238 | impl<'a> ZByteWriter<'a> |
239 | { |
240 | #[inline(always)] |
241 | fn $name(&mut self, byte: $int_type, mode: Mode) -> Result<(), &'static str> |
242 | { |
243 | const SIZE: usize = size_of::<$int_type>(); |
244 | |
245 | match self.buffer.get_mut(self.position..self.position + SIZE) |
246 | { |
247 | Some(m_byte) => |
248 | { |
249 | self.position += SIZE; |
250 | // get bits, depending on mode. |
251 | // This should be inlined and not visible in |
252 | // the generated binary since mode is a compile |
253 | // time constant. |
254 | let bytes = match mode |
255 | { |
256 | Mode::BE => byte.to_be_bytes(), |
257 | Mode::LE => byte.to_le_bytes() |
258 | }; |
259 | |
260 | m_byte.copy_from_slice(&bytes); |
261 | |
262 | Ok(()) |
263 | } |
264 | None => Err(ERROR_MSG) |
265 | } |
266 | } |
267 | #[inline(always)] |
268 | fn $name2(&mut self, byte: $int_type, mode: Mode) |
269 | { |
270 | const SIZE: usize = size_of::<$int_type>(); |
271 | |
272 | if let Some(m_byte) = self.buffer.get_mut(self.position..self.position + SIZE) |
273 | { |
274 | self.position += SIZE; |
275 | // get bits, depending on mode. |
276 | // This should be inlined and not visible in |
277 | // the generated binary since mode is a compile |
278 | // time constant. |
279 | let bytes = match mode |
280 | { |
281 | Mode::BE => byte.to_be_bytes(), |
282 | Mode::LE => byte.to_le_bytes() |
283 | }; |
284 | |
285 | m_byte.copy_from_slice(&bytes); |
286 | } |
287 | } |
288 | |
289 | #[doc=concat!("Write " ,stringify!($int_type)," as a big endian integer" )] |
290 | #[doc=concat!("Returning an error if the underlying buffer cannot support a " ,stringify!($int_type)," write." )] |
291 | #[inline] |
292 | pub fn $name3(&mut self, byte: $int_type) -> Result<(), &'static str> |
293 | { |
294 | self.$name(byte, Mode::BE) |
295 | } |
296 | |
297 | #[doc=concat!("Write " ,stringify!($int_type)," as a little endian integer" )] |
298 | #[doc=concat!("Returning an error if the underlying buffer cannot support a " ,stringify!($int_type)," write." )] |
299 | #[inline] |
300 | pub fn $name4(&mut self, byte: $int_type) -> Result<(), &'static str> |
301 | { |
302 | self.$name(byte, Mode::LE) |
303 | } |
304 | |
305 | #[doc=concat!("Write " ,stringify!($int_type)," as a big endian integer" )] |
306 | #[doc=concat!("Or don't write anything if the reader cannot support a " ,stringify!($int_type)," write." )] |
307 | #[doc=concat!(" \nShould be combined with the [`has`](Self::has) method to ensure a write succeeds" )] |
308 | #[inline] |
309 | pub fn $name5(&mut self, byte: $int_type) |
310 | { |
311 | self.$name2(byte, Mode::BE) |
312 | } |
313 | #[doc=concat!("Write " ,stringify!($int_type)," as a little endian integer" )] |
314 | #[doc=concat!("Or don't write anything if the reader cannot support a " ,stringify!($int_type)," write." )] |
315 | #[doc=concat!("Should be combined with the [`has`](Self::has) method to ensure a write succeeds" )] |
316 | #[inline] |
317 | pub fn $name6(&mut self, byte: $int_type) |
318 | { |
319 | self.$name2(byte, Mode::LE) |
320 | } |
321 | } |
322 | }; |
323 | } |
324 | |
325 | write_single_type!( |
326 | write_u64_inner_or_die, |
327 | write_u64_inner_or_none, |
328 | write_u64_be_err, |
329 | write_u64_le_err, |
330 | write_u64_be, |
331 | write_u64_le, |
332 | u64 |
333 | ); |
334 | |
335 | write_single_type!( |
336 | write_u32_inner_or_die, |
337 | write_u32_inner_or_none, |
338 | write_u32_be_err, |
339 | write_u32_le_err, |
340 | write_u32_be, |
341 | write_u32_le, |
342 | u32 |
343 | ); |
344 | |
345 | write_single_type!( |
346 | write_u16_inner_or_die, |
347 | write_u16_inner_or_none, |
348 | write_u16_be_err, |
349 | write_u16_le_err, |
350 | write_u16_be, |
351 | write_u16_le, |
352 | u16 |
353 | ); |
354 | |