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                "Offset {} out of bounds for data of length {}",
54                offset,
55                self.bytes.len()
56            );
57        }
58        new.truncate(self.bytes.len().checked_sub(offset).unwrap());
59        let old = &self.bytes[offset..offset + new.len()];
60        if old == new.as_slice() {
61            return 0;
62        }
63        self.history.push(Change::new(offset, old, &new));
64        self.bytes[offset..offset + new.len()].copy_from_slice(&new);
65        self.dirty = true;
66        new.len()
67    }
68
69    /// Undo the last change.
70    /// Returns the change that was undone, if any.
71    pub fn undo(&mut self) -> Option<&Change> {
72        self.history.undo(&mut self.bytes)
73    }
74
75    /// Redo the last change.
76    /// Returns the change that was redone, if any.
77    pub fn redo(&mut self) -> Option<&Change> {
78        self.history.redo(&mut self.bytes)
79    }
80
81    pub fn clear_history(&mut self) {
82        self.history.clear();
83    }
84
85    pub fn len(&self) -> usize {
86        self.bytes.len()
87    }
88
89    pub fn is_empty(&self) -> bool {
90        self.bytes.is_empty()
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97
98    #[test]
99    fn test_data_push_change() {
100        let mut data = Data::new(vec![0, 1, 2, 3, 4], 0);
101        assert_eq!(data.push_change(2, vec![9, 8, 7]), 3);
102        assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
103        assert_eq!(data.push_change(2, vec![9, 8, 7]), 0);
104        assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
105        assert_eq!(data.push_change(2, vec![9, 8, 7, 6]), 0);
106        assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
107        assert_eq!(data.push_change(2, vec![9, 8, 7, 6, 5]), 0);
108        assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
109        assert_eq!(data.push_change(2, vec![9, 8]), 0);
110        assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
111        assert_eq!(data.push_change(2, vec![9, 8, 7]), 0);
112        assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
113        assert_eq!(data.push_change(1, vec![9, 8, 7, 6]), 4);
114        assert_eq!(data.bytes(), &[0, 9, 8, 7, 6]);
115        assert_eq!(data.push_change(1, vec![9, 8, 7, 6, 5]), 0);
116        assert_eq!(data.bytes(), &[0, 9, 8, 7, 6]);
117        assert_eq!(data.push_change(1, vec![1, 2, 3, 4, 5]), 4);
118        assert_eq!(data.bytes(), &[0, 1, 2, 3, 4]);
119    }
120
121    #[test]
122    #[should_panic]
123    fn test_data_push_change_out_of_bounds() {
124        let mut data = Data::new(vec![0, 1, 2, 3, 4], 0);
125        data.push_change(5, vec![9, 8, 7]);
126    }
127
128    #[test]
129    fn test_data_undo_redo() {
130        let mut data = Data::new(vec![0, 1, 2, 3, 4], 0);
131        data.push_change(2, vec![9, 8, 7]);
132        assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
133        data.push_change(0, vec![9, 8]);
134        assert_eq!(data.bytes(), &[9, 8, 9, 8, 7]);
135        data.push_change(4, vec![9]);
136        assert_eq!(data.bytes(), &[9, 8, 9, 8, 9]);
137        data.undo();
138        assert_eq!(data.bytes(), &[9, 8, 9, 8, 7]);
139        data.undo();
140        assert_eq!(data.bytes(), &[0, 1, 9, 8, 7]);
141        data.redo();
142        assert_eq!(data.bytes(), &[9, 8, 9, 8, 7]);
143        data.redo();
144        assert_eq!(data.bytes(), &[9, 8, 9, 8, 9]);
145    }
146
147    #[test]
148    fn test_data_clear_history() {
149        let mut data = Data::new(vec![0, 1, 2, 3, 4], 0);
150        data.push_change(2, vec![9, 8, 7]);
151        data.push_change(0, vec![9, 8]);
152        data.push_change(4, vec![9]);
153        assert_eq!(data.bytes(), &[9, 8, 9, 8, 9]);
154        data.clear_history();
155        data.undo();
156        assert_eq!(data.bytes(), &[9, 8, 9, 8, 9]);
157    }
158}