use crate::Error::{DataInvalid, DecodeFailed};
use crate::Result;
use crate::core::buffer::{Buffer, DecodeResult, Decoder, Encoder};
use crc::{CRC_8_AUTOSAR, Crc};
use std::mem::size_of;
const LOG_TAG: &str = "MMKV:Crc";
const CRC8: Crc<u8> = Crc::<u8>::new(&CRC_8_AUTOSAR);
pub struct CrcEncoderDecoder;
impl Encoder for CrcEncoderDecoder {
fn encode_to_bytes(&self, raw_buffer: &Buffer, _: u32) -> Result<Vec<u8>> {
let bytes_to_write = raw_buffer.to_bytes();
let sum = CRC8.checksum(bytes_to_write.as_slice());
let len = bytes_to_write.len() as u32 + 1;
let mut data = len.to_be_bytes().to_vec();
data.extend_from_slice(bytes_to_write.as_slice());
data.push(sum);
Ok(data)
}
}
impl Decoder for CrcEncoderDecoder {
fn decode_bytes(&self, data: &[u8], _: u32) -> Result<DecodeResult> {
let offset = size_of::<u32>();
let item_len = u32::from_be_bytes(data[0..offset].try_into().map_err(|_| DataInvalid)?);
let bytes_to_decode = &data[offset..(offset + item_len as usize - 1)];
let read_len = offset as u32 + item_len;
let sum = data[offset + item_len as usize - 1];
let result = if CRC8.checksum(bytes_to_decode) == sum {
Buffer::from_encoded_bytes(bytes_to_decode)
} else {
Err(DecodeFailed("CRC check failed".to_string()))
};
let buffer = match result {
Ok(data) => Some(data),
Err(e) => {
error!(LOG_TAG, "Failed to decode data, reason: {:?}", e);
None
}
};
Ok(DecodeResult {
buffer,
len: read_len,
})
}
}
#[cfg(test)]
mod tests {
use crate::core::buffer::{Buffer, Decoder, Encoder};
use crate::core::crc::CrcEncoderDecoder;
#[test]
fn test_crc_buffer() {
let buffer = Buffer::new("key", 1);
let bytes = CrcEncoderDecoder.encode_to_bytes(&buffer, 0).unwrap();
let decode_result = CrcEncoderDecoder.decode_bytes(bytes.as_slice(), 0).unwrap();
assert_eq!(decode_result.len, bytes.len() as u32);
assert_eq!(decode_result.buffer, Some(buffer));
}
}