use bytes::Bytes;
use crc::Crc;
use crc::CRC_32_ISO_HDLC;
const CRC32_ALGO: Crc<u32> = Crc::<u32>::new(&CRC_32_ISO_HDLC);
#[inline]
pub fn crc32(array: &[u8]) -> u32 {
if array.is_empty() {
return 0;
}
crc32_range(array, 0, array.len())
}
#[inline]
pub fn crc32_range(array: &[u8], offset: usize, length: usize) -> u32 {
if array.is_empty() || offset >= array.len() || length > array.len() - offset {
return 0;
}
let mut digest = CRC32_ALGO.digest();
digest.update(&array[offset..offset + length]);
digest.finalize() & 0x7FFFFFFF
}
#[inline]
pub fn crc32_bytes(buf: Option<&Bytes>) -> u32 {
match buf {
Some(data) if !data.is_empty() => {
let mut digest = CRC32_ALGO.digest();
digest.update(data);
digest.finalize() & 0x7FFFFFFF
}
_ => 0,
}
}
#[inline]
pub fn crc32_bytes_offset(array: &[u8], offset: usize, length: usize) -> u32 {
crc32_range(array, offset, length)
}
#[inline]
pub fn crc32_bytebuffer(byte_buffer: &[u8]) -> u32 {
if byte_buffer.is_empty() {
return 0;
}
let mut digest = CRC32_ALGO.digest();
digest.update(byte_buffer);
digest.finalize() & 0x7FFFFFFF
}
#[inline]
pub fn crc32_bytebuffers(byte_buffers: &[Vec<u8>]) -> u32 {
if byte_buffers.is_empty() {
return 0;
}
let mut digest = CRC32_ALGO.digest();
for buffer in byte_buffers {
digest.update(buffer.as_slice());
}
digest.finalize() & 0x7FFFFFFF
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_crc32_with_data() {
let buf = [1, 2, 3, 4, 5];
let checksum = crc32(&buf);
assert!(checksum > 0);
assert!(checksum <= 0x7FFFFFFF); }
#[test]
fn test_crc32_with_empty_array() {
let buf: &[u8] = &[];
assert_eq!(crc32(buf), 0);
}
#[test]
fn test_crc32_consistency() {
let data1 = b"Hello, World!";
let data2 = b"Hello, World!";
assert_eq!(crc32(data1), crc32(data2));
}
#[test]
fn test_crc32_different_data_different_checksum() {
let data1 = b"test1";
let data2 = b"test2";
assert_ne!(crc32(data1), crc32(data2));
}
#[test]
fn test_crc32_always_positive() {
let test_data = vec![
b"".as_slice(),
b"a".as_slice(),
b"test".as_slice(),
b"RocketMQ".as_slice(),
&[0xFF, 0xFF, 0xFF, 0xFF],
&[0x00, 0x01, 0x02, 0x03],
];
for data in test_data {
if !data.is_empty() {
let checksum = crc32(data);
assert!(checksum <= 0x7FFFFFFF, "Checksum should be positive: {}", checksum);
}
}
}
#[test]
fn test_crc32_range_full_array() {
let buf = [1, 2, 3, 4, 5];
let checksum1 = crc32(&buf);
let checksum2 = crc32_range(&buf, 0, buf.len());
assert_eq!(checksum1, checksum2);
}
#[test]
fn test_crc32_range_partial() {
let buf = b"Hello, World!";
let checksum = crc32_range(buf, 0, 5); assert!(checksum > 0);
}
#[test]
fn test_crc32_range_middle() {
let buf = b"Hello, World!";
let checksum = crc32_range(buf, 7, 5); assert!(checksum > 0);
}
#[test]
fn test_crc32_range_empty_array() {
let buf: &[u8] = &[];
assert_eq!(crc32_range(buf, 0, 0), 0);
}
#[test]
fn test_crc32_range_offset_out_of_bounds() {
let buf = [1, 2, 3, 4, 5];
assert_eq!(crc32_range(&buf, 10, 1), 0); }
#[test]
fn test_crc32_range_length_out_of_bounds() {
let buf = [1, 2, 3, 4, 5];
assert_eq!(crc32_range(&buf, 2, 10), 0); }
#[test]
fn test_crc32_range_zero_length() {
let buf = [1, 2, 3, 4, 5];
assert_eq!(crc32_range(&buf, 0, 0), 0);
}
#[test]
fn test_crc32_range_overflowing_length_returns_zero() {
let buf = [1, 2, 3, 4, 5];
assert_eq!(crc32_range(&buf, 1, usize::MAX), 0);
assert_eq!(crc32_range(&[1, 2], 1, usize::MAX), 0);
}
#[test]
fn test_crc32_bytes_with_data() {
let data = Bytes::from("test data");
let checksum = crc32_bytes(Some(&data));
assert!(checksum > 0);
}
#[test]
fn test_crc32_bytes_with_none() {
assert_eq!(crc32_bytes(None), 0);
}
#[test]
fn test_crc32_bytes_with_empty() {
let data = Bytes::new();
assert_eq!(crc32_bytes(Some(&data)), 0);
}
#[test]
fn test_crc32_bytes_consistency() {
let data1 = Bytes::from("RocketMQ");
let data2 = Bytes::from("RocketMQ");
assert_eq!(crc32_bytes(Some(&data1)), crc32_bytes(Some(&data2)));
}
#[test]
fn test_crc32_bytes_matches_slice() {
let data = b"test data";
let bytes = Bytes::from(&data[..]);
assert_eq!(crc32(data), crc32_bytes(Some(&bytes)));
}
#[test]
fn test_crc32_bytes_offset_valid_range() {
let buf = [1, 2, 3, 4, 5];
let checksum = crc32_bytes_offset(&buf, 1, 3); assert!(checksum > 0);
}
#[test]
fn test_crc32_bytes_offset_full_array() {
let buf = [1, 2, 3, 4, 5];
let checksum1 = crc32(&buf);
let checksum2 = crc32_bytes_offset(&buf, 0, buf.len());
assert_eq!(checksum1, checksum2);
}
#[test]
fn test_crc32_bytes_offset_empty_array() {
let buf: [u8; 0] = [];
assert_eq!(crc32_bytes_offset(&buf, 0, 0), 0);
}
#[test]
fn test_crc32_bytes_offset_invalid_range() {
let buf = [1, 2, 3, 4, 5];
assert_eq!(crc32_bytes_offset(&buf, 0, 10), 0);
assert_eq!(crc32_bytes_offset(&buf, 10, 1), 0);
}
#[test]
fn test_crc32_bytes_offset_overflowing_length_returns_zero() {
assert_eq!(crc32_bytes_offset(&[1, 2], 1, usize::MAX), 0);
}
#[test]
fn test_crc32_bytebuffer_with_data() {
let buffer = vec![1, 2, 3, 4, 5];
let checksum = crc32_bytebuffer(&buffer);
assert!(checksum > 0);
}
#[test]
fn test_crc32_bytebuffer_empty() {
let buffer: Vec<u8> = vec![];
assert_eq!(crc32_bytebuffer(&buffer), 0);
}
#[test]
fn test_crc32_bytebuffer_matches_slice() {
let data = vec![1, 2, 3, 4, 5];
let checksum1 = crc32(&data);
let checksum2 = crc32_bytebuffer(&data);
assert_eq!(checksum1, checksum2);
}
#[test]
fn test_crc32_bytebuffer_large_data() {
let buffer = vec![0x42; 10000]; let checksum = crc32_bytebuffer(&buffer);
assert!(checksum > 0);
}
#[test]
fn test_crc32_bytebuffers_single_buffer() {
let buffers = vec![vec![1, 2, 3, 4, 5]];
let checksum = crc32_bytebuffers(&buffers);
assert!(checksum > 0);
}
#[test]
fn test_crc32_bytebuffers_multiple_buffers() {
let buffers = vec![vec![1, 2, 3], vec![4, 5]];
let checksum = crc32_bytebuffers(&buffers);
assert!(checksum > 0);
}
#[test]
fn test_crc32_bytebuffers_matches_concatenated() {
let buffers = vec![vec![1, 2, 3], vec![4, 5]];
let concatenated = vec![1, 2, 3, 4, 5];
let checksum1 = crc32_bytebuffers(&buffers);
let checksum2 = crc32(&concatenated);
assert_eq!(checksum1, checksum2);
}
#[test]
fn test_crc32_bytebuffers_empty() {
let buffers: Vec<Vec<u8>> = vec![];
assert_eq!(crc32_bytebuffers(&buffers), 0);
}
#[test]
fn test_crc32_bytebuffers_with_empty_buffers() {
let buffers = vec![vec![], vec![1, 2, 3], vec![]];
let checksum = crc32_bytebuffers(&buffers);
assert!(checksum > 0);
}
#[test]
fn test_crc32_bytebuffers_many_small_buffers() {
let buffers = vec![vec![1], vec![2], vec![3], vec![4], vec![5]];
let concatenated = vec![1, 2, 3, 4, 5];
assert_eq!(crc32_bytebuffers(&buffers), crc32(&concatenated));
}
#[test]
fn test_all_functions_return_same_for_same_data() {
let data = b"RocketMQ";
let bytes = Bytes::from(&data[..]);
let buffer = data.to_vec();
let buffers = vec![data.to_vec()];
let c1 = crc32(data);
let c2 = crc32_range(data, 0, data.len());
let c3 = crc32_bytes(Some(&bytes));
let c4 = crc32_bytes_offset(data, 0, data.len());
let c5 = crc32_bytebuffer(&buffer);
let c6 = crc32_bytebuffers(&buffers);
assert_eq!(c1, c2);
assert_eq!(c1, c3);
assert_eq!(c1, c4);
assert_eq!(c1, c5);
assert_eq!(c1, c6);
}
#[test]
fn test_crc32_with_special_characters() {
let data = b"!@#$%^&*()_+-=[]{}|;':\",./<>?";
let checksum = crc32(data);
assert!(checksum > 0);
}
#[test]
fn test_crc32_with_unicode_bytes() {
let data = "你好,世界!".as_bytes();
let checksum = crc32(data);
assert!(checksum > 0);
}
#[test]
fn test_crc32_with_binary_data() {
let data = [0x00, 0xFF, 0xAA, 0x55, 0x12, 0x34, 0x56, 0x78];
let checksum = crc32(&data);
assert!(checksum > 0);
}
}