1use std::{iter, marker::PhantomData};
2
3pub trait FromItem<I> {
4 fn from_item(item: I) -> Self;
5}
6
7impl<I> FromItem<I> for I {
8 fn from_item(item: I) -> Self {
9 item
10 }
11}
12
13impl<I> FromItem<I> for Vec<I>
14where
15 I: Clone,
16{
17 fn from_item(item: I) -> Self {
18 vec![item]
19 }
20}
21
22#[derive(Clone, Debug)]
23pub struct History<I, T = Vec<I>>
24where
25 T: FromItem<I> + Extend<I> + Clone,
26{
27 transactions: Vec<T>,
28 index: usize,
29 last_is_committed: bool,
30 _phantom: PhantomData<fn(I)>,
31}
32
33impl<I, T> History<I, T>
34where
35 T: FromItem<I> + Extend<I> + Clone,
36{
37 #[must_use]
38 pub fn new() -> Self {
39 Self::default()
40 }
41
42 pub fn push(&mut self, item: I) {
45 if self.index < self.transactions.len() {
47 self.transactions.truncate(self.index);
48 self.last_is_committed = true;
49 }
50 if self.last_is_committed {
52 self.transactions.push(T::from_item(item));
53 self.index += 1;
54 self.last_is_committed = false;
55 } else {
56 self.transactions
58 .last_mut()
59 .unwrap()
60 .extend(iter::once(item));
61 }
62 }
63
64 pub fn commit(&mut self) {
65 self.last_is_committed = true;
66 }
67
68 pub fn undo(&mut self) -> Option<&T> {
70 if self.index == 0 {
71 return None;
72 }
73 self.index -= 1;
74 self.last_is_committed = true;
75 let transaction = &self.transactions[self.index];
76 Some(transaction)
77 }
78
79 pub fn redo(&mut self) -> Option<&T> {
81 if self.index == self.transactions.len() {
82 return None;
83 }
84 let transaction = &self.transactions[self.index];
85 self.index += 1;
86 self.last_is_committed = true;
87 Some(transaction)
88 }
89}
90
91impl<I, T> Default for History<I, T>
92where
93 T: FromItem<I> + Extend<I> + Clone,
94{
95 fn default() -> Self {
96 Self {
97 transactions: Vec::new(),
98 index: 0,
99 last_is_committed: true,
100 _phantom: PhantomData,
101 }
102 }
103}
104
105#[derive(Clone, Debug, Default, PartialEq)]
106pub struct First<T>(pub Option<T>);
107
108impl<T> FromItem<T> for First<T> {
109 fn from_item(item: T) -> Self {
110 Self(Some(item))
111 }
112}
113
114impl<T> Extend<T> for First<T> {
115 fn extend<I>(&mut self, iter: I)
116 where
117 I: IntoIterator<Item = T>,
118 {
119 if self.0.is_none() {
120 self.0 = iter.into_iter().next();
121 }
122 }
123}
124
125#[derive(Clone, Debug, Default, PartialEq)]
126pub struct Last<T>(pub Option<T>);
127
128impl<T> FromItem<T> for Last<T> {
129 fn from_item(item: T) -> Self {
130 Self(Some(item))
131 }
132}
133
134impl<T> Extend<T> for Last<T> {
135 fn extend<I>(&mut self, iter: I)
136 where
137 I: IntoIterator<Item = T>,
138 {
139 self.0 = iter.into_iter().last();
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146 use std::ops::AddAssign;
147
148 #[test]
149 fn undo_returns_undone() {
150 let mut history: History<u8> = History::new();
151 history.push(1);
152 history.push(2);
153 assert_eq!(history.undo(), Some(&vec![1, 2]));
154 assert_eq!(history.undo(), None);
155 }
156
157 #[test]
158 fn redo_returns_redone() {
159 let mut history: History<u8> = History::new();
160 history.push(1);
161 history.push(2);
162 history.undo();
163 assert_eq!(history.redo(), Some(&vec![1, 2]));
164 assert_eq!(history.redo(), None);
165 }
166
167 #[test]
168 fn undo_redo_symmetry() {
169 let mut history: History<u8> = History::new();
170 history.push(1);
171 history.push(2);
172 history.push(3);
173 history.commit();
174 history.push(4);
175 history.push(5);
176 history.push(6);
177 history.commit();
178 assert_eq!(history.undo(), Some(&vec![4, 5, 6]));
179 assert_eq!(history.undo(), Some(&vec![1, 2, 3]));
180 assert_eq!(history.redo(), Some(&vec![1, 2, 3]));
181 assert_eq!(history.redo(), Some(&vec![4, 5, 6]));
182 }
183
184 #[test]
185 fn no_movement_no_commit() {
186 let mut history: History<u8> = History::new();
187 history.push(1);
188 history.redo();
190 history.push(2);
191 assert_eq!(history.undo(), Some(&vec![1, 2]));
193 }
194
195 #[test]
196 fn movement_commits() {
197 let mut history: History<u8> = History::new();
198 history.push(1);
199 history.undo();
201 history.redo();
202 history.push(2);
203 assert_eq!(history.undo(), Some(&vec![2]));
205 }
206
207 #[test]
208 fn fork_timeline_discards_future() {
209 let mut history: History<u8> = History::new();
210 history.push(1);
211 history.commit();
212 history.push(2);
213 history.commit();
214 history.undo();
215 history.push(3);
216 assert_eq!(history.undo(), Some(&vec![3]));
217 }
218
219 #[derive(Clone, Debug, Default, PartialEq)]
220 struct Sum<T>(T);
221
222 impl<T> FromItem<T> for Sum<T> {
223 fn from_item(item: T) -> Self {
224 Self(item)
225 }
226 }
227
228 impl<T> Extend<T> for Sum<T>
229 where
230 T: AddAssign,
231 {
232 fn extend<I>(&mut self, ns: I)
233 where
234 I: IntoIterator<Item = T>,
235 {
236 for n in ns {
237 self.0 += n;
238 }
239 }
240 }
241
242 #[test]
243 fn custom_transaction_type_sum() {
244 let mut history: History<u8, Sum<u8>> = History::new();
245 history.push(1);
246 history.push(1);
247 history.push(1);
248 history.commit();
249 history.push(2);
250 history.push(2);
251 history.push(2);
252 history.commit();
253 assert_eq!(history.undo(), Some(&Sum(6)));
254 assert_eq!(history.undo(), Some(&Sum(3)));
255 }
256
257 #[test]
258 fn custom_transaction_type_first() {
259 let mut history: History<u8, First<u8>> = History::new();
260 history.push(1);
261 history.push(2);
262 history.push(3);
263 history.commit();
264 history.push(4);
265 history.push(5);
266 history.push(6);
267 history.commit();
268 assert_eq!(history.undo(), Some(&First(Some(4))));
269 assert_eq!(history.undo(), Some(&First(Some(1))));
270 }
271
272 #[test]
273 fn custom_transaction_type_last() {
274 let mut history: History<u8, Last<u8>> = History::new();
275 history.push(1);
276 history.push(2);
277 history.push(3);
278 history.commit();
279 history.push(4);
280 history.push(5);
281 history.push(6);
282 history.commit();
283 assert_eq!(history.undo(), Some(&Last(Some(6))));
284 assert_eq!(history.undo(), Some(&Last(Some(3))));
285 }
286}