#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
pub struct Cursor<T> {
t: T,
cursor: usize,
len: usize,
}
impl<T: AsRef<[u8]>> Cursor<T> {
fn is_exhausted_(cursor: usize, len: usize) -> bool {
Self::remaining_(cursor, len) <= 0
}
fn remaining_(cursor: usize, len: usize) -> isize {
len as isize - cursor as isize
}
fn peek_(len: usize, cursor: usize, t: &T, n: usize) -> Option<&[u8]> {
if n as isize > Self::remaining_(cursor, len) {
None
} else {
Some(&t.as_ref()[cursor..cursor + n])
}
}
fn skip_(cursor: &mut usize, len: usize, n: usize) -> usize {
if Self::is_exhausted_(*cursor, len) {
0
} else if *cursor + n > len {
let left = len - *cursor;
*cursor += left;
left
} else {
*cursor += n;
n
}
}
fn peek_until_end_(cursor: usize, len: usize, t: &T) -> &[u8] {
if Self::is_exhausted_(cursor, len) {
&[]
} else {
&t.as_ref()[cursor..]
}
}
fn seek_to_end_(cursor: &mut usize, len: usize) {
*cursor = len;
}
fn take_until_end_<'a, 'b>(cursor: &'a mut usize, len: usize, t: &'b T) -> &'b [u8] {
let out = Self::peek_until_end_(*cursor, len, t);
Self::seek_to_end_(cursor, len);
out
}
pub fn new(t: T) -> Cursor<T> {
let len = t.as_ref().len();
Cursor { t, cursor: 0, len }
}
pub fn into_inner(self) -> T {
self.t
}
#[allow(clippy::should_implement_trait)]
pub fn next(&mut self) -> Option<u8> {
self.take_exact(1).and_then(|a| match a {
| &[a] => Some(a),
| _ => None,
})
}
pub fn take(&mut self, n: usize) -> &[u8] {
Self::peek_(self.len, self.cursor, &self.t, n).map(|a| {
Self::skip_(&mut self.cursor, self.len, n);
a
})
.unwrap_or_else(|| {
Self::take_until_end_(&mut self.cursor,
self.len,
&self.t)
})
}
pub fn take_exact(&mut self, n: usize) -> Option<&[u8]> {
Self::peek_(self.len, self.cursor, &self.t, n).map(|a| {
Self::skip_(&mut self.cursor, self.len, n);
a
})
}
pub fn peek(&self, n: usize) -> &[u8] {
Self::peek_(self.len, self.cursor, &self.t, n).unwrap_or_else(|| self.peek_until_end())
}
pub fn peek_exact(&self, n: usize) -> Option<&[u8]> {
Self::peek_(self.len, self.cursor, &self.t, n)
}
pub fn skip(&mut self, n: usize) -> usize {
Self::skip_(&mut self.cursor, self.len, n)
}
pub fn take_while(&mut self, mut f: impl FnMut(u8) -> bool) -> &[u8] {
if self.is_exhausted() {
return &[];
}
(self.cursor..self.len).into_iter()
.take_while(|ix| f(self.t.as_ref()[*ix]))
.last()
.map(|end_ix| {
let out = &self.t.as_ref()[self.cursor..=end_ix];
self.cursor = end_ix + 1;
out
})
.unwrap_or(&[])
}
pub fn is_exhausted(&self) -> bool {
Self::is_exhausted_(self.cursor, self.len)
}
pub fn remaining(&self) -> usize {
Self::remaining_(self.cursor, self.len).max(0) as usize
}
pub fn peek_until_end(&self) -> &[u8] {
Self::peek_until_end_(self.cursor, self.len, &self.t)
}
pub fn take_until_end(&mut self) -> &[u8] {
Self::take_until_end_(&mut self.cursor, self.len, &self.t)
}
pub fn position(&self) -> usize {
self.cursor
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
pub fn peek_until_end() {
let cur = Cursor::new(vec![]);
assert_eq!(cur.peek_until_end(), &[]);
let cur = Cursor::new(vec![1, 2, 3]);
assert_eq!(cur.peek_until_end(), &[1, 2, 3]);
let mut cur = Cursor::new(vec![1, 2, 3]);
cur.skip(1);
assert_eq!(cur.peek_until_end(), &[2, 3]);
}
#[test]
pub fn take_until_end() {
let mut cur = Cursor::new(vec![]);
assert_eq!(cur.take_until_end(), &[]);
assert_eq!(cur.take_until_end(), &[]);
assert_eq!(cur.take_until_end(), &[]);
let mut cur = Cursor::new(vec![1, 2, 3]);
assert_eq!(cur.take_until_end(), &[1, 2, 3]);
let mut cur = Cursor::new(vec![1, 2, 3]);
cur.skip(1);
assert_eq!(cur.take_until_end(), &[2, 3]);
assert_eq!(cur.peek_until_end(), &[]);
}
#[test]
pub fn next() {
let mut cur = Cursor::new(vec![1]);
assert_eq!(cur.next(), Some(1));
assert_eq!(cur.next(), None);
assert_eq!(cur.next(), None);
}
#[test]
pub fn take() {
let mut cur = Cursor::new(vec![1, 2, 3]);
assert_eq!(cur.take(2), &[1, 2]);
assert_eq!(cur.take(1), &[3]);
assert_eq!(cur.take(1), &[]);
}
#[test]
pub fn peek() {
let mut cur = Cursor::new(vec![1, 2, 3]);
assert_eq!(cur.peek(2), &[1, 2]);
assert_eq!(cur.peek(1), &[1]);
assert_eq!(cur.peek(4), &[1, 2, 3]);
cur.take(3);
assert_eq!(cur.peek(1), &[]);
}
#[test]
pub fn take_exact() {
let mut cur = Cursor::new(vec![1, 2, 3]);
assert_eq!(cur.take_exact(2), Some([1, 2].as_ref()));
assert_eq!(cur.take_exact(2), None);
assert_eq!(cur.take_exact(1), Some([3].as_ref()));
}
#[test]
pub fn peek_exact() {
let cur = Cursor::new(vec![1, 2, 3]);
assert_eq!(cur.peek_exact(3), Some([1, 2, 3].as_ref()));
assert_eq!(cur.peek_exact(1), Some([1].as_ref()));
assert_eq!(cur.peek_exact(4), None);
}
#[test]
pub fn take_while() {
let til_slash = |c: &mut Cursor<&str>| {
core::str::from_utf8(c.take_while(|b| (b as char) != '/')).unwrap()
.to_string()
};
let mut cur = Cursor::new("abc/def");
assert_eq!(til_slash(&mut cur), "abc".to_string());
cur.skip(1);
assert_eq!(til_slash(&mut cur), "def".to_string());
assert_eq!(til_slash(&mut cur), "".to_string());
let mut cur = Cursor::new("a");
assert_eq!(til_slash(&mut cur), "a");
let mut cur = Cursor::new("");
assert_eq!(til_slash(&mut cur), "");
let mut cur = Cursor::new("ab");
assert_eq!(til_slash(&mut cur), "ab");
let mut cur = Cursor::new("/abcd");
assert_eq!(til_slash(&mut cur), "");
}
#[test]
pub fn seek() {
let mut cur = Cursor::new(vec![1, 2, 3, 4]);
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); }
}