byteserde/
des_slice.rs

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