mod builder;
mod checkpoint;
mod display;
mod queue;
pub use builder::Builder;
pub use checkpoint::Checkpoint;
pub use display::Display;
pub use queue::Queue;
use crate::socket::{Slot, Socket};
use crate::{Edit, Entry, Event, Merged};
use alloc::collections::VecDeque;
use alloc::string::{String, ToString};
use alloc::vec::Vec;
use core::fmt;
use core::num::NonZeroUsize;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[derive(Clone, Debug)]
pub struct Record<E, S = ()> {
limit: NonZeroUsize,
index: usize,
pub(crate) saved: Option<usize>,
pub(crate) socket: Socket<S>,
pub(crate) entries: VecDeque<Entry<E>>,
}
impl<E> Record<E> {
pub fn new() -> Record<E> {
Record::builder().build()
}
}
impl<E, S> Record<E, S> {
pub fn builder() -> Builder<E, S> {
Builder::default()
}
pub fn reserve(&mut self, additional: usize) {
self.entries.reserve(additional);
}
pub fn capacity(&self) -> usize {
self.entries.capacity()
}
pub fn shrink_to_fit(&mut self) {
self.entries.shrink_to_fit();
}
pub fn len(&self) -> usize {
self.entries.len()
}
pub fn is_empty(&self) -> bool {
self.entries.is_empty()
}
pub fn limit(&self) -> usize {
self.limit.get()
}
pub fn connect(&mut self, slot: S) -> Option<S> {
self.socket.connect(Some(slot))
}
pub fn disconnect(&mut self) -> Option<S> {
self.socket.disconnect()
}
pub fn can_undo(&self) -> bool {
self.index > 0
}
pub fn can_redo(&self) -> bool {
self.index < self.len()
}
pub fn is_saved(&self) -> bool {
self.saved == Some(self.index)
}
pub fn saved(&self) -> Option<usize> {
self.saved
}
pub fn head(&self) -> usize {
self.index
}
pub fn get_entry(&self, index: usize) -> Option<&Entry<E>> {
self.entries.get(index)
}
pub fn entries(&self) -> impl Iterator<Item = &Entry<E>> {
self.entries.iter()
}
pub fn queue(&mut self) -> Queue<E, S> {
Queue::from(self)
}
pub fn checkpoint(&mut self) -> Checkpoint<E, S> {
Checkpoint::from(self)
}
pub fn display(&self) -> Display<E, S> {
Display::from(self)
}
pub(crate) fn rm_tail(&mut self) -> (VecDeque<Entry<E>>, Option<usize>) {
let rm_saved = if self.saved > Some(self.index) {
self.saved.take()
} else {
None
};
let tail = self.entries.split_off(self.index);
(tail, rm_saved)
}
}
impl<E, S: Slot> Record<E, S> {
pub fn set_saved(&mut self) {
let was_saved = self.is_saved();
self.saved = Some(self.index);
self.socket.emit_if(!was_saved, || Event::Saved(true));
}
pub fn clear_saved(&mut self) {
let was_saved = self.is_saved();
self.saved = None;
self.socket.emit_if(was_saved, || Event::Saved(false));
}
pub fn clear(&mut self) {
let old_index = self.index;
let could_undo = self.can_undo();
let could_redo = self.can_redo();
self.entries.clear();
self.saved = self.is_saved().then_some(0);
self.index = 0;
self.socket.emit_if(could_undo, || Event::Undo(false));
self.socket.emit_if(could_redo, || Event::Redo(false));
self.socket.emit_if(old_index != 0, || Event::Index(0));
}
}
impl<E: Edit, S: Slot> Record<E, S> {
pub fn edit(&mut self, target: &mut E::Target, edit: E) -> E::Output {
let (output, _, _, _) = self.edit_and_push(target, Entry::new(edit));
output
}
pub(crate) fn edit_and_push(
&mut self,
target: &mut E::Target,
mut entry: Entry<E>,
) -> (E::Output, bool, VecDeque<Entry<E>>, Option<usize>) {
let output = entry.edit(target);
let (merged_or_annulled, tail, rm_saved) = self.push(entry);
(output, merged_or_annulled, tail, rm_saved)
}
pub(crate) fn redo_and_push(
&mut self,
target: &mut E::Target,
mut entry: Entry<E>,
) -> (E::Output, bool, VecDeque<Entry<E>>, Option<usize>) {
let output = entry.redo(target);
let (merged_or_annulled, tail, rm_saved) = self.push(entry);
(output, merged_or_annulled, tail, rm_saved)
}
fn push(&mut self, entry: Entry<E>) -> (bool, VecDeque<Entry<E>>, Option<usize>) {
let old_index = self.index;
let could_undo = self.can_undo();
let could_redo = self.can_redo();
let was_saved = self.is_saved();
let (tail, rm_saved) = self.rm_tail();
let merged = match self.entries.back_mut() {
Some(last) if !was_saved => last.merge(entry),
_ => Merged::No(entry),
};
let merged_or_annulled = match merged {
Merged::Yes => true,
Merged::Annul => {
self.entries.pop_back();
self.index -= 1;
true
}
Merged::No(entry) => {
if self.limit() == self.index {
self.entries.pop_front();
self.saved = self.saved.and_then(|saved| saved.checked_sub(1));
} else {
self.index += 1;
}
self.entries.push_back(entry);
false
}
};
self.socket.emit_if(could_redo, || Event::Redo(false));
self.socket.emit_if(!could_undo, || Event::Undo(true));
self.socket.emit_if(was_saved, || Event::Saved(false));
self.socket
.emit_if(old_index != self.index, || Event::Index(self.index));
(merged_or_annulled, tail, rm_saved)
}
pub fn undo(&mut self, target: &mut E::Target) -> Option<E::Output> {
self.can_undo().then(|| {
let old_index = self.index;
let was_saved = self.is_saved();
let output = self.entries[self.index - 1].undo(target);
self.index -= 1;
let is_saved = self.is_saved();
self.socket.emit_if(old_index == 1, || Event::Undo(false));
self.socket
.emit_if(old_index == self.entries.len(), || Event::Redo(true));
self.socket
.emit_if(was_saved != is_saved, || Event::Saved(is_saved));
self.socket.emit(|| Event::Index(self.index));
output
})
}
pub fn redo(&mut self, target: &mut E::Target) -> Option<E::Output> {
self.can_redo().then(|| {
let old_index = self.index;
let was_saved = self.is_saved();
let output = self.entries[self.index].redo(target);
self.index += 1;
let is_saved = self.is_saved();
self.socket.emit_if(old_index == 0, || Event::Undo(true));
self.socket
.emit_if(old_index == self.len() - 1, || Event::Redo(false));
self.socket
.emit_if(was_saved != is_saved, || Event::Saved(is_saved));
self.socket.emit(|| Event::Index(self.index));
output
})
}
pub fn revert(&mut self, target: &mut E::Target) -> Vec<E::Output> {
self.saved
.map_or_else(Vec::new, |saved| self.go_to(target, saved))
}
pub fn go_to(&mut self, target: &mut E::Target, index: usize) -> Vec<E::Output> {
if self.index == index || index > self.len() {
return Vec::new();
}
let could_undo = self.can_undo();
let could_redo = self.can_redo();
let was_saved = self.is_saved();
let slot = self.socket.disconnect();
let undo_or_redo = if index > self.index {
Record::redo
} else {
Record::undo
};
let capacity = self.index.abs_diff(index);
let mut outputs = Vec::with_capacity(capacity);
while self.index != index {
let output = undo_or_redo(self, target).unwrap();
outputs.push(output);
}
let can_undo = self.can_undo();
let can_redo = self.can_redo();
let is_saved = self.is_saved();
self.socket.connect(slot);
self.socket
.emit_if(could_undo != can_undo, || Event::Undo(can_undo));
self.socket
.emit_if(could_redo != can_redo, || Event::Redo(can_redo));
self.socket
.emit_if(was_saved != is_saved, || Event::Saved(is_saved));
self.socket.emit(|| Event::Index(self.index));
outputs
}
}
impl<E: fmt::Display, S> Record<E, S> {
pub fn undo_string(&self) -> Option<String> {
self.index.checked_sub(1).and_then(|i| self.string_at(i))
}
pub fn redo_string(&self) -> Option<String> {
self.string_at(self.index)
}
fn string_at(&self, i: usize) -> Option<String> {
self.entries.get(i).map(|e| e.to_string())
}
}
impl<E> Default for Record<E> {
fn default() -> Record<E> {
Record::new()
}
}