use arrayvec::ArrayVec;
use std::cmp::{max, min};
use std::io::Write;
const DEFAULT_BUFFER_SIZE: usize = 1024;
#[derive(Debug, Clone)]
pub struct UndoBuffer {
buffer: ArrayVec<[u8; DEFAULT_BUFFER_SIZE]>,
original: ArrayVec<[u8; DEFAULT_BUFFER_SIZE]>,
dirty: Option<(usize, usize)>,
}
impl UndoBuffer {
pub fn new(buf: &[u8]) -> Self {
let mut original = ArrayVec::<[u8; DEFAULT_BUFFER_SIZE]>::new();
let mut buffer = ArrayVec::<[u8; DEFAULT_BUFFER_SIZE]>::new();
(&mut original)
.write_all(buf)
.expect("Failed to copy into UndoBuffer");
(&mut buffer)
.write_all(buf)
.expect("Failed to copy into UndoBuffer");
Self {
original,
buffer,
dirty: None,
}
}
pub fn len(&self) -> usize {
self.buffer.len()
}
pub fn is_empty(&self) -> bool {
self.buffer.len() == 0
}
pub fn get_mut(&mut self) -> &mut [u8] {
self.dirty = Some((0, self.buffer.len()));
&mut self.buffer[..]
}
pub fn get_mut_range(&mut self, start: usize, end: usize) -> &mut [u8] {
let end = min(self.buffer.len(), end);
self.dirty = match self.dirty {
Some(range) => {
Some((min(range.0, start), max(range.1, end)))
}
None => Some((start, end)),
};
&mut self.buffer[start..end]
}
pub fn read(&self) -> &[u8] {
&self.buffer[..]
}
pub fn undo(&mut self) {
let (start, end) = match self.dirty {
None => {
return; }
Some(range) => range,
};
(&mut self.buffer[start..end])
.write_all(&self.original[start..end])
.expect("Failed to write");
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::mutators::bitflipper::BitFlipper;
#[test]
fn mutate_and_reset() {
let mut buffer = UndoBuffer::new(b"foo");
BitFlipper::mutate(buffer.get_mut(), 0, 1);
assert_eq!(buffer.read(), b"goo");
buffer.undo();
assert_eq!(buffer.read(), b"foo");
}
#[test]
fn mutate_reset_range() {
let (min, max) = (2, 3);
let mut buffer = UndoBuffer::new(b"foo");
let range = buffer.get_mut_range(min, max);
BitFlipper::mutate(range, 0, 1);
assert_ne!(buffer.read()[0..3], b"foo"[..]);
buffer.undo();
assert_eq!(buffer.read()[0..3], b"foo"[..]);
}
}