Created
October 3, 2021 06:31
-
-
Save jonpalmisc/ed3708deb60070dd332fbfa123c62f3f to your computer and use it in GitHub Desktop.
Rust: DataView
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/// DataView wraps a vector and provides a multi-cursor interface over it. | |
#[derive(Clone, Debug)] | |
pub struct DataView<'a, T> { | |
data: &'a Vec<T>, | |
pivot_pos: usize, | |
cursor_pos: usize, | |
} | |
#[allow(dead_code)] | |
impl<'a, T: std::cmp::PartialEq + std::clone::Clone> DataView<'a, T> { | |
/// Create a new DataView backed by the given vector. | |
pub fn new(data: &'a Vec<T>) -> Self { | |
DataView { | |
data, | |
pivot_pos: 0, | |
cursor_pos: 0, | |
} | |
} | |
/// Get the underlying data. | |
pub fn data(&self) -> &'a Vec<T> { | |
self.data | |
} | |
/// Get the length of the underlying data. | |
pub fn len(&self) -> usize { | |
self.data.len() | |
} | |
/// Get the index of the cursor. | |
pub fn cursor_pos(&self) -> usize { | |
self.cursor_pos | |
} | |
/// Get the index of the pivot. | |
pub fn pivot_pos(&self) -> usize { | |
self.pivot_pos | |
} | |
/// Get at the element under the cursor. Will return `None` if the cursor is | |
/// past the end of the data. | |
pub fn peek(&self) -> Option<&T> { | |
self.data.get(self.cursor_pos) | |
} | |
/// Peek at the next N elements from the cursor. Will return `None` if | |
/// cursor index + N is past the end of the data. | |
pub fn peek_many(&self, n: usize) -> Option<&[T]> { | |
if self.cursor_pos + n >= self.data.len() { | |
None | |
} else { | |
Some(&self.data[self.cursor_pos..self.cursor_pos + n]) | |
} | |
} | |
/// Get the element under the cursor, then advance the cursor. This method | |
/// can potentially advance the cursor to an invalid index. Will return | |
/// `None` if the cursor is past the end of the data. | |
pub fn next(&mut self) -> Option<&T> { | |
self.cursor_pos += 1; | |
self.data.get(self.cursor_pos - 1) | |
} | |
/// Shorthand for doing `next()` then `reset_pivot()`. | |
pub fn next_and_reset(&mut self) -> Option<&T> { | |
self.cursor_pos += 1; | |
self.pivot_pos = self.cursor_pos; | |
self.data.get(self.cursor_pos - 1) | |
} | |
/// Advance the cursor to skip N elements. | |
pub fn skip(&mut self, n: usize) { | |
self.cursor_pos += n; | |
} | |
/// Advance the pivot to the cursor. This method can potentially advance the | |
/// pivot to an invalid index if the cursor is already at an invalid index. | |
pub fn reset_pivot(&mut self) { | |
self.pivot_pos = self.cursor_pos | |
} | |
/// Get the elements between the pivot and the cursor. | |
pub fn window(&self) -> Option<&[T]> { | |
if self.pivot_pos >= self.len() || self.cursor_pos >= self.len() { | |
None | |
} else { | |
Some(&self.data[self.pivot_pos..self.cursor_pos]) | |
} | |
} | |
/// Get the elements between the pivot and the cursor as a Vec<T>. | |
pub fn owned_window(&self) -> Option<Vec<T>> { | |
self.window().map(|w| w.to_vec()) | |
} | |
/// Move the cursor until the next element is (not) in the given set. | |
pub fn advance_set(&mut self, set: &[T], include: bool) { | |
while let Some(c) = self.peek() { | |
if include == set.contains(c) && self.next().is_some() { | |
continue; | |
} | |
break; | |
} | |
} | |
/// Move the cursor each time the test function returns true. | |
pub fn advance_while(&mut self, test: fn(&T) -> bool) { | |
while let Some(t) = self.peek() { | |
if test(t) && self.next().is_some() { | |
continue; | |
} | |
break; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment