byteorder_cursor/
cursor.rs

1#[cfg(not(feature = "std"))]
2use core::{fmt::Debug, prelude::rust_2021::derive, result::Result::Ok};
3
4use byteorder::ByteOrder;
5
6use super::BufferTooSmall;
7
8/// A std::io::Cursor like buffer interface with byteorder support and no_std
9/// compatibility.
10#[derive(Debug)]
11pub struct Cursor<T> {
12    buffer: T,
13    pos: usize,
14}
15
16impl<T: AsRef<[u8]>> Cursor<T> {
17    /// Constructs a new cursor object on top of a slice.
18    pub fn new(buffer: T) -> Self {
19        Self { buffer, pos: 0 }
20    }
21
22    #[allow(clippy::len_without_is_empty)]
23    /// Returns the length of the underlying buffer.
24    pub fn len(&self) -> usize {
25        self.buffer.as_ref().len()
26    }
27
28    /// Returns the remaining length in bytes of the underlying buffer.
29    pub fn remaining(&self) -> usize {
30        self.buffer.as_ref().len() - self.pos
31    }
32
33    /// Checks if the underlying buffer has the expected amount of space left.
34    pub fn check_remaining(
35        &self,
36        expected: usize,
37    ) -> Result<(), BufferTooSmall> {
38        if self.remaining() < expected {
39            return Err(BufferTooSmall {
40                size: self.len(),
41                expected: self.pos + expected,
42            });
43        }
44
45        Ok(())
46    }
47
48    /// Returns the cursor position in the underlying buffer.
49    pub fn position(&self) -> usize {
50        self.pos
51    }
52
53    /// Sets the cursor position in the underlying buffer.
54    pub fn set_position(&mut self, position: usize) {
55        self.pos = position
56    }
57
58    /// Advances it cursor position by the given amount of bytes.
59    pub fn skip(&mut self, count: usize) {
60        self.pos += count;
61    }
62
63    /// Reads data from the underlying buffer to the given slice and advances
64    /// cursor position.
65    /// Panics if there is not enough data remaining to fill the slice.
66    pub fn read_bytes(&mut self, dst: &mut [u8]) {
67        dst.copy_from_slice(
68            &self.buffer.as_ref()[self.pos..(self.pos + dst.len())],
69        );
70        self.pos += dst.len();
71    }
72
73    /// Reads a 8bit integer value from the underlying buffer and advances
74    /// cursor position.
75    /// Panics if there is not enough data remaining.
76    pub fn read_u8(&mut self) -> u8 {
77        let val = self.buffer.as_ref()[self.pos];
78        self.pos += 1;
79        val
80    }
81
82    /// Reads a 16bit integer value from the underlying buffer and advances
83    /// cursor position.
84    /// Panics if there is not enough data remaining.
85    pub fn read_u16<B: ByteOrder>(&mut self) -> u16 {
86        let val = B::read_u16(&self.buffer.as_ref()[self.pos..]);
87        self.pos += 2;
88        val
89    }
90
91    /// Reads a 24bit integer value from the underlying buffer and advances
92    /// cursor position.
93    /// Panics if there is not enough data remaining.
94    pub fn read_u24<B: ByteOrder>(&mut self) -> u32 {
95        let val = B::read_u24(&self.buffer.as_ref()[self.pos..]);
96        self.pos += 3;
97        val
98    }
99
100    /// Reads a 32bit integer value from the underlying buffer and advances
101    /// cursor position.
102    /// Panics if there is not enough data remaining.
103    pub fn read_u32<B: ByteOrder>(&mut self) -> u32 {
104        let val = B::read_u32(&self.buffer.as_ref()[self.pos..]);
105        self.pos += 4;
106        val
107    }
108
109    /// Reads a 64bit integer value from the underlying buffer and advances
110    /// cursor position.
111    /// Panics if there is not enough data remaining.
112    pub fn read_u64<B: ByteOrder>(&mut self) -> u64 {
113        let val = B::read_u64(&self.buffer.as_ref()[self.pos..]);
114        self.pos += 8;
115        val
116    }
117
118    /// Reads a 8bit integer value from the underlying buffer at a given
119    /// offset from the cursor position without advancing the cursor position.
120    /// Panics if there is not enough data remaining.
121    pub fn peek_u8(&self, offset: usize) -> u8 {
122        self.buffer.as_ref()[self.pos + offset]
123    }
124
125    /// Reads a 16bit integer value from the underlying buffer at a given
126    /// offset from the cursor position without advancing the cursor position.
127    /// Panics if there is not enough data remaining.
128    pub fn peek_u16<B: ByteOrder>(&self, offset: usize) -> u16 {
129        B::read_u16(&self.buffer.as_ref()[(self.pos + offset)..])
130    }
131
132    /// Reads a 24bit integer value from the underlying buffer at a given
133    /// offset from the cursor position without advancing the cursor position.
134    /// Panics if there is not enough data remaining.
135    pub fn peek_u24<B: ByteOrder>(&self, offset: usize) -> u32 {
136        B::read_u24(&self.buffer.as_ref()[(self.pos + offset)..])
137    }
138
139    /// Reads a 32bit integer value from the underlying buffer at a given
140    /// offset from the cursor position without advancing the cursor position.
141    /// Panics if there is not enough data remaining.
142    pub fn peek_u32<B: ByteOrder>(&self, offset: usize) -> u32 {
143        B::read_u32(&self.buffer.as_ref()[(self.pos + offset)..])
144    }
145}
146
147impl Cursor<&mut [u8]> {
148    /// Writes the given slice to the underlying buffer and advances
149    /// cursor position.
150    /// Panics if there is not enough space remaining to write the slice.
151    pub fn write_bytes(&mut self, src: &[u8]) {
152        self.buffer[self.pos..(self.pos + src.len())].copy_from_slice(src);
153        self.pos += src.len();
154    }
155
156    /// Writes a 8bit integer value to the underlying buffer and advances
157    /// cursor position.
158    /// Panics if there is not enough space remaining.
159    pub fn write_u8(&mut self, val: u8) {
160        self.buffer[self.pos] = val;
161        self.pos += 1;
162    }
163
164    /// Writes a 16bit integer value to the underlying buffer and advances
165    /// cursor position.
166    /// Panics if there is not enough space remaining.
167    pub fn write_u16<B: ByteOrder>(&mut self, val: u16) {
168        B::write_u16(&mut self.buffer[self.pos..], val);
169        self.pos += 2;
170    }
171
172    /// Writes a 24bit integer value to the underlying buffer and advances
173    /// cursor position.
174    /// Panics if there is not enough space remaining.
175    pub fn write_u24<B: ByteOrder>(&mut self, val: u32) {
176        B::write_u24(&mut self.buffer[self.pos..], val);
177        self.pos += 3;
178    }
179
180    /// Writes a 32bit integer value to the underlying buffer and advances
181    /// cursor position.
182    /// Panics if there is not enough space remaining.
183    pub fn write_u32<B: ByteOrder>(&mut self, val: u32) {
184        B::write_u32(&mut self.buffer[self.pos..], val);
185        self.pos += 4;
186    }
187
188    /// Writes a 64bit integer value to the underlying buffer and advances
189    /// cursor position.
190    /// Panics if there is not enough space remaining.
191    pub fn write_u64<B: ByteOrder>(&mut self, val: u64) {
192        B::write_u64(&mut self.buffer[self.pos..], val);
193        self.pos += 8;
194    }
195}
196
197#[cfg(test)]
198mod tests {
199    use byteorder::{BigEndian, LittleEndian};
200
201    use super::*;
202
203    #[test]
204    fn test_read() {
205        let buffer = [1u8, 0, 1, 0, 1, 0, 0, 0, 0, 2, 2, 0, 0, 0];
206        let mut cursor = Cursor::new(&buffer[..]);
207
208        assert_eq!(cursor.len(), 14);
209        assert_eq!(cursor.remaining(), 14);
210
211        assert_eq!(cursor.read_u8(), 1);
212        assert_eq!(cursor.remaining(), 13);
213
214        assert_eq!(cursor.read_u16::<BigEndian>(), 1);
215        cursor.skip(1);
216        assert_eq!(cursor.read_u16::<LittleEndian>(), 1);
217        assert!(cursor.check_remaining(8).is_ok());
218
219        assert_eq!(cursor.read_u32::<BigEndian>(), 2);
220        assert_eq!(cursor.read_u32::<LittleEndian>(), 2);
221        assert!(cursor.check_remaining(1).is_err());
222
223        cursor.set_position(1);
224        let mut buf = [0u8; 4];
225        cursor.read_bytes(&mut buf);
226        assert_eq!(buf, [0, 1, 0, 1]);
227    }
228
229    #[test]
230    fn test_peek() {
231        let buffer = [1u8, 0, 1, 0, 1, 0, 0, 0, 0, 2, 2, 0, 0, 0];
232        let mut cursor = Cursor::new(&buffer[..]);
233
234        assert_eq!(cursor.peek_u8(1), 0);
235        assert_eq!(cursor.peek_u16::<BigEndian>(2), 256);
236        assert_eq!(cursor.peek_u32::<LittleEndian>(6), 0x02000000);
237
238        cursor.set_position(5);
239        assert_eq!(cursor.peek_u8(1), 0);
240        assert_eq!(cursor.peek_u16::<BigEndian>(3), 2);
241        assert_eq!(cursor.peek_u32::<LittleEndian>(5), 2);
242    }
243
244    #[test]
245    fn test_write() {
246        let mut buffer = [0u8; 16];
247        let mut cursor = Cursor::new(&mut buffer[..]);
248
249        cursor.write_u8(1);
250        cursor.write_u16::<BigEndian>(5);
251        cursor.write_u32::<LittleEndian>(16);
252        cursor.write_bytes(&[1, 2, 3, 4, 5]);
253
254        assert_eq!(cursor.position(), 12);
255        assert_eq!(buffer, [1, 0, 5, 16, 0, 0, 0, 1, 2, 3, 4, 5, 0, 0, 0, 0]);
256    }
257}