use std::ptr;
use crate::Error;
#[derive(Debug, Clone)]
pub struct RecordHeader {
pub transaction: i32,
pub b_page: i32,
pub b_line: u16,
pub flags: u16,
pub format: u8,
pub data: Vec<u8>,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct RecordHeaderRepr {
pub transaction: i32,
pub b_page: i32,
pub b_line: u16,
pub flags: u16,
pub format: u8,
pub data: [u8; 1024],
}
impl RecordHeader {
pub fn from_bytes(bytes: Vec<u8>) -> Result<RecordHeader, Error> {
if bytes.len() > 1024 {
return Err(Error::Overflow {
limit: 1024,
value: bytes.len(),
msg: "supported data on header".to_string(),
});
}
let rrecord: RecordHeaderRepr = unsafe { ptr::read(bytes.as_ptr() as *const _) };
let mut data = rrecord.data.to_vec();
data.truncate(bytes.len() as usize);
let record = RecordHeader {
transaction: rrecord.transaction,
b_page: rrecord.b_page,
b_line: rrecord.b_line,
flags: rrecord.flags,
format: rrecord.format,
data,
};
Ok(record)
}
pub fn read(&self) -> Result<Vec<u8>, Error> {
Ok(rle_decode(&self.data))
}
}
fn rle_decode(data: &Vec<u8>) -> Vec<u8> {
let mut result = Vec::<u8>::new();
let mut iter = data.iter();
let iter = iter.by_ref();
while let Some(n) = iter.next() {
let n = *n;
let ni = n as i8;
match ni {
0 => break,
ni if ni > 0 => {
for next_byte in iter.take(n.into()) {
result.push(*next_byte);
}
}
_ => {
if let Some(next_byte) = iter.next() {
let to = (ni as i16).abs();
for _ in 0..to {
result.push(*next_byte);
}
}
}
}
}
result
}
#[cfg(test)]
pub mod tests {
use super::*;
#[test]
pub fn rle_decode_compressed() {
let data = vec![
0x01, 0xfe, 0xfd, 0x00, 0x03, 0x20, 0x00, 0x41, 0xfc, 0x61, 0x01, 0x42, 0xf7, 0x62,
0x01, 0x43, 0xf2, 0x63, 0x02, 0x44, 0x44,
];
let eresult = vec![
0xfe, 0x00, 0x00, 0x00, 0x20, 0x00, 0x41, 0x61, 0x61, 0x61, 0x61, 0x42, 0x62, 0x62,
0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x62, 0x43, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x44, 0x44,
];
let result = rle_decode(&data);
assert_eq!(eresult, result);
}
#[test]
pub fn rle_decode_uncompressed() {
let data = vec![
0x01, 0xfe, 0xfd, 0x00, 0x0a, 0x08, 0x00, 0x46, 0x69, 0x72, 0x65, 0x62, 0x69, 0x72,
0x64, 0x00,
];
let eresult = vec![
0xfe, 0x00, 0x00, 0x00, 0x08, 0x00, 0x46, 0x69, 0x72, 0x65, 0x62, 0x69, 0x72, 0x64,
];
let result = rle_decode(&data);
assert_eq!(eresult, result);
}
#[test]
pub fn rle_decode_compressed_varchar_with_666() {
let data = vec![0x01, 0xfe, 0xfd, 0x00, 0x02, 0x03, 0x00, 0xfd, 0x36];
let eresult = vec![0xFE, 0x00, 0x00, 0x00, 0x03, 0x00, 0x36, 0x36, 0x36];
let result = rle_decode(&data);
assert_eq!(eresult, result);
}
}