2014-07-22 06:40:51 -05:00
|
|
|
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
|
|
|
|
// file at the top-level directory of this distribution and at
|
|
|
|
// http://rust-lang.org/COPYRIGHT.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
|
|
|
// option. This file may not be copied, modified, or distributed
|
|
|
|
// except according to those terms.
|
|
|
|
|
2014-11-25 20:17:11 -06:00
|
|
|
//! A utility class for implementing "snapshottable" things; a snapshottable data structure permits
|
|
|
|
//! you to take a snapshot (via `start_snapshot`) and then, after making some changes, elect either
|
|
|
|
//! to rollback to the start of the snapshot or commit those changes.
|
|
|
|
//!
|
|
|
|
//! This vector is intended to be used as part of an abstraction, not serve as a complete
|
|
|
|
//! abstraction on its own. As such, while it will roll back most changes on its own, it also
|
2015-01-06 19:53:18 -06:00
|
|
|
//! supports a `get_mut` operation that gives you an arbitrary mutable pointer into the vector. To
|
2014-11-25 20:17:11 -06:00
|
|
|
//! ensure that any changes you make this with this pointer are rolled back, you must invoke
|
|
|
|
//! `record` to record any changes you make and also supplying a delegate capable of reversing
|
|
|
|
//! those changes.
|
2014-11-06 02:05:53 -06:00
|
|
|
use self::UndoLog::*;
|
2014-07-22 06:40:51 -05:00
|
|
|
|
|
|
|
use std::mem;
|
2015-04-07 05:11:49 -05:00
|
|
|
use std::ops;
|
2014-07-22 06:40:51 -05:00
|
|
|
|
2015-01-21 19:25:24 -06:00
|
|
|
pub enum UndoLog<D:SnapshotVecDelegate> {
|
2014-07-22 06:40:51 -05:00
|
|
|
/// Indicates where a snapshot started.
|
|
|
|
OpenSnapshot,
|
|
|
|
|
|
|
|
/// Indicates a snapshot that has been committed.
|
|
|
|
CommittedSnapshot,
|
|
|
|
|
|
|
|
/// New variable with given index was created.
|
2015-03-25 19:06:52 -05:00
|
|
|
NewElem(usize),
|
2014-07-22 06:40:51 -05:00
|
|
|
|
|
|
|
/// Variable with given index was changed *from* the given value.
|
2015-03-25 19:06:52 -05:00
|
|
|
SetElem(usize, D::Value),
|
2014-07-22 06:40:51 -05:00
|
|
|
|
|
|
|
/// Extensible set of actions
|
2015-01-21 19:25:24 -06:00
|
|
|
Other(D::Undo)
|
2014-07-22 06:40:51 -05:00
|
|
|
}
|
|
|
|
|
2015-01-21 19:25:24 -06:00
|
|
|
pub struct SnapshotVec<D:SnapshotVecDelegate> {
|
|
|
|
values: Vec<D::Value>,
|
|
|
|
undo_log: Vec<UndoLog<D>>,
|
2014-07-22 06:40:51 -05:00
|
|
|
}
|
|
|
|
|
2014-12-13 22:06:44 -06:00
|
|
|
// Snapshots are tokens that should be created/consumed linearly.
|
2014-07-22 06:40:51 -05:00
|
|
|
pub struct Snapshot {
|
|
|
|
// Length of the undo log at the time the snapshot was taken.
|
2015-03-25 19:06:52 -05:00
|
|
|
length: usize,
|
2014-07-22 06:40:51 -05:00
|
|
|
}
|
|
|
|
|
2015-01-21 19:25:24 -06:00
|
|
|
pub trait SnapshotVecDelegate {
|
|
|
|
type Value;
|
|
|
|
type Undo;
|
|
|
|
|
2015-04-07 05:11:49 -05:00
|
|
|
fn reverse(values: &mut Vec<Self::Value>, action: Self::Undo);
|
2014-07-22 06:40:51 -05:00
|
|
|
}
|
|
|
|
|
2015-01-21 19:25:24 -06:00
|
|
|
impl<D:SnapshotVecDelegate> SnapshotVec<D> {
|
2015-04-07 05:11:49 -05:00
|
|
|
pub fn new() -> SnapshotVec<D> {
|
2014-07-22 06:40:51 -05:00
|
|
|
SnapshotVec {
|
|
|
|
values: Vec::new(),
|
|
|
|
undo_log: Vec::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn in_snapshot(&self) -> bool {
|
|
|
|
!self.undo_log.is_empty()
|
|
|
|
}
|
|
|
|
|
2015-01-21 19:25:24 -06:00
|
|
|
pub fn record(&mut self, action: D::Undo) {
|
2014-07-22 06:40:51 -05:00
|
|
|
if self.in_snapshot() {
|
|
|
|
self.undo_log.push(Other(action));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-07 05:11:49 -05:00
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
self.values.len()
|
|
|
|
}
|
|
|
|
|
2015-03-25 19:06:52 -05:00
|
|
|
pub fn push(&mut self, elem: D::Value) -> usize {
|
2014-07-22 06:40:51 -05:00
|
|
|
let len = self.values.len();
|
|
|
|
self.values.push(elem);
|
|
|
|
|
|
|
|
if self.in_snapshot() {
|
|
|
|
self.undo_log.push(NewElem(len));
|
|
|
|
}
|
|
|
|
|
|
|
|
len
|
|
|
|
}
|
|
|
|
|
2015-03-25 19:06:52 -05:00
|
|
|
pub fn get<'a>(&'a self, index: usize) -> &'a D::Value {
|
2014-10-15 01:05:01 -05:00
|
|
|
&self.values[index]
|
2014-07-22 06:40:51 -05:00
|
|
|
}
|
|
|
|
|
2014-11-25 20:17:11 -06:00
|
|
|
/// Returns a mutable pointer into the vec; whatever changes you make here cannot be undone
|
|
|
|
/// automatically, so you should be sure call `record()` with some sort of suitable undo
|
|
|
|
/// action.
|
2015-03-25 19:06:52 -05:00
|
|
|
pub fn get_mut<'a>(&'a mut self, index: usize) -> &'a mut D::Value {
|
2014-10-23 10:42:21 -05:00
|
|
|
&mut self.values[index]
|
2014-07-22 06:40:51 -05:00
|
|
|
}
|
|
|
|
|
2014-11-25 20:17:11 -06:00
|
|
|
/// Updates the element at the given index. The old value will saved (and perhaps restored) if
|
|
|
|
/// a snapshot is active.
|
2015-03-25 19:06:52 -05:00
|
|
|
pub fn set(&mut self, index: usize, new_elem: D::Value) {
|
2014-10-23 10:42:21 -05:00
|
|
|
let old_elem = mem::replace(&mut self.values[index], new_elem);
|
2014-07-22 06:40:51 -05:00
|
|
|
if self.in_snapshot() {
|
|
|
|
self.undo_log.push(SetElem(index, old_elem));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn start_snapshot(&mut self) -> Snapshot {
|
|
|
|
let length = self.undo_log.len();
|
|
|
|
self.undo_log.push(OpenSnapshot);
|
2014-12-13 22:06:44 -06:00
|
|
|
Snapshot { length: length }
|
2014-07-22 06:40:51 -05:00
|
|
|
}
|
|
|
|
|
2014-12-01 09:11:59 -06:00
|
|
|
pub fn actions_since_snapshot(&self,
|
|
|
|
snapshot: &Snapshot)
|
2015-01-21 19:25:24 -06:00
|
|
|
-> &[UndoLog<D>] {
|
2015-01-07 10:58:31 -06:00
|
|
|
&self.undo_log[snapshot.length..]
|
2014-12-01 09:11:59 -06:00
|
|
|
}
|
|
|
|
|
2014-07-22 06:40:51 -05:00
|
|
|
fn assert_open_snapshot(&self, snapshot: &Snapshot) {
|
|
|
|
// Or else there was a failure to follow a stack discipline:
|
|
|
|
assert!(self.undo_log.len() > snapshot.length);
|
|
|
|
|
|
|
|
// Invariant established by start_snapshot():
|
|
|
|
assert!(
|
2014-10-15 01:05:01 -05:00
|
|
|
match self.undo_log[snapshot.length] {
|
2014-07-22 06:40:51 -05:00
|
|
|
OpenSnapshot => true,
|
|
|
|
_ => false
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn rollback_to(&mut self, snapshot: Snapshot) {
|
|
|
|
debug!("rollback_to({})", snapshot.length);
|
|
|
|
|
|
|
|
self.assert_open_snapshot(&snapshot);
|
|
|
|
|
|
|
|
while self.undo_log.len() > snapshot.length + 1 {
|
|
|
|
match self.undo_log.pop().unwrap() {
|
|
|
|
OpenSnapshot => {
|
|
|
|
// This indicates a failure to obey the stack discipline.
|
2014-10-09 14:17:22 -05:00
|
|
|
panic!("Cannot rollback an uncommitted snapshot");
|
2014-07-22 06:40:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
CommittedSnapshot => {
|
|
|
|
// This occurs when there are nested snapshots and
|
2014-09-02 00:35:58 -05:00
|
|
|
// the inner is committed but outer is rolled back.
|
2014-07-22 06:40:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
NewElem(i) => {
|
|
|
|
self.values.pop();
|
|
|
|
assert!(self.values.len() == i);
|
|
|
|
}
|
|
|
|
|
|
|
|
SetElem(i, v) => {
|
2014-10-23 10:42:21 -05:00
|
|
|
self.values[i] = v;
|
2014-07-22 06:40:51 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
Other(u) => {
|
2015-04-07 05:11:49 -05:00
|
|
|
D::reverse(&mut self.values, u);
|
2014-07-22 06:40:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let v = self.undo_log.pop().unwrap();
|
|
|
|
assert!(match v { OpenSnapshot => true, _ => false });
|
|
|
|
assert!(self.undo_log.len() == snapshot.length);
|
|
|
|
}
|
|
|
|
|
2014-11-24 19:06:06 -06:00
|
|
|
/// Commits all changes since the last snapshot. Of course, they
|
|
|
|
/// can still be undone if there is a snapshot further out.
|
2014-07-22 06:40:51 -05:00
|
|
|
pub fn commit(&mut self, snapshot: Snapshot) {
|
|
|
|
debug!("commit({})", snapshot.length);
|
|
|
|
|
|
|
|
self.assert_open_snapshot(&snapshot);
|
|
|
|
|
|
|
|
if snapshot.length == 0 {
|
|
|
|
// The root snapshot.
|
|
|
|
self.undo_log.truncate(0);
|
|
|
|
} else {
|
2014-10-23 10:42:21 -05:00
|
|
|
self.undo_log[snapshot.length] = CommittedSnapshot;
|
2014-07-22 06:40:51 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2015-04-07 05:11:49 -05:00
|
|
|
|
|
|
|
impl<D:SnapshotVecDelegate> ops::Deref for SnapshotVec<D> {
|
|
|
|
type Target = [D::Value];
|
|
|
|
fn deref(&self) -> &[D::Value] { &*self.values }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<D:SnapshotVecDelegate> ops::DerefMut for SnapshotVec<D> {
|
|
|
|
fn deref_mut(&mut self) -> &mut [D::Value] { &mut *self.values }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<D:SnapshotVecDelegate> ops::Index<usize> for SnapshotVec<D> {
|
|
|
|
type Output = D::Value;
|
|
|
|
fn index(&self, index: usize) -> &D::Value { self.get(index) }
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<D:SnapshotVecDelegate> ops::IndexMut<usize> for SnapshotVec<D> {
|
|
|
|
fn index_mut(&mut self, index: usize) -> &mut D::Value { self.get_mut(index) }
|
|
|
|
}
|