undo_map.rs

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