1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261
use std::fmt::{Debug, LowerHex};
use crate::{
error::SerDesError,
prelude::ByteSerializerHeap,
utils::{
hex::{to_hex_line, to_hex_pretty},
numerics::{be_bytes::FromBeBytes, le_bytes::FromLeBytes, ne_bytes::FromNeBytes},
},
};
use super::ser_stack::ByteSerializerStack;
/// Utility struct with a number of methods to enable deserialization of bytes into various types
/// ```
/// use ::byteserde::prelude::*;
/// let bytes = &[0x01, 0x00, 0x02, 0x00, 0x00, 0x03];
/// let mut des = ByteDeserializerSlice::new(bytes);
/// assert_eq!(des.remaining(), 6);
/// assert_eq!(des.idx(), 0);
/// assert_eq!(des.len(), 6);
///
/// let first: u8 = des.deserialize_bytes_slice(1).unwrap()[0];
/// assert_eq!(first , 1);
///
/// let second: &[u8; 2] = des.deserialize_bytes_array_ref().unwrap();
/// assert_eq!(second, &[0x00, 0x02]);
///
/// let remaining: &[u8] = des.deserialize_bytes_slice_remaining();
/// assert_eq!(remaining, &[0x00, 0x00, 0x03]);
/// ```
#[derive(Debug, PartialEq)]
pub struct ByteDeserializerSlice<'slice> {
bytes: &'slice [u8],
idx: usize,
}
/// Provides a convenient way to view buffer content as both HEX and ASCII bytes where printable.
/// supports both forms of alternate
/// ```
/// use byteserde::prelude::*;
/// let mut des = ByteDeserializerSlice::new(&[0x01, 0x00, 0x02, 0x00, 0x00, 0x03]);
/// println ! ("{:#x}", des); // up to 16 bytes per line
/// println ! ("{:x}", des); // single line
/// ```
impl<'bytes> LowerHex for ByteDeserializerSlice<'bytes> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let bytes = match f.alternate() {
true => format!("\n{hex}", hex = to_hex_pretty(self.bytes)),
false => to_hex_line(self.bytes),
};
let len = self.bytes.len();
let idx = self.idx;
let rem = self.remaining();
write!(f, "ByteDeserializerSlice {{ len: {len}, idx: {idx}, remaining: {rem}, bytes: {bytes} }}",)
}
}
impl<'bytes> ByteDeserializerSlice<'bytes> {
#[inline(always)]
pub fn new(bytes: &[u8]) -> ByteDeserializerSlice {
ByteDeserializerSlice { bytes, idx: 0 }
}
pub fn reset(&mut self) {
self.idx = 0;
}
/// Tracks the bytes read and always set to the next unread byte in the buffer. This is an inverse of [Self::remaining()]
pub fn idx(&self) -> usize {
self.idx
}
/// Number of bytes remaining to be deserialized, this is an inverse of [Self::idx()]
pub fn remaining(&self) -> usize {
self.len() - self.idx
}
// Number of bytes in the buffer does not change as deserialization progresses unlike [Self::remaining()] and [Self::idx()]
pub fn len(&self) -> usize {
self.bytes.len()
}
pub fn is_empty(&self) -> bool {
self.remaining() == 0
}
#[cold]
fn error(&self, n: usize) -> SerDesError {
// moving error into a fn improves performance by 10%
// from_bytes - reuse ByteDeserializerSlice
// time: [39.251 ns 39.333 ns 39.465 ns]
// change: [-12.507% -11.603% -10.612%] (p = 0.00 < 0.05)
// Performance has improved.
SerDesError {
message: format!("Failed to get a slice size: {n} bytes from {self:x}"),
}
}
/// consumes all of the remaining bytes in the buffer and returns them as slice
pub fn deserialize_bytes_slice_remaining(&mut self) -> &'bytes [u8] {
let slice = &self.bytes[self.idx..];
self.idx += slice.len();
slice
}
/// consumes `len` bytes from the buffer and returns them as slice if successful.
/// Fails if `len` is greater then [Self::remaining()]
pub fn deserialize_bytes_slice(&mut self, len: usize) -> crate::error::Result<&'bytes [u8]> {
let res = self.peek_bytes_slice(len)?;
self.advance_idx(len);
Ok(res)
}
#[inline(always)]
pub fn deserialize_u8(&mut self) -> crate::error::Result<u8> {
let res = self.bytes.get(self.idx..);
match res {
Some(v) => {
self.idx += 1;
Ok(v[0])
}
None => Err(self.error(1)),
}
}
#[inline(always)]
pub fn deserialize_i8(&mut self) -> crate::error::Result<i8> {
let res = self.bytes.get(self.idx..);
match res {
Some(v) => {
self.idx += 1;
Ok(v[0] as i8)
}
None => Err(self.error(1)),
}
}
/// moves the index forward by `len` bytes, intended to be used in combination with [Self::peek_bytes_slice()]
#[inline(always)]
fn advance_idx(&mut self, len: usize) {
self.idx += len;
}
/// produces with out consuming `len` bytes from the buffer and returns them as slice if successful.
#[inline(always)]
pub fn peek_bytes_slice(&self, len: usize) -> crate::error::Result<&'bytes [u8]> {
match self.bytes.get(self.idx..self.idx + len) {
Some(v) => Ok(v),
None => Err(SerDesError {
message: format!("requested: {req}, bytes:\n{self:#x}", req = len,),
}),
}
}
#[inline]
pub fn deserialize_bytes_array_ref<const N: usize>(&mut self) -> crate::error::Result<&'bytes [u8; N]> {
match self.bytes.get(self.idx..self.idx + N) {
Some(v) => {
self.idx += N;
Ok(v.try_into().expect("Failed to convert &[u8] into &[u8; N]"))
}
None => Err(self.error(N)),
}
}
/// depletes `2` bytes for `u16`, etc. and returns after deserializing using `native` endianess
/// FromNeBytes trait is already implemented for all rust's numeric primitives in this crate
/// ```
/// use ::byteserde::prelude::*;
/// let mut des = ByteDeserializerSlice::new(&[0x00, 0x01]);
/// let v: u16 = des.deserialize_ne().unwrap();
/// // ... etc
/// ```
#[inline]
pub fn deserialize_ne<const N: usize, T: FromNeBytes<N, T>>(&mut self) -> crate::error::Result<T> {
let r = self.deserialize_bytes_array_ref::<N>()?;
Ok(T::from_bytes_ref(r))
}
/// depletes `2` bytes for `u16`, etc. and returns after deserializing using `little` endianess
/// FromLeBytes trait is already implemented for all rust's numeric primitives in this crate
/// ```
/// use ::byteserde::prelude::*;
/// let mut des = ByteDeserializerSlice::new(&[0x00, 0x01]);
/// let v: u16 = des.deserialize_le().unwrap();
/// // ... etc
/// ```
// #[inline]
pub fn deserialize_le<const N: usize, T: FromLeBytes<N, T>>(&mut self) -> crate::error::Result<T> {
let r = self.deserialize_bytes_array_ref::<N>()?;
Ok(T::from_bytes_ref(r))
}
/// depletes `2` bytes for `u16`, etc. and returns after deserializing using `big` endianess
/// FromBeBytes trait is already implemented for all rust's numeric primitives in this crate
/// ```
/// use ::byteserde::prelude::*;
/// let mut des = ByteDeserializerSlice::new(&[0x00, 0x01]);
/// let v: u16 = des.deserialize_be().unwrap();
/// // ... etc
/// ```
#[inline]
pub fn deserialize_be<const N: usize, T: FromBeBytes<N, T>>(&mut self) -> crate::error::Result<T> {
let r = self.deserialize_bytes_array_ref::<N>()?;
Ok(T::from_bytes_ref(r))
}
/// creates a new instance of `T` type `struct`, depleting exactly the right amount of bytes from [ByteDeserializerSlice]
/// `T` must implement [ByteDeserializeSlice] trait
pub fn deserialize<T>(&mut self) -> crate::error::Result<T>
where T: ByteDeserializeSlice<T> {
T::byte_deserialize(self)
}
/// creates a new instance of T type struct, depleting `exactly` `len` bytes from [ByteDeserializerSlice].
/// Intended for types with variable length such as Strings, Vec, etc.
pub fn deserialize_take<T>(&mut self, len: usize) -> crate::error::Result<T>
where T: ByteDeserializeSlice<T> {
T::byte_deserialize_take(self, len)
}
}
/// This trait is to be implemented by any struct, example `MyFavStruct`, to be compatible with [`ByteDeserializerSlice::deserialize<MyFavStruct>()`]
pub trait ByteDeserializeSlice<T> {
/// If successful returns a new instance of T type struct, depleting exactly the right amount of bytes from [ByteDeserializerSlice]
/// Number of bytes depleted is determined by the struct T itself and its member types.
fn byte_deserialize(des: &mut ByteDeserializerSlice) -> crate::error::Result<T>;
/// if successful returns a new instance of T type struct, however ONLY depleting a maximum of `len` bytes from [ByteDeserializerSlice]
/// Intended for types with variable length such as Strings, Vec, etc.
/// No bytes will be depleted if attempt was not successful.
#[inline(always)]
fn byte_deserialize_take(des: &mut ByteDeserializerSlice, len: usize) -> crate::error::Result<T> {
let bytes = des.peek_bytes_slice(len)?;
let tmp_des = &mut ByteDeserializerSlice::new(bytes);
let result = Self::byte_deserialize(tmp_des);
match result {
Ok(v) => {
des.advance_idx(bytes.len());
Ok(v)
}
Err(e) => Err(e),
}
}
}
/// Greedy deserialization of the remaining byte stream into a `Vec<u8>`
impl ByteDeserializeSlice<Vec<u8>> for Vec<u8> {
fn byte_deserialize(des: &mut ByteDeserializerSlice) -> crate::error::Result<Vec<u8>> {
Ok(des.deserialize_bytes_slice_remaining().into())
}
}
/// This is a short cut method that creates a new instance of [ByteDeserializerSlice] and then uses that to convert them into a T type struct.
#[inline(always)]
pub fn from_slice<T>(bytes: &[u8]) -> crate::error::Result<T>
where T: ByteDeserializeSlice<T> {
let de = &mut ByteDeserializerSlice::new(bytes);
T::byte_deserialize(de)
}
/// This is a short cut method that uses [`ByteSerializerStack<CAP>::as_slice()`] method to issue a [from_slice] call.
pub fn from_serializer_stack<const CAP: usize, T>(ser: &ByteSerializerStack<CAP>) -> crate::error::Result<T>
where T: ByteDeserializeSlice<T> {
from_slice(ser.as_slice())
}
/// This is a short cut method that uses [`ByteSerializerHeap::as_slice()`] method to issue a [from_slice] call.
pub fn from_serializer_heap<T>(ser: &ByteSerializerHeap) -> crate::error::Result<T>
where T: ByteDeserializeSlice<T> {
from_slice(ser.as_slice())
}