use crate::{EdError, InternalError, Result};
use std::fmt::Debug;
pub trait Snapshot{
fn create_snapshot(&self) -> Self;
}
#[derive(Clone, Debug)]
pub struct History<T> where
T: Default + Debug + Snapshot + PartialEq,
{
snapshots: Vec<T>,
viewed_i: usize,
saved_i: Option<usize>,
pub dont_snapshot: bool,
}
impl<T> Default for History<T> where
T: Default + Debug + Snapshot + PartialEq,
{
fn default() -> Self { Self::new() }
}
impl <T> History<T> where
T: Default + Debug + Snapshot + PartialEq,
{
pub fn new() -> Self {
Self{
snapshots: vec![T::default()],
viewed_i: 0,
saved_i: Some(0),
dont_snapshot: false,
}
}
pub fn saved(&self) -> bool {
self.saved_i == Some(self.viewed_i)
}
pub fn set_saved(&mut self) {
if !self.dont_snapshot {
self.saved_i = Some(self.viewed_i);
} else {
self.saved_i = None;
}
}
pub fn set_unsaved(&mut self) {
self.saved_i = None;
}
pub fn current(&self) -> &T {
&self.snapshots[self.viewed_i]
}
pub fn current_mut(&mut self) -> Result<&mut T> {
self.snapshot()?;
Ok(&mut self.snapshots[self.viewed_i])
}
pub fn undo(&mut self,
steps: isize,
) -> Result<()> {
let range = self.undo_range()?;
if !range.contains(&steps) {
Err(EdError::UndoStepsInvalid{undo_steps: steps, undo_range: range})?
}
if steps.is_negative() {
self.viewed_i += (-steps) as usize;
} else {
self.viewed_i -= steps as usize;
}
Ok(())
}
pub fn undo_range(&self) -> Result<std::ops::Range<isize>> {
if self.snapshots.len() < isize::MAX as usize && self.viewed_i < self.snapshots.len() {
Ok(self.viewed_i as isize - self.snapshots.len() as isize +1 .. self.viewed_i as isize + 1)
} else {
Err(InternalError::UndoHistoryTooLarge.into())
}
}
fn internal_create_snapshot(&mut self) {
self.snapshots.push(self.snapshots[self.viewed_i].create_snapshot());
self.viewed_i = self.snapshots.len() - 1;
}
pub fn snapshot(&mut self) -> Result<()> {
if self.snapshots.len() + 2 > isize::MAX as usize {
Err(InternalError::UndoHistoryTooLarge)?;
}
if self.viewed_i < self.snapshots.len() - 1 {
self.internal_create_snapshot();
}
if !self.dont_snapshot {
self.internal_create_snapshot();
}
Ok(())
}
pub fn dedup_present(&mut self) {
let mut last_2_iter = self.snapshots.iter().rev().take(2);
if last_2_iter.next() == last_2_iter.next() {
self.snapshots.pop();
self.viewed_i = self.snapshots.len() - 1;
}
}
}