hex_patch/app/
data.rs

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    /// Pushes a change to the history and updates the data.
48    /// Returns the number of bytes changed.
49    /// Panics if the offset is out of bounds.
50    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    /// Undo the last change.
73    /// Returns the change that was undone, if any.
74    pub fn undo(&mut self) -> Option<&Change> {
75        self.history.undo(&mut self.bytes)
76    }
77
78    /// Redo the last change.
79    /// Returns the change that was redone, if any.
80    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}