1use super::history::{change::Change, History};
2
3#[derive(Debug, Clone, Default)]
4pub struct Data {
5 bytes: Vec<u8>,
6 history: History,
7 dirty: bool,
8}
9
10impl Data {
11 pub fn new(bytes: Vec<u8>, history_limit: usize) -> Self {
12 Self {
13 bytes,
14 history: History::with_limit(history_limit),
15 dirty: false,
16 }
17 }
18
19 pub fn get(&self, i: usize) -> Option<u8> {
20 self.bytes.get(i).copied()
21 }
22
23 pub fn set(&mut self, i: usize, byte: u8) -> Result<(), mlua::Error> {
24 match self.bytes.get_mut(i) {
25 Some(b) => {
26 self.history.push(Change::new(i, &[*b], &[byte]));
27 *b = byte;
28 self.dirty = true;
29 Ok(())
30 }
31 None => Err(mlua::Error::external("index out of bounds")),
32 }
33 }
34
35 pub fn bytes(&self) -> &[u8] {
36 &self.bytes
37 }
38
39 pub fn dirty(&self) -> bool {
40 self.dirty
41 }
42
43 pub fn reset_dirty(&mut self) {
44 self.dirty = false;
45 }
46
47 pub fn push_change(&mut self, offset: usize, mut new: Vec<u8>) -> usize {
51 if offset >= self.bytes.len() {
52 panic!(
53 "{}",
54 t!(
55 "panic.data_offset_out_of_bounds",
56 offset = offset,
57 data_len = self.bytes.len()
58 )
59 );
60 }
61 new.truncate(self.bytes.len().checked_sub(offset).unwrap());
62 let old = &self.bytes[offset..offset + new.len()];
63 if old == new.as_slice() {
64 return 0;
65 }
66 self.history.push(Change::new(offset, old, &new));
67 self.bytes[offset..offset + new.len()].copy_from_slice(&new);
68 self.dirty = true;
69 new.len()
70 }
71
72 pub fn undo(&mut self) -> Option<&Change> {
75 self.history.undo(&mut self.bytes)
76 }
77
78 pub fn redo(&mut self) -> Option<&Change> {
81 self.history.redo(&mut self.bytes)
82 }
83
84 pub fn clear_history(&mut self) {
85 self.history.clear();
86 }
87
88 pub fn len(&self) -> usize {
89 self.bytes.len()
90 }
91
92 pub fn is_empty(&self) -> bool {
93 self.bytes.is_empty()
94 }
95}
96
97#[cfg(test)]
98mod tests {
99 use super::*;
100
101 #[test]
102 fn test_data_push_change() {
103 let mut data = Data::new(vec![0, 1, 2, 3, 4], 0);
104 assert_eq!(data.push_change(2, vec![9, 8, 7]), 3);
105 assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
106 assert_eq!(data.push_change(2, vec![9, 8, 7]), 0);
107 assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
108 assert_eq!(data.push_change(2, vec![9, 8, 7, 6]), 0);
109 assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
110 assert_eq!(data.push_change(2, vec![9, 8, 7, 6, 5]), 0);
111 assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
112 assert_eq!(data.push_change(2, vec![9, 8]), 0);
113 assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
114 assert_eq!(data.push_change(2, vec![9, 8, 7]), 0);
115 assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
116 assert_eq!(data.push_change(1, vec![9, 8, 7, 6]), 4);
117 assert_eq!(data.bytes(), &[0, 9, 8, 7, 6]);
118 assert_eq!(data.push_change(1, vec![9, 8, 7, 6, 5]), 0);
119 assert_eq!(data.bytes(), &[0, 9, 8, 7, 6]);
120 assert_eq!(data.push_change(1, vec![1, 2, 3, 4, 5]), 4);
121 assert_eq!(data.bytes(), &[0, 1, 2, 3, 4]);
122 }
123
124 #[test]
125 #[should_panic]
126 fn test_data_push_change_out_of_bounds() {
127 let mut data = Data::new(vec![0, 1, 2, 3, 4], 0);
128 data.push_change(5, vec![9, 8, 7]);
129 }
130
131 #[test]
132 fn test_data_undo_redo() {
133 let mut data = Data::new(vec![0, 1, 2, 3, 4], 0);
134 data.push_change(2, vec![9, 8, 7]);
135 assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
136 data.push_change(0, vec![9, 8]);
137 assert_eq!(data.bytes(), &[9, 8, 9, 8, 7]);
138 data.push_change(4, vec![9]);
139 assert_eq!(data.bytes(), &[9, 8, 9, 8, 9]);
140 data.undo();
141 assert_eq!(data.bytes(), &[9, 8, 9, 8, 7]);
142 data.undo();
143 assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
144 data.redo();
145 assert_eq!(data.bytes(), &[9, 8, 9, 8, 7]);
146 data.redo();
147 assert_eq!(data.bytes(), &[9, 8, 9, 8, 9]);
148 }
149
150 #[test]
151 fn test_data_clear_history() {
152 let mut data = Data::new(vec![0, 1, 2, 3, 4], 0);
153 data.push_change(2, vec![9, 8, 7]);
154 data.push_change(0, vec![9, 8]);
155 data.push_change(4, vec![9]);
156 assert_eq!(data.bytes(), &[9, 8, 9, 8, 9]);
157 data.clear_history();
158 data.undo();
159 assert_eq!(data.bytes(), &[9, 8, 9, 8, 9]);
160 }
161}