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) -> 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 add_summary(&mut self, summary: &Self, _: &Self::Context) {
37 *self = cmp::max(*self, *summary);
38 }
39}
40
41#[derive(Clone, Default)]
42pub struct UndoMap(SumTree<UndoMapEntry>);
43
44impl UndoMap {
45 pub fn insert(&mut self, undo: &UndoOperation) {
46 let edits = undo
47 .counts
48 .iter()
49 .map(|(edit_id, count)| {
50 sum_tree::Edit::Insert(UndoMapEntry {
51 key: UndoMapKey {
52 edit_id: *edit_id,
53 undo_id: undo.timestamp,
54 },
55 undo_count: *count,
56 })
57 })
58 .collect::<Vec<_>>();
59 self.0.edit(edits, &());
60 }
61
62 pub fn is_undone(&self, edit_id: clock::Lamport) -> bool {
63 self.undo_count(edit_id) % 2 == 1
64 }
65
66 pub fn was_undone(&self, edit_id: clock::Lamport, version: &clock::Global) -> bool {
67 let mut cursor = self.0.cursor::<UndoMapKey>();
68 cursor.seek(
69 &UndoMapKey {
70 edit_id,
71 undo_id: Default::default(),
72 },
73 Bias::Left,
74 &(),
75 );
76
77 let mut undo_count = 0;
78 for entry in cursor {
79 if entry.key.edit_id != edit_id {
80 break;
81 }
82
83 if version.observed(entry.key.undo_id) {
84 undo_count = cmp::max(undo_count, entry.undo_count);
85 }
86 }
87
88 undo_count % 2 == 1
89 }
90
91 pub fn undo_count(&self, edit_id: clock::Lamport) -> u32 {
92 let mut cursor = self.0.cursor::<UndoMapKey>();
93 cursor.seek(
94 &UndoMapKey {
95 edit_id,
96 undo_id: Default::default(),
97 },
98 Bias::Left,
99 &(),
100 );
101
102 let mut undo_count = 0;
103 for entry in cursor {
104 if entry.key.edit_id != edit_id {
105 break;
106 }
107
108 undo_count = cmp::max(undo_count, entry.undo_count);
109 }
110 undo_count
111 }
112}