use crate::{EmptyHistoryError, Select, INVARIANT_UNWRAP};
use std::collections::TryReserveError;
use std::ops::{Bound, RangeBounds};
#[derive(Debug)]
#[repr(transparent)]
pub struct Snaplog<T> {
history: Vec<T>,
}
impl<T> Snaplog<T> {
pub fn new(initial: T) -> Self {
Self {
history: vec![initial],
}
}
pub fn try_from_vec(history: Vec<T>) -> Result<Self, EmptyHistoryError> {
if history.is_empty() {
Err(EmptyHistoryError(()))
} else {
Ok(Self { history })
}
}
pub fn from_vec(history: Vec<T>) -> Self {
match Self::try_from_vec(history) {
Ok(this) => this,
Err(_) => panic!("history must not be empty"),
}
}
pub fn try_from_history<I>(history: I) -> Result<Self, EmptyHistoryError>
where
I: IntoIterator<Item = T>,
{
Self::try_from_vec(history.into_iter().collect())
}
pub fn from_history<I>(history: I) -> Self
where
I: IntoIterator<Item = T>,
{
Self::from_vec(history.into_iter().collect())
}
}
impl<T> Snaplog<T> {
pub fn record(&mut self, snapshot: T) {
self.history.push(snapshot);
}
pub fn record_all<I>(&mut self, snapshots: I)
where
I: IntoIterator<Item = T>,
{
self.history.extend(snapshots);
}
pub fn record_change<F>(&mut self, mut f: F)
where
F: FnMut(&T) -> T,
{
self.history.push(f(self.current()));
}
pub fn try_record_change<F, E>(&mut self, mut f: F) -> Result<(), E>
where
F: FnMut(&T) -> Result<T, E>,
{
self.history.push(f(self.current())?);
Ok(())
}
pub fn record_changes_all<F, M>(&mut self, mutations: &mut [M], mut f: F)
where
F: FnMut(&mut M, &T) -> T,
{
self.history.reserve(mutations.len());
for mutation in mutations {
self.history.push(f(mutation, self.current()));
}
}
pub fn has_changes(&self) -> bool {
self.history.len() > 1
}
pub fn initial(&self) -> &T {
self.history.first().expect(INVARIANT_UNWRAP)
}
pub fn snapshot_at(&self, select: Select) -> &T {
select.index_into(&self.history)
}
pub fn current(&self) -> &T {
self.history.last().expect(INVARIANT_UNWRAP)
}
pub fn initial_mut(&mut self) -> &mut T {
self.history.first_mut().expect(INVARIANT_UNWRAP)
}
pub fn snapshot_at_mut(&mut self, select: Select) -> &mut T {
select.index_into_mut(&mut self.history)
}
pub fn current_mut(&mut self) -> &mut T {
self.history.last_mut().expect(INVARIANT_UNWRAP)
}
pub fn clone_snapshot_at(&self, select: Select) -> T
where
T: Clone,
{
select.index_into(&self.history).clone()
}
pub fn history(&self) -> &[T] {
self.history.as_slice()
}
pub fn history_mut(&mut self) -> &mut [T] {
self.history.as_mut_slice()
}
pub fn drain<R>(&mut self, range: R) -> impl Iterator<Item = T> + '_
where
R: RangeBounds<usize>,
{
let start_bound = match range.start_bound() {
Bound::Included(&idx) if idx == 0 => panic!("cannot drain initial element"),
Bound::Included(&idx) => Bound::Included(idx),
Bound::Excluded(&idx) => Bound::Excluded(idx),
Bound::Unbounded => Bound::Excluded(0),
};
self.history
.drain((start_bound, range.end_bound().cloned()))
}
pub fn clear_history(&mut self) {
self.history.drain(..self.history.len() - 1);
}
pub fn reset(&mut self) {
self.history.drain(1..);
}
pub fn reserve(&mut self, n: usize) {
self.history.reserve(n);
}
pub fn try_reserve(&mut self, n: usize) -> Result<(), TryReserveError> {
self.history.try_reserve(n)
}
pub fn iter(&self) -> Iter<'_, T> {
self.history.iter()
}
pub fn iter_mut(&mut self) -> IterMut<'_, T> {
self.history.iter_mut()
}
pub fn into_initial(mut self) -> T {
self.history.swap_remove(0)
}
pub fn into_current(mut self) -> T {
self.history.pop().expect(INVARIANT_UNWRAP)
}
pub fn into_snapshot_at(mut self, select: Select) -> T {
select.index_into_remove(&mut self.history)
}
pub fn into_inner(self) -> Vec<T> {
self.history
}
}
impl<T> Snaplog<T> {
pub unsafe fn from_vec_unchecked(history: Vec<T>) -> Self {
Self { history }
}
pub unsafe fn from_history_unchecked<I>(history: I) -> Self
where
I: IntoIterator<Item = T>,
{
unsafe { Self::from_vec_unchecked(history.into_iter().collect()) }
}
pub unsafe fn history_mut_vec(&mut self) -> &mut Vec<T> {
&mut self.history
}
}
impl<T: PartialEq> PartialEq for Snaplog<T> {
fn eq(&self, other: &Self) -> bool {
if self.initial() == other.initial() && self.history.len() == other.history.len() {
if self.has_changes() {
(self.history.last() == other.history.last())
&& (self.history[1..self.history.len() - 1]
== other.history[1..other.history.len() - 1])
} else {
true }
} else {
false }
}
}
impl<T: Eq> Eq for Snaplog<T> {}
impl<T: Clone> Clone for Snaplog<T> {
fn clone(&self) -> Self {
Self {
history: self.history.clone(),
}
}
fn clone_from(&mut self, source: &Self) {
self.history.clone_from(&source.history)
}
}
impl<T> std::ops::Index<Select> for Snaplog<T> {
type Output = T;
fn index(&self, index: Select) -> &Self::Output {
self.snapshot_at(index)
}
}
impl<T> std::ops::IndexMut<Select> for Snaplog<T> {
fn index_mut(&mut self, index: Select) -> &mut Self::Output {
self.snapshot_at_mut(index)
}
}
impl<T> std::iter::Extend<T> for Snaplog<T> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
self.history.extend(iter);
}
}
pub type IntoIter<T> = std::vec::IntoIter<T>;
impl<T> IntoIterator for Snaplog<T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
self.history.into_iter()
}
}
pub type Iter<'cl, T> = std::slice::Iter<'cl, T>;
impl<'cl, T> IntoIterator for &'cl Snaplog<T> {
type Item = &'cl T;
type IntoIter = Iter<'cl, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
pub type IterMut<'cl, T> = std::slice::IterMut<'cl, T>;
impl<'cl, T> IntoIterator for &'cl mut Snaplog<T> {
type Item = &'cl mut T;
type IntoIter = IterMut<'cl, T>;
fn into_iter(self) -> Self::IntoIter {
self.iter_mut()
}
}
impl<T> From<T> for Snaplog<T> {
fn from(initial: T) -> Self {
Self::new(initial)
}
}
impl<T> From<Snaplog<T>> for Vec<T> {
fn from(snaplog: Snaplog<T>) -> Self {
snaplog.into_inner()
}
}
impl<T> TryFrom<Vec<T>> for Snaplog<T> {
type Error = EmptyHistoryError;
fn try_from(value: Vec<T>) -> Result<Self, Self::Error> {
Self::try_from_vec(value)
}
}