use crate::SDDEError;
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum DifferenceAction {
Replace,
Insert,
Delete,
}
impl From<DifferenceAction> for u8 {
fn from(val: DifferenceAction) -> Self {
match val {
DifferenceAction::Replace => b'r',
DifferenceAction::Insert => b'i',
DifferenceAction::Delete => b'd',
}
}
}
impl TryInto<DifferenceAction> for u8 {
type Error = SDDEError;
fn try_into(self) -> Result<DifferenceAction, Self::Error> {
match self {
b'r' => Ok(DifferenceAction::Replace),
b'i' => Ok(DifferenceAction::Insert),
b'd' => Ok(DifferenceAction::Delete),
_ => Err(SDDEError::DifferenceInvalid(format!("Invalid difference action. Byte: {:?}", self)))
}
}
}
#[derive(Debug, PartialEq, Clone)]
pub struct Range {
pub start: usize,
pub length: usize,
}
impl Range {
pub fn new(start: usize, length: usize) -> Self {
Self {
start,
length,
}
}
}
#[derive(Debug, PartialEq)]
pub enum USizeType {
U8,
U16,
U32,
U64,
}
impl From<u8> for USizeType {
fn from(value: u8) -> Self {
match value {
b's' => USizeType::U16,
b'i' => USizeType::U32,
b'l' => USizeType::U64,
_ => USizeType::U8,
}
}
}
impl From<USizeType> for u8 {
fn from(val: USizeType) -> Self {
match val {
USizeType::U16 => b's',
USizeType::U32 => b'i',
USizeType::U64 => b'l',
_ => b'u',
}
}
}
#[derive(Clone)]
pub struct Difference {
pub action: DifferenceAction,
pub range: Range,
pub value: Vec<u8>,
pub is_open: bool,
}
impl std::fmt::Debug for Difference {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Difference")
.field("action", &self.action)
.field("range", &self.range)
.field("value_len", &self.value.len())
.field("utf8", &String::from_utf8(self.value.clone()))
.field("is_open", &self.is_open)
.finish()
}
}
impl Difference {
pub fn to_bytes(&self) -> Vec<u8> {
let mut diff = Vec::new();
diff.push(self.action.into());
diff.push(b':');
diff.extend(Self::get_usize_type_to_bytes(self.range.start));
diff.push(b'-');
diff.extend(Self::get_usize_type_to_bytes(self.range.length));
if self.action != DifferenceAction::Delete {
diff.extend(self.value.to_owned());
}
diff
}
pub fn from_bytes(bytes: &[u8]) -> Self {
let action: DifferenceAction = bytes[0].try_into().ok().unwrap();
let range_start = Self::get_usize_type_from_bytes(&bytes[2..]);
let offset = 2 + range_start.1 + 1; let range_end = Self::get_usize_type_from_bytes(&bytes[offset..]);
let offset = offset + range_end.1;
let value = bytes[offset..].to_vec();
let is_open = false;
Self {
action,
range: Range::new(range_start.0, range_end.0),
value,
is_open,
}
}
pub fn validate_from_bytes(bytes: &[u8]) -> Result<Self, SDDEError> {
let action_byte = bytes[0];
let action_result = action_byte.try_into();
if action_result.is_err() {
return Err(action_result.err().unwrap());
}
let range_start = Self::get_usize_type_from_bytes(&bytes[2..]);
let offset = 2 + range_start.1 + 1; let range_end = Self::get_usize_type_from_bytes(&bytes[offset..]);
let offset = offset + range_end.1;
let value = bytes[offset..].to_vec();
let is_open = false;
Ok(Self {
action: action_result.ok().unwrap(),
range: Range::new(range_start.0, range_end.0),
value,
is_open,
})
}
pub fn get_usize_type_to_bytes(value: usize) -> Vec<u8> {
if value <= 255 {
(value as u8).to_be_bytes().to_vec()
} else if value <= 65_535 {
[vec![USizeType::U16.into()], (value as u16).to_be_bytes().to_vec()].concat()
} else if value <= 4_294_967_295 {
[vec![USizeType::U32.into()], (value as u32).to_be_bytes().to_vec()].concat()
} else {
[vec![USizeType::U64.into()], (value as u64).to_be_bytes().to_vec()].concat()
}
}
pub fn get_usize_type_from_bytes(bytes: &[u8]) -> (usize, usize) {
match bytes[0].into() {
USizeType::U16 => {
let mut buffer = [0; 2];
buffer.copy_from_slice(&bytes[1..3]);
(u16::from_be_bytes(buffer) as usize, 3)
},
USizeType::U32 => {
let mut buffer = [0; 4];
buffer.copy_from_slice(&bytes[1..5]);
(u32::from_be_bytes(buffer) as usize, 5)
},
USizeType::U64 => {
let mut buffer = [0; 8];
buffer.copy_from_slice(&bytes[1..9]);
(u64::from_be_bytes(buffer) as usize, 9)
},
_ => (bytes[0] as usize, 1)
}
}
}
pub struct DataDifference { }
impl DataDifference {
pub fn diff(old_data: &[u8], new_data: &[u8]) -> Vec<Difference> {
let mut differences: Vec<Difference> = Vec::new();
let mut same_count = 0;
let mut same_byte_buffer: Vec<u8> = Vec::new();
for (i, b) in new_data.iter().enumerate() {
let old_b = old_data.get(i);
if let Some(old_byte) = old_b {
if old_byte != b {
if let Some(diff) = differences.last_mut() {
if !diff.is_open {
if same_count > 0 {
same_count = 0;
same_byte_buffer.clear();
}
differences.push(Difference {
action: DifferenceAction::Replace,
range: Range::new(i, 1),
value: vec![*b],
is_open: true,
});
} else {
if same_count > 0 {
diff.value.extend(same_byte_buffer.clone());
diff.range.length += same_count;
same_byte_buffer.clear();
same_count = 0;
}
diff.value.push(*b);
diff.range.length += 1;
}
} else {
if same_count > 0 {
same_count = 0;
same_byte_buffer.clear();
}
differences.push(Difference {
action: DifferenceAction::Replace,
range: Range::new(i, 1),
value: vec![*b],
is_open: true,
});
}
} else {
if let Some(diff) = differences.last_mut() {
if same_count > 1 {
diff.is_open = false;
same_count = 0;
same_byte_buffer.clear();
} else {
same_count += 1;
same_byte_buffer.push(*b);
}
}
}
} else {
if let Some(diff) = differences.last_mut() {
if !diff.is_open {
if same_count > 0 {
same_count = 0;
same_byte_buffer.clear();
}
differences.push(Difference {
action: DifferenceAction::Insert,
range: Range::new(i, 1),
value: vec![*b],
is_open: true,
});
} else {
if diff.action == DifferenceAction::Insert {
diff.value.push(*b);
diff.range.length += 1;
} else {
same_count = 0;
same_byte_buffer.clear();
diff.is_open = false;
differences.push(Difference {
action: DifferenceAction::Insert,
range: Range::new(i, 1),
value: vec![*b],
is_open: true,
});
}
}
} else {
if same_count > 0 {
same_count = 0;
same_byte_buffer.clear();
}
differences.push(Difference {
action: DifferenceAction::Insert,
range: Range::new(i, 1),
value: vec![*b],
is_open: true,
});
}
}
}
if let Some(diff) = differences.last_mut() {
diff.is_open = false;
}
if old_data.len() > new_data.len() {
differences.push(Difference {
action: DifferenceAction::Delete,
range: Range::new(new_data.len(), old_data.len() - new_data.len()),
value: vec![],
is_open: false,
});
}
differences
}
pub fn apply_diff(data: &[u8], diff: &[Difference]) -> Vec<u8> {
let mut data = data.to_vec();
for d in diff {
if d.action == DifferenceAction::Replace {
data[d.range.start..(d.range.start + d.range.length)].copy_from_slice(&d.value);
} else if d.action == DifferenceAction::Insert {
data.extend_from_slice(&d.value);
} else if d.action == DifferenceAction::Delete {
data.drain(d.range.start..(d.range.start + d.range.length));
}
}
data
}
}