1#![doc(html_root_url = "https://docs.rs/toad-cursor/0.1.0")]
5#![cfg_attr(any(docsrs, feature = "docs"), feature(doc_cfg))]
6#![allow(clippy::unused_unit)]
9#![deny(missing_docs)]
12#![deny(missing_debug_implementations)]
13#![deny(missing_copy_implementations)]
14#![cfg_attr(not(test), deny(unsafe_code))]
15#![cfg_attr(not(test), warn(unreachable_pub))]
18#![cfg_attr(not(feature = "std"), no_std)]
21
22#[cfg(feature = "alloc")]
23extern crate alloc as std_alloc;
24
25#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
27pub struct Cursor<T> {
28 t: T,
29 cursor: usize,
30 len: usize,
31}
32
33impl<T: AsRef<[u8]>> Cursor<T> {
34 fn is_exhausted_(cursor: usize, len: usize) -> bool {
35 Self::remaining_(cursor, len) <= 0
36 }
37
38 fn remaining_(cursor: usize, len: usize) -> isize {
39 len as isize - cursor as isize
40 }
41
42 fn peek_(len: usize, cursor: usize, t: &T, n: usize) -> Option<&[u8]> {
43 if n as isize > Self::remaining_(cursor, len) {
44 None
45 } else {
46 Some(&t.as_ref()[cursor..cursor + n])
47 }
48 }
49
50 fn skip_(cursor: &mut usize, len: usize, n: usize) -> usize {
51 if Self::is_exhausted_(*cursor, len) {
52 0
53 } else if *cursor + n > len {
54 let left = len - *cursor;
55 *cursor += left;
56 left
57 } else {
58 *cursor += n;
59 n
60 }
61 }
62
63 fn peek_until_end_(cursor: usize, len: usize, t: &T) -> &[u8] {
64 if Self::is_exhausted_(cursor, len) {
65 &[]
66 } else {
67 &t.as_ref()[cursor..]
68 }
69 }
70
71 fn seek_to_end_(cursor: &mut usize, len: usize) {
72 *cursor = len;
73 }
74
75 fn take_until_end_<'a, 'b>(cursor: &'a mut usize, len: usize, t: &'b T) -> &'b [u8] {
76 let out = Self::peek_until_end_(*cursor, len, t);
77 Self::seek_to_end_(cursor, len);
78
79 out
80 }
81
82 pub fn new(t: T) -> Cursor<T> {
84 let len = t.as_ref().len();
85 Cursor { t, cursor: 0, len }
86 }
87
88 pub fn into_inner(self) -> T {
90 self.t
91 }
92
93 #[allow(clippy::should_implement_trait)]
98 pub fn next(&mut self) -> Option<u8> {
99 self.take_exact(1).and_then(|a| match a {
100 | &[a] => Some(a),
101 | _ => None,
102 })
103 }
104
105 pub fn take(&mut self, n: usize) -> &[u8] {
110 Self::peek_(self.len, self.cursor, &self.t, n).map(|a| {
111 Self::skip_(&mut self.cursor, self.len, n);
112 a
113 })
114 .unwrap_or_else(|| {
115 Self::take_until_end_(&mut self.cursor,
116 self.len,
117 &self.t)
118 })
119 }
120
121 pub fn take_exact(&mut self, n: usize) -> Option<&[u8]> {
126 Self::peek_(self.len, self.cursor, &self.t, n).map(|a| {
127 Self::skip_(&mut self.cursor, self.len, n);
128 a
129 })
130 }
131
132 pub fn peek(&self, n: usize) -> &[u8] {
138 Self::peek_(self.len, self.cursor, &self.t, n).unwrap_or_else(|| self.peek_until_end())
139 }
140
141 pub fn peek_exact(&self, n: usize) -> Option<&[u8]> {
147 Self::peek_(self.len, self.cursor, &self.t, n)
148 }
149
150 pub fn skip(&mut self, n: usize) -> usize {
159 Self::skip_(&mut self.cursor, self.len, n)
160 }
161
162 pub fn take_while(&mut self, mut f: impl FnMut(u8) -> bool) -> &[u8] {
166 if self.is_exhausted() {
167 return &[];
168 }
169
170 (self.cursor..self.len).into_iter()
171 .take_while(|ix| f(self.t.as_ref()[*ix]))
172 .last()
173 .map(|end_ix| {
174 let out = &self.t.as_ref()[self.cursor..=end_ix];
175 self.cursor = end_ix + 1;
176 out
177 })
178 .unwrap_or(&[])
179 }
180
181 pub fn is_exhausted(&self) -> bool {
186 Self::is_exhausted_(self.cursor, self.len)
187 }
188
189 pub fn remaining(&self) -> usize {
193 Self::remaining_(self.cursor, self.len).max(0) as usize
194 }
195
196 pub fn peek_until_end(&self) -> &[u8] {
200 Self::peek_until_end_(self.cursor, self.len, &self.t)
201 }
202
203 pub fn take_until_end(&mut self) -> &[u8] {
208 Self::take_until_end_(&mut self.cursor, self.len, &self.t)
209 }
210
211 pub fn position(&self) -> usize {
214 self.cursor
215 }
216}
217
218#[cfg(test)]
219mod tests {
220 use super::*;
221
222 #[test]
223 pub fn peek_until_end() {
224 let cur = Cursor::new(vec![]);
225 assert_eq!(cur.peek_until_end(), &[]);
226
227 let cur = Cursor::new(vec![1, 2, 3]);
228 assert_eq!(cur.peek_until_end(), &[1, 2, 3]);
229
230 let mut cur = Cursor::new(vec![1, 2, 3]);
231 cur.skip(1);
232 assert_eq!(cur.peek_until_end(), &[2, 3]);
233 }
234
235 #[test]
236 pub fn take_until_end() {
237 let mut cur = Cursor::new(vec![]);
238 assert_eq!(cur.take_until_end(), &[]);
239 assert_eq!(cur.take_until_end(), &[]);
240 assert_eq!(cur.take_until_end(), &[]);
241
242 let mut cur = Cursor::new(vec![1, 2, 3]);
243 assert_eq!(cur.take_until_end(), &[1, 2, 3]);
244
245 let mut cur = Cursor::new(vec![1, 2, 3]);
246 cur.skip(1);
247 assert_eq!(cur.take_until_end(), &[2, 3]);
248 assert_eq!(cur.peek_until_end(), &[]);
249 }
250
251 #[test]
252 pub fn next() {
253 let mut cur = Cursor::new(vec![1]);
254 assert_eq!(cur.next(), Some(1));
255 assert_eq!(cur.next(), None);
256 assert_eq!(cur.next(), None);
257 }
258
259 #[test]
260 pub fn take() {
261 let mut cur = Cursor::new(vec![1, 2, 3]);
262 assert_eq!(cur.take(2), &[1, 2]);
263 assert_eq!(cur.take(1), &[3]);
264 assert_eq!(cur.take(1), &[]);
265 }
266
267 #[test]
268 pub fn peek() {
269 let mut cur = Cursor::new(vec![1, 2, 3]);
270 assert_eq!(cur.peek(2), &[1, 2]);
271 assert_eq!(cur.peek(1), &[1]);
272 assert_eq!(cur.peek(4), &[1, 2, 3]);
273 cur.take(3);
274 assert_eq!(cur.peek(1), &[]);
275 }
276
277 #[test]
278 pub fn take_exact() {
279 let mut cur = Cursor::new(vec![1, 2, 3]);
280 assert_eq!(cur.take_exact(2), Some([1, 2].as_ref()));
281 assert_eq!(cur.take_exact(2), None);
282 assert_eq!(cur.take_exact(1), Some([3].as_ref()));
283 }
284
285 #[test]
286 pub fn peek_exact() {
287 let cur = Cursor::new(vec![1, 2, 3]);
288 assert_eq!(cur.peek_exact(3), Some([1, 2, 3].as_ref()));
289 assert_eq!(cur.peek_exact(1), Some([1].as_ref()));
290 assert_eq!(cur.peek_exact(4), None);
291 }
292
293 #[test]
294 pub fn take_while() {
295 let til_slash = |c: &mut Cursor<&str>| {
296 core::str::from_utf8(c.take_while(|b| (b as char) != '/')).unwrap()
297 .to_string()
298 };
299
300 let mut cur = Cursor::new("abc/def");
301 assert_eq!(til_slash(&mut cur), "abc".to_string());
302 cur.skip(1);
303 assert_eq!(til_slash(&mut cur), "def".to_string());
304 assert_eq!(til_slash(&mut cur), "".to_string());
305
306 let mut cur = Cursor::new("a");
307 assert_eq!(til_slash(&mut cur), "a");
308
309 let mut cur = Cursor::new("");
310 assert_eq!(til_slash(&mut cur), "");
311
312 let mut cur = Cursor::new("ab");
313 assert_eq!(til_slash(&mut cur), "ab");
314
315 let mut cur = Cursor::new("/abcd");
316 assert_eq!(til_slash(&mut cur), "");
317 }
318
319 #[test]
320 pub fn seek() {
321 let mut cur = Cursor::new(vec![1, 2, 3, 4]);
322 assert_eq!(cur.skip(0), 0); assert_eq!(cur.skip(1), 1); assert_eq!(cur.skip(2), 2); assert_eq!(cur.skip(1), 1); assert_eq!(cur.skip(1), 0); }
328}