1use crate::value::Value;
2use std::fmt::{Display, Formatter};
3
4#[derive(Debug, PartialEq)]
5pub struct Undo {
6 remove: usize,
7 insert: Vec<Value>,
8 tokens: Vec<String>,
9}
10
11impl Undo {
12 pub fn new(remove: usize, insert: Vec<Value>, tokens: Vec<String>) -> Self {
13 Self { remove, insert, tokens }
14 }
15
16 pub fn is_empty(&self) -> bool {
17 self.remove == 0 && self.insert.is_empty()
18 }
19
20 pub fn merge(&mut self, remove: usize, mut insert: Vec<Value>, token: Option<&str>) {
21 if let Some(start) = insert.len().checked_sub(self.remove) {
22 insert.drain(start..);
23 insert.append(&mut self.insert);
24 self.remove = remove;
25 self.insert = insert;
26 } else if let Some(delta) = self.remove.checked_sub(insert.len()) {
27 self.remove = remove + delta;
28 }
29 if let Some(token) = token {
30 self.tokens.push(String::from(token));
31 }
32 }
33
34 pub fn clear(&mut self) {
35 self.remove = 0;
36 self.insert.clear();
37 self.tokens.clear();
38 }
39
40 pub fn apply_to(&mut self, stack: &mut Vec<Value>) -> Self {
41 let start = stack.len().checked_sub(self.remove).unwrap_or(0);
42 let remove = self.insert.len();
43 let insert = stack.drain(start..).collect();
44 let tokens = self.tokens.drain(..).collect();
45 stack.append(&mut self.insert);
46 self.remove = 0;
47 Self::new(remove, insert, tokens)
48 }
49}
50
51impl Default for Undo {
52 fn default() -> Self {
53 Self::new(0, Vec::new(), Vec::new())
54 }
55}
56
57impl Display for Undo {
58 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
59 let tokens = self.tokens.join(" ");
60 write!(f, "{}", tokens)?;
61 Ok(())
62 }
63}
64
65#[cfg(test)]
66pub mod tests {
67 use crate::engine::tests::create_values;
68 use crate::undo::Undo;
69 use pretty_assertions::assert_eq;
70
71 #[test]
72 fn test_values_are_merged_with_underflow() {
73 let mut undo = create_undo(1, vec!["2", "3"], vec![]);
74 undo.merge(1, create_values(vec!["1", "5"]), None);
75 assert_eq!(undo.remove, 1);
76 assert_eq!(undo.insert, create_values(vec!["1", "2", "3"]));
77 }
78
79 #[test]
80 fn test_values_are_merged_with_overflow() {
81 let mut undo = create_undo(3, vec!["2", "3"], vec![]);
82 undo.merge(1, create_values(vec!["1", "5"]), None);
83 assert_eq!(undo.remove, 2);
84 assert_eq!(undo.insert, create_values(vec!["2", "3"]));
85 }
86
87 #[test]
88 fn test_changes_are_applied_with_underflow() {
89 let mut stack = create_values(vec!["1", "2", "3"]);
90 let mut undo = create_undo(2, vec!["4", "5"], vec![]);
91 undo.apply_to(&mut stack);
92 assert_eq!(stack, create_values(vec!["1", "4", "5"]));
93 }
94
95 #[test]
96 fn test_changes_are_applied_with_overflow() {
97 let mut stack = create_values(vec!["1", "2", "3"]);
98 let mut undo = create_undo(4, vec!["4", "5"], vec![]);
99 undo.apply_to(&mut stack);
100 assert_eq!(stack, create_values(vec!["4", "5"]));
101 }
102
103 pub fn create_undo(remove: usize, insert: Vec<&str>, tokens: Vec<&str>) -> Undo {
104 let insert = create_values(insert);
105 let tokens = tokens.iter().map(|x| x.to_string()).collect();
106 Undo::new(remove, insert, tokens)
107 }
108}