zune_core/bytestream/writer.rs
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
9use core::mem::size_of;
10
11enum Mode {
12 // Big endian
13 BE,
14 // Little Endian
15 LE
16}
17
18static ERROR_MSG: &str = "No more space";
19
20/// Encapsulates a simple Byte writer with
21/// support for Endian aware writes
22pub struct ZByteWriter<'a> {
23 buffer: &'a mut [u8],
24 position: usize
25}
26
27impl<'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
236macro_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
325write_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
335write_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
345write_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);