polyspec_crudui_generator/
history.rs1use crate::error::{FormError, FormResult};
2
3pub const HISTORY_LIMIT: usize = 100;
5
6#[derive(Debug, Clone, PartialEq)]
9pub struct History<T> {
10 pub entries: Vec<T>,
12 pub redo_entries: Vec<T>,
14 pub last_path: Option<String>,
16}
17
18#[derive(Debug, Clone, PartialEq)]
20pub struct HistoryResult<T> {
21 pub history: History<T>,
23 pub value: T,
25}
26
27fn last_records<T: Clone>(records: &[T]) -> Vec<T> {
29 records[records.len().saturating_sub(HISTORY_LIMIT)..].to_vec()
30}
31
32pub fn empty_history<T>() -> History<T> {
34 History {
35 entries: Vec::new(),
36 redo_entries: Vec::new(),
37 last_path: None,
38 }
39}
40
41pub fn record_change<T: Clone>(
45 history: &History<T>,
46 previous: T,
47 path: Option<&str>,
48) -> History<T> {
49 let mut entries = history.entries.clone();
50 if path.is_none() || path != history.last_path.as_deref() {
51 entries.push(previous);
52 }
53 History {
54 entries: last_records(&entries),
55 redo_entries: Vec::new(),
56 last_path: path.map(str::to_string),
57 }
58}
59
60pub fn can_undo<T>(history: &History<T>) -> bool {
62 !history.entries.is_empty()
63}
64
65pub fn can_redo<T>(history: &History<T>) -> bool {
67 !history.redo_entries.is_empty()
68}
69
70pub fn undo_change<T: Clone>(history: &History<T>, current: T) -> FormResult<HistoryResult<T>> {
73 let Some((value, rest)) = history.entries.split_last() else {
74 return Err(FormError::input("Nothing to undo"));
75 };
76 let mut redo_entries = history.redo_entries.clone();
77 redo_entries.push(current);
78 Ok(HistoryResult {
79 history: History {
80 entries: rest.to_vec(),
81 redo_entries: last_records(&redo_entries),
82 last_path: None,
83 },
84 value: value.clone(),
85 })
86}
87
88pub fn redo_change<T: Clone>(history: &History<T>, current: T) -> FormResult<HistoryResult<T>> {
91 let Some((value, rest)) = history.redo_entries.split_last() else {
92 return Err(FormError::input("Nothing to redo"));
93 };
94 let mut entries = history.entries.clone();
95 entries.push(current);
96 Ok(HistoryResult {
97 history: History {
98 entries: last_records(&entries),
99 redo_entries: rest.to_vec(),
100 last_path: None,
101 },
102 value: value.clone(),
103 })
104}