| 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 | |