1 | // Copyright 2014 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at |
3 | // http://rust-lang.org/COPYRIGHT. |
4 | // |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your |
8 | // option. This file may not be copied, modified, or distributed |
9 | // except according to those terms. |
10 | |
11 | //! A utility class for implementing "snapshottable" things; a snapshottable data structure permits |
12 | //! you to take a snapshot (via `start_snapshot`) and then, after making some changes, elect either |
13 | //! to rollback to the start of the snapshot or commit those changes. |
14 | //! |
15 | //! This vector is intended to be used as part of an abstraction, not serve as a complete |
16 | //! abstraction on its own. As such, while it will roll back most changes on its own, it also |
17 | //! supports a `get_mut` operation that gives you an arbitrary mutable pointer into the vector. To |
18 | //! ensure that any changes you make this with this pointer are rolled back, you must invoke |
19 | //! `record` to record any changes you make and also supplying a delegate capable of reversing |
20 | //! those changes. |
21 | |
22 | use self::UndoLog::*; |
23 | |
24 | use std::fmt; |
25 | use std::marker::PhantomData; |
26 | use std::mem; |
27 | use std::ops; |
28 | |
29 | use undo_log::{Rollback, Snapshots, UndoLogs, VecLog}; |
30 | |
31 | #[derive (Debug)] |
32 | pub enum UndoLog<D: SnapshotVecDelegate> { |
33 | /// New variable with given index was created. |
34 | NewElem(usize), |
35 | |
36 | /// Variable with given index was changed *from* the given value. |
37 | SetElem(usize, D::Value), |
38 | |
39 | /// Extensible set of actions |
40 | Other(D::Undo), |
41 | } |
42 | |
43 | impl<D: SnapshotVecDelegate> Rollback<UndoLog<D>> for SnapshotVecStorage<D> { |
44 | fn reverse(&mut self, undo: UndoLog<D>) { |
45 | self.values.reverse(undo) |
46 | } |
47 | } |
48 | impl<D: SnapshotVecDelegate> Rollback<UndoLog<D>> for Vec<D::Value> { |
49 | fn reverse(&mut self, undo: UndoLog<D>) { |
50 | match undo { |
51 | NewElem(i: usize) => { |
52 | self.pop(); |
53 | assert!(Vec::len(self) == i); |
54 | } |
55 | |
56 | SetElem(i: usize, v: ::Value) => { |
57 | self[i] = v; |
58 | } |
59 | |
60 | Other(u: ::Undo) => { |
61 | D::reverse(self, action:u); |
62 | } |
63 | } |
64 | } |
65 | } |
66 | |
67 | pub trait VecLike<D>: AsRef<[D::Value]> + AsMut<[D::Value]> + Rollback<UndoLog<D>> |
68 | where |
69 | D: SnapshotVecDelegate, |
70 | { |
71 | fn push(&mut self, item: D::Value); |
72 | fn len(&self) -> usize; |
73 | fn reserve(&mut self, size: usize); |
74 | } |
75 | |
76 | impl<D> VecLike<D> for Vec<D::Value> |
77 | where |
78 | D: SnapshotVecDelegate, |
79 | { |
80 | fn push(&mut self, item: D::Value) { |
81 | Vec::push(self, value:item) |
82 | } |
83 | fn len(&self) -> usize { |
84 | Vec::len(self) |
85 | } |
86 | fn reserve(&mut self, size: usize) { |
87 | Vec::reserve(self, additional:size) |
88 | } |
89 | } |
90 | |
91 | impl<D> VecLike<D> for &'_ mut Vec<D::Value> |
92 | where |
93 | D: SnapshotVecDelegate, |
94 | { |
95 | fn push(&mut self, item: D::Value) { |
96 | Vec::push(self, value:item) |
97 | } |
98 | fn len(&self) -> usize { |
99 | Vec::len(self) |
100 | } |
101 | fn reserve(&mut self, size: usize) { |
102 | Vec::reserve(self, additional:size) |
103 | } |
104 | } |
105 | |
106 | #[allow (type_alias_bounds)] |
107 | pub type SnapshotVecStorage<D: SnapshotVecDelegate> = |
108 | SnapshotVec<D, Vec<<D as SnapshotVecDelegate>::Value>, ()>; |
109 | |
110 | pub struct SnapshotVec< |
111 | D: SnapshotVecDelegate, |
112 | V: VecLike<D> = Vec<<D as SnapshotVecDelegate>::Value>, |
113 | L = VecLog<UndoLog<D>>, |
114 | > { |
115 | values: V, |
116 | undo_log: L, |
117 | _marker: PhantomData<D>, |
118 | } |
119 | |
120 | impl<D, V, L> fmt::Debug for SnapshotVec<D, V, L> |
121 | where |
122 | D: SnapshotVecDelegate, |
123 | V: VecLike<D> + fmt::Debug, |
124 | L: fmt::Debug, |
125 | { |
126 | fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { |
127 | fmt&mut DebugStruct<'_, '_>.debug_struct("SnapshotVec" ) |
128 | .field("values" , &self.values) |
129 | .field(name:"undo_log" , &self.undo_log) |
130 | .finish() |
131 | } |
132 | } |
133 | |
134 | // Snapshots are tokens that should be created/consumed linearly. |
135 | pub struct Snapshot<S = ::undo_log::Snapshot> { |
136 | pub(crate) value_count: usize, |
137 | snapshot: S, |
138 | } |
139 | |
140 | pub trait SnapshotVecDelegate { |
141 | type Value; |
142 | type Undo; |
143 | |
144 | fn reverse(values: &mut Vec<Self::Value>, action: Self::Undo); |
145 | } |
146 | |
147 | // HACK(eddyb) manual impl avoids `Default` bound on `D`. |
148 | impl<D: SnapshotVecDelegate, V: VecLike<D> + Default, L: Default> Default for SnapshotVec<D, V, L> { |
149 | fn default() -> Self { |
150 | SnapshotVec { |
151 | values: V::default(), |
152 | undo_log: Default::default(), |
153 | _marker: PhantomData, |
154 | } |
155 | } |
156 | } |
157 | |
158 | impl<D: SnapshotVecDelegate, V: VecLike<D> + Default, L: Default> SnapshotVec<D, V, L> { |
159 | /// Creates a new `SnapshotVec`. If `L` is set to `()` then most mutating functions will not |
160 | /// be accessible without calling `with_log` and supplying a compatibly `UndoLogs` instance. |
161 | pub fn new() -> Self { |
162 | Self::default() |
163 | } |
164 | } |
165 | |
166 | impl<D: SnapshotVecDelegate> SnapshotVecStorage<D> { |
167 | /// Creates a `SnapshotVec` using the `undo_log`, allowing mutating methods to be called |
168 | pub fn with_log<'a, L>( |
169 | &'a mut self, |
170 | undo_log: L, |
171 | ) -> SnapshotVec<D, &'a mut Vec<<D as SnapshotVecDelegate>::Value>, L> |
172 | where |
173 | L: UndoLogs<UndoLog<D>>, |
174 | { |
175 | SnapshotVec { |
176 | values: &mut self.values, |
177 | undo_log, |
178 | _marker: PhantomData, |
179 | } |
180 | } |
181 | } |
182 | |
183 | impl<D: SnapshotVecDelegate, L: Default> SnapshotVec<D, Vec<D::Value>, L> { |
184 | pub fn with_capacity(c: usize) -> Self { |
185 | SnapshotVec { |
186 | values: Vec::with_capacity(c), |
187 | undo_log: Default::default(), |
188 | _marker: PhantomData, |
189 | } |
190 | } |
191 | } |
192 | |
193 | impl<V: VecLike<D>, D: SnapshotVecDelegate, U> SnapshotVec<D, V, U> { |
194 | pub fn len(&self) -> usize { |
195 | self.values.len() |
196 | } |
197 | |
198 | pub fn get(&self, index: usize) -> &D::Value { |
199 | &self.values.as_ref()[index] |
200 | } |
201 | |
202 | /// Returns a mutable pointer into the vec; whatever changes you make here cannot be undone |
203 | /// automatically, so you should be sure call `record()` with some sort of suitable undo |
204 | /// action. |
205 | pub fn get_mut(&mut self, index: usize) -> &mut D::Value { |
206 | &mut self.values.as_mut()[index] |
207 | } |
208 | |
209 | /// Reserve space for new values, just like an ordinary vec. |
210 | pub fn reserve(&mut self, additional: usize) { |
211 | // This is not affected by snapshots or anything. |
212 | self.values.reserve(size:additional); |
213 | } |
214 | } |
215 | |
216 | impl<V: VecLike<D>, D: SnapshotVecDelegate, L: UndoLogs<UndoLog<D>>> SnapshotVec<D, V, L> { |
217 | fn in_snapshot(&self) -> bool { |
218 | self.undo_log.in_snapshot() |
219 | } |
220 | |
221 | pub fn record(&mut self, action: D::Undo) { |
222 | if self.in_snapshot() { |
223 | self.undo_log.push(Other(action)); |
224 | } |
225 | } |
226 | |
227 | pub fn push(&mut self, elem: D::Value) -> usize { |
228 | let len = self.values.len(); |
229 | self.values.push(elem); |
230 | |
231 | if self.in_snapshot() { |
232 | self.undo_log.push(NewElem(len)); |
233 | } |
234 | |
235 | len |
236 | } |
237 | |
238 | /// Updates the element at the given index. The old value will saved (and perhaps restored) if |
239 | /// a snapshot is active. |
240 | pub fn set(&mut self, index: usize, new_elem: D::Value) { |
241 | let old_elem = mem::replace(&mut self.values.as_mut()[index], new_elem); |
242 | if self.undo_log.in_snapshot() { |
243 | self.undo_log.push(SetElem(index, old_elem)); |
244 | } |
245 | } |
246 | |
247 | /// Updates all elements. Potentially more efficient -- but |
248 | /// otherwise equivalent to -- invoking `set` for each element. |
249 | pub fn set_all(&mut self, mut new_elems: impl FnMut(usize) -> D::Value) { |
250 | if !self.undo_log.in_snapshot() { |
251 | for (index, slot) in self.values.as_mut().iter_mut().enumerate() { |
252 | *slot = new_elems(index); |
253 | } |
254 | } else { |
255 | for i in 0..self.values.len() { |
256 | self.set(i, new_elems(i)); |
257 | } |
258 | } |
259 | } |
260 | |
261 | pub fn update<OP>(&mut self, index: usize, op: OP) |
262 | where |
263 | OP: FnOnce(&mut D::Value), |
264 | D::Value: Clone, |
265 | { |
266 | if self.undo_log.in_snapshot() { |
267 | let old_elem = self.values.as_mut()[index].clone(); |
268 | self.undo_log.push(SetElem(index, old_elem)); |
269 | } |
270 | op(&mut self.values.as_mut()[index]); |
271 | } |
272 | } |
273 | |
274 | impl<D, V, L> SnapshotVec<D, V, L> |
275 | where |
276 | D: SnapshotVecDelegate, |
277 | V: VecLike<D> + Rollback<UndoLog<D>>, |
278 | L: Snapshots<UndoLog<D>>, |
279 | { |
280 | pub fn start_snapshot(&mut self) -> Snapshot<L::Snapshot> { |
281 | Snapshot { |
282 | value_count: self.values.len(), |
283 | snapshot: self.undo_log.start_snapshot(), |
284 | } |
285 | } |
286 | |
287 | pub fn actions_since_snapshot(&self, snapshot: &Snapshot<L::Snapshot>) -> &[UndoLog<D>] { |
288 | self.undo_log.actions_since_snapshot(&snapshot.snapshot) |
289 | } |
290 | |
291 | pub fn rollback_to(&mut self, snapshot: Snapshot<L::Snapshot>) { |
292 | let values: &mut V = &mut self.values; |
293 | self.undo_log.rollback_to(|| values, snapshot.snapshot); |
294 | } |
295 | |
296 | /// Commits all changes since the last snapshot. Of course, they |
297 | /// can still be undone if there is a snapshot further out. |
298 | pub fn commit(&mut self, snapshot: Snapshot<L::Snapshot>) { |
299 | self.undo_log.commit(snapshot.snapshot); |
300 | } |
301 | } |
302 | |
303 | impl<D: SnapshotVecDelegate, V: VecLike<D>, L> ops::Deref for SnapshotVec<D, V, L> { |
304 | type Target = [D::Value]; |
305 | fn deref(&self) -> &[D::Value] { |
306 | self.values.as_ref() |
307 | } |
308 | } |
309 | |
310 | impl<D: SnapshotVecDelegate, V: VecLike<D>, L> ops::DerefMut for SnapshotVec<D, V, L> { |
311 | fn deref_mut(&mut self) -> &mut [D::Value] { |
312 | self.values.as_mut() |
313 | } |
314 | } |
315 | |
316 | impl<D: SnapshotVecDelegate, V: VecLike<D>, L> ops::Index<usize> for SnapshotVec<D, V, L> { |
317 | type Output = D::Value; |
318 | fn index(&self, index: usize) -> &D::Value { |
319 | self.get(index) |
320 | } |
321 | } |
322 | |
323 | impl<D: SnapshotVecDelegate, V: VecLike<D>, L> ops::IndexMut<usize> for SnapshotVec<D, V, L> { |
324 | fn index_mut(&mut self, index: usize) -> &mut D::Value { |
325 | self.get_mut(index) |
326 | } |
327 | } |
328 | |
329 | impl<D: SnapshotVecDelegate, V: VecLike<D> + Extend<D::Value>> Extend<D::Value> |
330 | for SnapshotVec<D, V> |
331 | { |
332 | fn extend<T>(&mut self, iterable: T) |
333 | where |
334 | T: IntoIterator<Item = D::Value>, |
335 | { |
336 | let initial_len: usize = self.values.len(); |
337 | self.values.extend(iter:iterable); |
338 | let final_len: usize = self.values.len(); |
339 | |
340 | if self.in_snapshot() { |
341 | self.undo_log |
342 | .extend((initial_len..final_len).map(|len: usize| NewElem(len))); |
343 | } |
344 | } |
345 | } |
346 | |
347 | impl<D: SnapshotVecDelegate, V, L> Clone for SnapshotVec<D, V, L> |
348 | where |
349 | V: VecLike<D> + Clone, |
350 | L: Clone, |
351 | { |
352 | fn clone(&self) -> Self { |
353 | SnapshotVec { |
354 | values: self.values.clone(), |
355 | undo_log: self.undo_log.clone(), |
356 | _marker: PhantomData, |
357 | } |
358 | } |
359 | } |
360 | |
361 | impl<D: SnapshotVecDelegate> Clone for UndoLog<D> |
362 | where |
363 | D::Value: Clone, |
364 | D::Undo: Clone, |
365 | { |
366 | fn clone(&self) -> Self { |
367 | match *self { |
368 | NewElem(i: usize) => NewElem(i), |
369 | SetElem(i: usize, ref v: &::Value) => SetElem(i, v.clone()), |
370 | Other(ref u: &::Undo) => Other(u.clone()), |
371 | } |
372 | } |
373 | } |
374 | |
375 | impl SnapshotVecDelegate for i32 { |
376 | type Value = i32; |
377 | type Undo = (); |
378 | |
379 | fn reverse(_: &mut Vec<i32>, _: ()) {} |
380 | } |
381 | |
382 | #[test ] |
383 | fn basic() { |
384 | let mut vec: SnapshotVec<i32> = SnapshotVec::default(); |
385 | assert!(!vec.in_snapshot()); |
386 | assert_eq!(vec.len(), 0); |
387 | vec.push(22); |
388 | vec.push(33); |
389 | assert_eq!(vec.len(), 2); |
390 | assert_eq!(*vec.get(0), 22); |
391 | assert_eq!(*vec.get(1), 33); |
392 | vec.set(1, 34); |
393 | assert_eq!(vec.len(), 2); |
394 | assert_eq!(*vec.get(0), 22); |
395 | assert_eq!(*vec.get(1), 34); |
396 | |
397 | let snapshot = vec.start_snapshot(); |
398 | assert!(vec.in_snapshot()); |
399 | |
400 | vec.push(44); |
401 | vec.push(55); |
402 | vec.set(1, 35); |
403 | assert_eq!(vec.len(), 4); |
404 | assert_eq!(*vec.get(0), 22); |
405 | assert_eq!(*vec.get(1), 35); |
406 | assert_eq!(*vec.get(2), 44); |
407 | assert_eq!(*vec.get(3), 55); |
408 | |
409 | vec.rollback_to(snapshot); |
410 | assert!(!vec.in_snapshot()); |
411 | |
412 | assert_eq!(vec.len(), 2); |
413 | assert_eq!(*vec.get(0), 22); |
414 | assert_eq!(*vec.get(1), 34); |
415 | } |
416 | |
417 | #[test ] |
418 | #[should_panic ] |
419 | fn out_of_order() { |
420 | let mut vec: SnapshotVec<i32> = SnapshotVec::default(); |
421 | vec.push(elem:22); |
422 | let snapshot1: Snapshot = vec.start_snapshot(); |
423 | vec.push(elem:33); |
424 | let snapshot2: Snapshot = vec.start_snapshot(); |
425 | vec.push(elem:44); |
426 | vec.rollback_to(snapshot:snapshot1); // bogus, but accepted |
427 | vec.rollback_to(snapshot:snapshot2); // asserts |
428 | } |
429 | |
430 | #[test ] |
431 | fn nested_commit_then_rollback() { |
432 | let mut vec: SnapshotVec<i32> = SnapshotVec::default(); |
433 | vec.push(elem:22); |
434 | let snapshot1: Snapshot = vec.start_snapshot(); |
435 | let snapshot2: Snapshot = vec.start_snapshot(); |
436 | vec.set(index:0, new_elem:23); |
437 | vec.commit(snapshot:snapshot2); |
438 | assert_eq!(*vec.get(0), 23); |
439 | vec.rollback_to(snapshot:snapshot1); |
440 | assert_eq!(*vec.get(0), 22); |
441 | } |
442 | |