1use crate::UndoOperation;
2use std::cmp;
3use sum_tree::{Bias, SumTree};
4
5#[derive(Copy, Clone, Debug)]
6struct UndoMapEntry {
7 key: UndoMapKey,
8 undo_count: u32,
9}
10
11impl sum_tree::Item for UndoMapEntry {
12 type Summary = UndoMapKey;
13
14 fn summary(&self, _cx: &()) -> Self::Summary {
15 self.key
16 }
17}
18
19impl sum_tree::KeyedItem for UndoMapEntry {
20 type Key = UndoMapKey;
21
22 fn key(&self) -> Self::Key {
23 self.key
24 }
25}
26
27#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord)]
28struct UndoMapKey {
29 edit_id: clock::Lamport,
30 undo_id: clock::Lamport,
31}
32
33impl sum_tree::Summary for UndoMapKey {
34 type Context = ();
35
36 fn zero(_cx: &Self::Context) -> Self {
37 Default::default()
38 }
39
40 fn add_summary(&mut self, summary: &Self, _: &Self::Context) {
41 *self = cmp::max(*self, *summary);
42 }
43}
44
45#[derive(Clone, Default)]
46pub struct UndoMap(SumTree<UndoMapEntry>);
47
48impl UndoMap {
49 pub fn insert(&mut self, undo: &UndoOperation) {
50 let edits = undo
51 .counts
52 .iter()
53 .map(|(edit_id, count)| {
54 sum_tree::Edit::Insert(UndoMapEntry {
55 key: UndoMapKey {
56 edit_id: *edit_id,
57 undo_id: undo.timestamp,
58 },
59 undo_count: *count,
60 })
61 })
62 .collect::<Vec<_>>();
63 self.0.edit(edits, &());
64 }
65
66 pub fn is_undone(&self, edit_id: clock::Lamport) -> bool {
67 self.undo_count(edit_id) % 2 == 1
68 }
69 pub fn was_undone(&self, edit_id: clock::Lamport, version: &clock::Global) -> bool {
70 let mut cursor = self.0.cursor::<UndoMapKey>(&());
71 cursor.seek(
72 &UndoMapKey {
73 edit_id,
74 undo_id: Default::default(),
75 },
76 Bias::Left,
77 );
78
79 let mut undo_count = 0;
80 for entry in cursor {
81 if entry.key.edit_id != edit_id {
82 break;
83 }
84
85 if version.observed(entry.key.undo_id) {
86 undo_count = cmp::max(undo_count, entry.undo_count);
87 }
88 }
89
90 undo_count % 2 == 1
91 }
92
93 pub fn undo_count(&self, edit_id: clock::Lamport) -> u32 {
94 let mut cursor = self.0.cursor::<UndoMapKey>(&());
95 cursor.seek(
96 &UndoMapKey {
97 edit_id,
98 undo_id: Default::default(),
99 },
100 Bias::Left,
101 );
102
103 let mut undo_count = 0;
104 for entry in cursor {
105 if entry.key.edit_id != edit_id {
106 break;
107 }
108
109 undo_count = cmp::max(undo_count, entry.undo_count);
110 }
111 undo_count
112 }
113}