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