tbytes/
bytes_reader.rs

1//! # Bytes reader.
2//!
3//! [`TBytesReader`] is designed to read primitive types and fixed arrays of primitive types from
4//! a provided [`TBytesReaderBackend`].
5#![warn(missing_docs)]
6#![deny(rustdoc::broken_intra_doc_links)]
7
8use core::cell::Cell;
9
10use super::errors::TBytesError;
11
12/// Reads primitive types and arrays of primitive types from [`TBytesReaderBackend`].
13#[derive(Clone, Debug)]
14#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
15pub struct TBytesReader<B: TBytesReaderBackend> {
16    backend: B,
17}
18
19impl<B: TBytesReaderBackend> TBytesReader<B> {
20    /// Default constructor.
21    pub fn new(backend: B) -> Self {
22        Self { backend }
23    }
24}
25
26/// Type-aware read interface for [`TBytesReader`].
27pub trait TBytesReaderFor<T> {
28    /// Reads value of type `T`.
29    fn read(&self) -> Result<T, TBytesError>;
30    /// Reads array of values of type `T`.
31    ///
32    /// # Arguments
33    ///
34    /// Array length is specified as a generic parameter `N`.
35    fn read_array<const N: usize>(&self) -> Result<[T; N], TBytesError>;
36}
37
38/// Implements [`TBytesReaderFor`] for a specific type.
39macro_rules! t_bytes_reader_for {
40    ($type_: ident) => {
41        impl<B: TBytesReaderBackend> TBytesReaderFor<$type_> for TBytesReader<B> {
42            fn read(&self) -> Result<$type_, TBytesError> {
43                const SIZE: usize = core::mem::size_of::<$type_>();
44                let mut bytes = [0u8; SIZE];
45                bytes.copy_from_slice(self.backend.read(SIZE)?);
46
47                Ok($type_::from_le_bytes(bytes))
48            }
49
50            fn read_array<const N: usize>(&self) -> Result<[$type_; N], TBytesError> {
51                const SIZE: usize = core::mem::size_of::<$type_>();
52                let mut result: [$type_; N] = [0 as $type_; N];
53
54                for i in 0..N {
55                    let mut bytes = [0u8; SIZE];
56                    bytes.copy_from_slice(self.backend.read(SIZE)?);
57                    result[i] = $type_::from_le_bytes(bytes);
58                }
59
60                Ok(result)
61            }
62        }
63    };
64}
65
66// Implement bytes reader for primitive types
67t_bytes_reader_for!(u8);
68t_bytes_reader_for!(u16);
69t_bytes_reader_for!(u32);
70t_bytes_reader_for!(u64);
71t_bytes_reader_for!(u128);
72t_bytes_reader_for!(i8);
73t_bytes_reader_for!(i16);
74t_bytes_reader_for!(i32);
75t_bytes_reader_for!(i64);
76t_bytes_reader_for!(i128);
77t_bytes_reader_for!(f32);
78t_bytes_reader_for!(f64);
79
80/// Backend for [`TBytesReader`].
81pub trait TBytesReaderBackend {
82    /// Reads a sequence of bytes from buffer.
83    fn read(&self, num_bytes: usize) -> Result<&[u8], TBytesError>;
84}
85
86/// Backend for [`TBytesReader`] which operates on read-only slices of bytes.
87///
88/// > This is not a thread-safe implementation!
89#[derive(Clone, Debug)]
90#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
91pub struct TBytesReaderSliceBackend<'a> {
92    buffer: &'a [u8],
93    pos: Cell<usize>,
94}
95
96impl<'a> TBytesReaderSliceBackend<'a> {
97    /// Default constructor.
98    pub fn new(buffer: &'a [u8]) -> Self {
99        Self {
100            buffer,
101            pos: Default::default(),
102        }
103    }
104
105    /// Current cursor position.
106    pub fn pos(&self) -> usize {
107        self.pos.get()
108    }
109}
110
111impl<'a> TBytesReaderBackend for TBytesReaderSliceBackend<'a> {
112    /// Reads `num_bytes` from slice.
113    fn read(&self, num_bytes: usize) -> Result<&[u8], TBytesError> {
114        let pos = self.pos.get();
115
116        if self.buffer.len() < pos + num_bytes {
117            return Err(TBytesError::OutOfBounds);
118        }
119
120        let bytes = &self.buffer[pos..pos + num_bytes];
121        self.pos.replace(pos + num_bytes);
122
123        Ok(bytes)
124    }
125}
126
127impl<'a> From<&'a [u8]> for TBytesReader<TBytesReaderSliceBackend<'a>> {
128    /// Constructs [`TBytesReader`] from provided slice.
129    ///
130    /// # Examples
131    ///
132    /// ```rust
133    /// use tbytes::{TBytesReader, TBytesReaderFor};
134    ///
135    /// let buffer = [255, 1];
136    /// let reader = TBytesReader::from(buffer.as_slice());
137    ///
138    /// let val: u16 = reader.read().unwrap();
139    /// assert_eq!(val, 511);
140    /// ```
141    fn from(value: &'a [u8]) -> Self {
142        TBytesReader::new(TBytesReaderSliceBackend::new(value))
143    }
144}
145
146#[cfg(test)]
147mod tests {
148    use super::*;
149
150    #[test]
151    fn slice_backend() {
152        let buffer = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9u8];
153        let backend = TBytesReaderSliceBackend::new(&buffer);
154
155        assert_eq!(backend.read(2).unwrap(), &[0, 1u8]);
156        assert_eq!(backend.read(4).unwrap(), &[2, 3, 4, 5u8]);
157        assert_eq!(backend.read(4).unwrap(), &[6, 7, 8, 9u8]);
158
159        let eof = backend.read(1);
160        assert!(eof.is_err());
161        assert!(matches!(eof, Err(TBytesError::OutOfBounds)));
162    }
163
164    #[test]
165    fn slice_backend_out_of_bouts_is_idempotent() {
166        let buffer = [42; 10];
167        let backend = TBytesReaderSliceBackend::new(&buffer);
168
169        assert_eq!(backend.read(10).unwrap(), &[42; 10]);
170
171        let eof = backend.read(1);
172        assert!(matches!(eof, Err(TBytesError::OutOfBounds)));
173        let eof = backend.read(1);
174        assert!(matches!(eof, Err(TBytesError::OutOfBounds)));
175
176        assert_eq!(backend.pos(), 10);
177    }
178
179    #[test]
180    fn from_slice() {
181        let buffer = [128, 255, 1, 1u8, 1, 255];
182        let reader = TBytesReader::from(buffer.as_slice());
183
184        let val: u8 = reader.read().unwrap();
185        assert_eq!(val, 128);
186
187        let val: i8 = reader.read().unwrap();
188        assert_eq!(val, -1);
189
190        let val: u16 = reader.read().unwrap();
191        assert_eq!(val, 257);
192
193        let val: [u8; 2] = reader.read_array().unwrap();
194        assert_eq!(val, [1, 255]);
195    }
196
197    #[test]
198    fn bytes_reader_for() {
199        let buffer = [128, 255, 1, 1u8, 1, 255];
200        let backend = TBytesReaderSliceBackend::new(&buffer);
201        let reader = TBytesReader::new(backend);
202
203        let val: u8 = reader.read().unwrap();
204        assert_eq!(val, 128);
205
206        let val: i8 = reader.read().unwrap();
207        assert_eq!(val, -1);
208
209        let val: u16 = reader.read().unwrap();
210        assert_eq!(val, 257);
211
212        let val: [u8; 2] = reader.read_array().unwrap();
213        assert_eq!(val, [1, 255]);
214    }
215
216    #[test]
217    fn arrays() {
218        let buffer = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9u8];
219        let backend = TBytesReaderSliceBackend::new(&buffer);
220        let reader = &TBytesReader::new(backend);
221
222        let result: Result<[u8; 8], TBytesError> = reader.read_array();
223        assert!(result.is_ok());
224        assert_eq!(result.unwrap(), [0, 1, 2, 3, 4, 5, 6, 7u8]);
225
226        let result: Result<[u8; 4], TBytesError> = reader.read_array();
227        assert!(result.is_err());
228    }
229}