#![allow(dead_code)]
pub struct ZipperList<T> {
left: Vec<T>,
focus: Option<T>,
right: Vec<T>,
}
impl<T: Clone> ZipperList<T> {
pub fn from_slice(items: &[T]) -> Self {
if items.is_empty() {
return Self {
left: Vec::new(),
focus: None,
right: Vec::new(),
};
}
Self {
left: Vec::new(),
focus: Some(items[0].clone()),
right: items[1..].to_vec(),
}
}
pub fn has_focus(&self) -> bool {
self.focus.is_some()
}
pub fn peek(&self) -> Option<&T> {
self.focus.as_ref()
}
pub fn move_right(&mut self) -> bool {
if self.right.is_empty() {
return false;
}
if let Some(f) = self.focus.take() {
self.left.push(f);
}
self.focus = Some(self.right.remove(0));
true
}
pub fn move_left(&mut self) -> bool {
if self.left.is_empty() {
return false;
}
if let Some(f) = self.focus.take() {
self.right.insert(0, f);
}
self.focus = self.left.pop();
true
}
pub fn insert_before(&mut self, value: T) {
self.left.insert(0, value);
}
pub fn insert_after(&mut self, value: T) {
self.right.insert(0, value);
}
pub fn remove_focus(&mut self) -> Option<T> {
let removed = self.focus.take()?;
if !self.right.is_empty() {
self.focus = Some(self.right.remove(0));
} else if !self.left.is_empty() {
self.focus = self.left.pop();
}
Some(removed)
}
pub fn to_vec(&self) -> Vec<T> {
let mut v: Vec<T> = self.left.iter().rev().cloned().collect();
if let Some(f) = &self.focus {
v.push(f.clone());
}
v.extend(self.right.iter().cloned());
v
}
pub fn len(&self) -> usize {
self.left.len() + self.focus.as_ref().map(|_| 1).unwrap_or(0) + self.right.len()
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
}
pub fn new_zipper_list<T: Clone>(items: &[T]) -> ZipperList<T> {
ZipperList::from_slice(items)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_focus_first_element() {
let z = ZipperList::from_slice(&[1, 2, 3]);
assert_eq!(z.peek(), Some(&1));
}
#[test]
fn test_move_right() {
let mut z = ZipperList::from_slice(&[1, 2, 3]);
z.move_right();
assert_eq!(z.peek(), Some(&2));
}
#[test]
fn test_move_left() {
let mut z = ZipperList::from_slice(&[1, 2, 3]);
z.move_right();
z.move_left();
assert_eq!(z.peek(), Some(&1));
}
#[test]
fn test_to_vec_preserves_order() {
let z = ZipperList::from_slice(&[1, 2, 3]);
assert_eq!(z.to_vec(), vec![1, 2, 3]);
}
#[test]
fn test_insert_before() {
let mut z = ZipperList::from_slice(&[1, 3]);
z.move_right();
z.insert_before(2);
assert_eq!(z.to_vec(), vec![1, 2, 3]);
}
#[test]
fn test_insert_after() {
let mut z = ZipperList::from_slice(&[1, 3]);
z.insert_after(2);
assert_eq!(z.to_vec(), vec![1, 2, 3]);
}
#[test]
fn test_remove_focus() {
let mut z = ZipperList::from_slice(&[1, 2, 3]);
let removed = z.remove_focus();
assert_eq!(removed, Some(1));
assert_eq!(z.peek(), Some(&2));
}
#[test]
fn test_len() {
let z = ZipperList::from_slice(&[1, 2, 3]);
assert_eq!(z.len(), 3);
}
#[test]
fn test_is_empty() {
let z: ZipperList<i32> = ZipperList::from_slice(&[]);
assert!(z.is_empty());
}
#[test]
fn test_new_helper() {
let z = new_zipper_list(&[10, 20]);
assert_eq!(z.peek(), Some(&10));
}
}