toad_common/
cursor.rs

1/// A cursor over a byte array (std- and alloc-less port of [`std::io::Cursor`])
2#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
3pub struct Cursor<T> {
4  t: T,
5  cursor: usize,
6  len: usize,
7}
8
9impl<T: AsRef<[u8]>> Cursor<T> {
10  fn is_exhausted_(cursor: usize, len: usize) -> bool {
11    Self::remaining_(cursor, len) <= 0
12  }
13
14  fn remaining_(cursor: usize, len: usize) -> isize {
15    len as isize - cursor as isize
16  }
17
18  fn peek_(len: usize, cursor: usize, t: &T, n: usize) -> Option<&[u8]> {
19    if n as isize > Self::remaining_(cursor, len) {
20      None
21    } else {
22      Some(&t.as_ref()[cursor..cursor + n])
23    }
24  }
25
26  fn skip_(cursor: &mut usize, len: usize, n: usize) -> usize {
27    if Self::is_exhausted_(*cursor, len) {
28      0
29    } else if *cursor + n > len {
30      let left = len - *cursor;
31      *cursor += left;
32      left
33    } else {
34      *cursor += n;
35      n
36    }
37  }
38
39  fn peek_until_end_(cursor: usize, len: usize, t: &T) -> &[u8] {
40    if Self::is_exhausted_(cursor, len) {
41      &[]
42    } else {
43      &t.as_ref()[cursor..]
44    }
45  }
46
47  fn seek_to_end_(cursor: &mut usize, len: usize) {
48    *cursor = len;
49  }
50
51  fn take_until_end_<'a, 'b>(cursor: &'a mut usize, len: usize, t: &'b T) -> &'b [u8] {
52    let out = Self::peek_until_end_(*cursor, len, t);
53    Self::seek_to_end_(cursor, len);
54
55    out
56  }
57
58  /// Creates a new cursor
59  pub fn new(t: T) -> Cursor<T> {
60    let len = t.as_ref().len();
61    Cursor { t, cursor: 0, len }
62  }
63
64  /// Unwraps the cursor, discarding its internal position
65  pub fn into_inner(self) -> T {
66    self.t
67  }
68
69  /// Take the next byte in the cursor, returning None
70  /// if the cursor is exhausted.
71  ///
72  /// Runs in O(1) time.
73  #[allow(clippy::should_implement_trait)]
74  pub fn next(&mut self) -> Option<u8> {
75    self.take_exact(1).and_then(|a| match a {
76                        | &[a] => Some(a),
77                        | _ => None,
78                      })
79  }
80
81  /// Take `n` bytes from the cursor, stopping early if
82  /// the end of the buffer is encountered.
83  ///
84  /// Runs in O(1) time.
85  pub fn take(&mut self, n: usize) -> &[u8] {
86    Self::peek_(self.len, self.cursor, &self.t, n).map(|a| {
87                                                    Self::skip_(&mut self.cursor, self.len, n);
88                                                    a
89                                                  })
90                                                  .unwrap_or_else(|| {
91                                                    Self::take_until_end_(&mut self.cursor,
92                                                                          self.len,
93                                                                          &self.t)
94                                                  })
95  }
96
97  /// Take `n` bytes from the cursor, returning None if
98  /// the end of the buffer is encountered.
99  ///
100  /// Runs in O(1) time.
101  pub fn take_exact(&mut self, n: usize) -> Option<&[u8]> {
102    Self::peek_(self.len, self.cursor, &self.t, n).map(|a| {
103                                                    Self::skip_(&mut self.cursor, self.len, n);
104                                                    a
105                                                  })
106  }
107
108  /// Without advancing the position, look at the next
109  /// `n` bytes, or until the end if there are less than `n` bytes
110  /// remaining.
111  ///
112  /// Runs in O(1) time.
113  pub fn peek(&self, n: usize) -> &[u8] {
114    Self::peek_(self.len, self.cursor, &self.t, n).unwrap_or_else(|| self.peek_until_end())
115  }
116
117  /// Without advancing the position, look at the next
118  /// `n` bytes, returning None if there are less than `n` bytes
119  /// remaining.
120  ///
121  /// Runs in O(1) time.
122  pub fn peek_exact(&self, n: usize) -> Option<&[u8]> {
123    Self::peek_(self.len, self.cursor, &self.t, n)
124  }
125
126  /// Advance the cursor by `n` bytes.
127  ///
128  /// Returns the actual number of bytes skipped:
129  ///  - Equal to n if there are at least n more bytes in the buffer
130  ///  - Less than n if n would seek past the end
131  ///  - Zero if the cursor is already exhausted
132  ///
133  /// Runs in O(1) time.
134  pub fn skip(&mut self, n: usize) -> usize {
135    Self::skip_(&mut self.cursor, self.len, n)
136  }
137
138  /// Consume bytes until a predicate returns `false` or the end is reached.
139  ///
140  /// Runs in O(n) time.
141  pub fn take_while(&mut self, mut f: impl FnMut(u8) -> bool) -> &[u8] {
142    if self.is_exhausted() {
143      return &[];
144    }
145
146    (self.cursor..self.len).into_iter()
147                           .take_while(|ix| f(self.t.as_ref()[*ix]))
148                           .last()
149                           .map(|end_ix| {
150                             let out = &self.t.as_ref()[self.cursor..=end_ix];
151                             self.cursor = end_ix + 1;
152                             out
153                           })
154                           .unwrap_or(&[])
155  }
156
157  /// Whether the cursor has reached the end
158  /// of the buffer.
159  ///
160  /// Runs in O(1) time.
161  pub fn is_exhausted(&self) -> bool {
162    Self::is_exhausted_(self.cursor, self.len)
163  }
164
165  /// The number of elements not yet consumed
166  ///
167  /// Runs in O(1) time.
168  pub fn remaining(&self) -> usize {
169    Self::remaining_(self.cursor, self.len).max(0) as usize
170  }
171
172  /// Get the bytes remaining in the buffer without advancing the position.
173  ///
174  /// Runs in O(1) time.
175  pub fn peek_until_end(&self) -> &[u8] {
176    Self::peek_until_end_(self.cursor, self.len, &self.t)
177  }
178
179  /// Get the bytes remaining in the buffer, advancing
180  /// the position to the end.
181  ///
182  /// Runs in O(1) time.
183  pub fn take_until_end(&mut self) -> &[u8] {
184    Self::take_until_end_(&mut self.cursor, self.len, &self.t)
185  }
186
187  /// Get the position the cursor points to within
188  /// the buffer
189  pub fn position(&self) -> usize {
190    self.cursor
191  }
192}
193
194#[cfg(test)]
195mod tests {
196  use super::*;
197
198  #[test]
199  pub fn peek_until_end() {
200    let cur = Cursor::new(vec![]);
201    assert_eq!(cur.peek_until_end(), &[]);
202
203    let cur = Cursor::new(vec![1, 2, 3]);
204    assert_eq!(cur.peek_until_end(), &[1, 2, 3]);
205
206    let mut cur = Cursor::new(vec![1, 2, 3]);
207    cur.skip(1);
208    assert_eq!(cur.peek_until_end(), &[2, 3]);
209  }
210
211  #[test]
212  pub fn take_until_end() {
213    let mut cur = Cursor::new(vec![]);
214    assert_eq!(cur.take_until_end(), &[]);
215    assert_eq!(cur.take_until_end(), &[]);
216    assert_eq!(cur.take_until_end(), &[]);
217
218    let mut cur = Cursor::new(vec![1, 2, 3]);
219    assert_eq!(cur.take_until_end(), &[1, 2, 3]);
220
221    let mut cur = Cursor::new(vec![1, 2, 3]);
222    cur.skip(1);
223    assert_eq!(cur.take_until_end(), &[2, 3]);
224    assert_eq!(cur.peek_until_end(), &[]);
225  }
226
227  #[test]
228  pub fn next() {
229    let mut cur = Cursor::new(vec![1]);
230    assert_eq!(cur.next(), Some(1));
231    assert_eq!(cur.next(), None);
232    assert_eq!(cur.next(), None);
233  }
234
235  #[test]
236  pub fn take() {
237    let mut cur = Cursor::new(vec![1, 2, 3]);
238    assert_eq!(cur.take(2), &[1, 2]);
239    assert_eq!(cur.take(1), &[3]);
240    assert_eq!(cur.take(1), &[]);
241  }
242
243  #[test]
244  pub fn peek() {
245    let mut cur = Cursor::new(vec![1, 2, 3]);
246    assert_eq!(cur.peek(2), &[1, 2]);
247    assert_eq!(cur.peek(1), &[1]);
248    assert_eq!(cur.peek(4), &[1, 2, 3]);
249    cur.take(3);
250    assert_eq!(cur.peek(1), &[]);
251  }
252
253  #[test]
254  pub fn take_exact() {
255    let mut cur = Cursor::new(vec![1, 2, 3]);
256    assert_eq!(cur.take_exact(2), Some([1, 2].as_ref()));
257    assert_eq!(cur.take_exact(2), None);
258    assert_eq!(cur.take_exact(1), Some([3].as_ref()));
259  }
260
261  #[test]
262  pub fn peek_exact() {
263    let cur = Cursor::new(vec![1, 2, 3]);
264    assert_eq!(cur.peek_exact(3), Some([1, 2, 3].as_ref()));
265    assert_eq!(cur.peek_exact(1), Some([1].as_ref()));
266    assert_eq!(cur.peek_exact(4), None);
267  }
268
269  #[test]
270  pub fn take_while() {
271    let til_slash = |c: &mut Cursor<&str>| {
272      core::str::from_utf8(c.take_while(|b| (b as char) != '/')).unwrap()
273                                                                .to_string()
274    };
275
276    let mut cur = Cursor::new("abc/def");
277    assert_eq!(til_slash(&mut cur), "abc".to_string());
278    cur.skip(1);
279    assert_eq!(til_slash(&mut cur), "def".to_string());
280    assert_eq!(til_slash(&mut cur), "".to_string());
281
282    let mut cur = Cursor::new("a");
283    assert_eq!(til_slash(&mut cur), "a");
284
285    let mut cur = Cursor::new("");
286    assert_eq!(til_slash(&mut cur), "");
287
288    let mut cur = Cursor::new("ab");
289    assert_eq!(til_slash(&mut cur), "ab");
290
291    let mut cur = Cursor::new("/abcd");
292    assert_eq!(til_slash(&mut cur), "");
293  }
294
295  #[test]
296  pub fn seek() {
297    let mut cur = Cursor::new(vec![1, 2, 3, 4]);
298    assert_eq!(cur.skip(0), 0); // 0 <- cursor
299    assert_eq!(cur.skip(1), 1); // 1
300    assert_eq!(cur.skip(2), 2); // 3
301    assert_eq!(cur.skip(1), 1); // 4
302    assert_eq!(cur.skip(1), 0); // 4
303  }
304}