1use bytes::Bytes;
19use crc::Crc;
20use crc::CRC_32_ISO_HDLC;
21
22const CRC32_ALGO: Crc<u32> = Crc::<u32>::new(&CRC_32_ISO_HDLC);
24
25#[inline]
50pub fn crc32(array: &[u8]) -> u32 {
51 if array.is_empty() {
52 return 0;
53 }
54 crc32_range(array, 0, array.len())
55}
56
57#[inline]
85pub fn crc32_range(array: &[u8], offset: usize, length: usize) -> u32 {
86 if array.is_empty() || offset >= array.len() || offset + length > array.len() {
87 return 0;
88 }
89
90 let mut digest = CRC32_ALGO.digest();
91 digest.update(&array[offset..offset + length]);
92 digest.finalize() & 0x7FFFFFFF
93}
94
95#[inline]
116pub fn crc32_bytes(buf: Option<&Bytes>) -> u32 {
117 match buf {
118 Some(data) if !data.is_empty() => {
119 let mut digest = CRC32_ALGO.digest();
120 digest.update(data);
121 digest.finalize() & 0x7FFFFFFF
122 }
123 _ => 0,
124 }
125}
126
127#[inline]
139pub fn crc32_bytes_offset(array: &[u8], offset: usize, length: usize) -> u32 {
140 crc32_range(array, offset, length)
141}
142
143#[inline]
165pub fn crc32_bytebuffer(byte_buffer: &[u8]) -> u32 {
166 if byte_buffer.is_empty() {
167 return 0;
168 }
169
170 let mut digest = CRC32_ALGO.digest();
171 digest.update(byte_buffer);
172 digest.finalize() & 0x7FFFFFFF
173}
174
175#[inline]
195pub fn crc32_bytebuffers(byte_buffers: &[Vec<u8>]) -> u32 {
196 if byte_buffers.is_empty() {
197 return 0;
198 }
199
200 let mut digest = CRC32_ALGO.digest();
201 for buffer in byte_buffers {
202 digest.update(buffer.as_slice());
203 }
204 digest.finalize() & 0x7FFFFFFF
205}
206
207#[cfg(test)]
208mod tests {
209 use super::*;
210
211 #[test]
214 fn test_crc32_with_data() {
215 let buf = [1, 2, 3, 4, 5];
216 let checksum = crc32(&buf);
217 assert!(checksum > 0);
218 assert!(checksum <= 0x7FFFFFFF); }
220
221 #[test]
222 fn test_crc32_with_empty_array() {
223 let buf: &[u8] = &[];
224 assert_eq!(crc32(buf), 0);
225 }
226
227 #[test]
228 fn test_crc32_consistency() {
229 let data1 = b"Hello, World!";
230 let data2 = b"Hello, World!";
231 assert_eq!(crc32(data1), crc32(data2));
232 }
233
234 #[test]
235 fn test_crc32_different_data_different_checksum() {
236 let data1 = b"test1";
237 let data2 = b"test2";
238 assert_ne!(crc32(data1), crc32(data2));
239 }
240
241 #[test]
242 fn test_crc32_always_positive() {
243 let test_data = vec![
245 b"".as_slice(),
246 b"a".as_slice(),
247 b"test".as_slice(),
248 b"RocketMQ".as_slice(),
249 &[0xFF, 0xFF, 0xFF, 0xFF],
250 &[0x00, 0x01, 0x02, 0x03],
251 ];
252
253 for data in test_data {
254 if !data.is_empty() {
255 let checksum = crc32(data);
256 assert!(
257 checksum <= 0x7FFFFFFF,
258 "Checksum should be positive: {}",
259 checksum
260 );
261 }
262 }
263 }
264
265 #[test]
268 fn test_crc32_range_full_array() {
269 let buf = [1, 2, 3, 4, 5];
270 let checksum1 = crc32(&buf);
271 let checksum2 = crc32_range(&buf, 0, buf.len());
272 assert_eq!(checksum1, checksum2);
273 }
274
275 #[test]
276 fn test_crc32_range_partial() {
277 let buf = b"Hello, World!";
278 let checksum = crc32_range(buf, 0, 5); assert!(checksum > 0);
280 }
281
282 #[test]
283 fn test_crc32_range_middle() {
284 let buf = b"Hello, World!";
285 let checksum = crc32_range(buf, 7, 5); assert!(checksum > 0);
287 }
288
289 #[test]
290 fn test_crc32_range_empty_array() {
291 let buf: &[u8] = &[];
292 assert_eq!(crc32_range(buf, 0, 0), 0);
293 }
294
295 #[test]
296 fn test_crc32_range_offset_out_of_bounds() {
297 let buf = [1, 2, 3, 4, 5];
298 assert_eq!(crc32_range(&buf, 10, 1), 0); }
300
301 #[test]
302 fn test_crc32_range_length_out_of_bounds() {
303 let buf = [1, 2, 3, 4, 5];
304 assert_eq!(crc32_range(&buf, 2, 10), 0); }
306
307 #[test]
308 fn test_crc32_range_zero_length() {
309 let buf = [1, 2, 3, 4, 5];
310 assert_eq!(crc32_range(&buf, 0, 0), 0);
311 }
312
313 #[test]
316 fn test_crc32_bytes_with_data() {
317 let data = Bytes::from("test data");
318 let checksum = crc32_bytes(Some(&data));
319 assert!(checksum > 0);
320 }
321
322 #[test]
323 fn test_crc32_bytes_with_none() {
324 assert_eq!(crc32_bytes(None), 0);
325 }
326
327 #[test]
328 fn test_crc32_bytes_with_empty() {
329 let data = Bytes::new();
330 assert_eq!(crc32_bytes(Some(&data)), 0);
331 }
332
333 #[test]
334 fn test_crc32_bytes_consistency() {
335 let data1 = Bytes::from("RocketMQ");
336 let data2 = Bytes::from("RocketMQ");
337 assert_eq!(crc32_bytes(Some(&data1)), crc32_bytes(Some(&data2)));
338 }
339
340 #[test]
341 fn test_crc32_bytes_matches_slice() {
342 let data = b"test data";
343 let bytes = Bytes::from(&data[..]);
344 assert_eq!(crc32(data), crc32_bytes(Some(&bytes)));
345 }
346
347 #[test]
350 fn test_crc32_bytes_offset_valid_range() {
351 let buf = [1, 2, 3, 4, 5];
352 let checksum = crc32_bytes_offset(&buf, 1, 3); assert!(checksum > 0);
354 }
355
356 #[test]
357 fn test_crc32_bytes_offset_full_array() {
358 let buf = [1, 2, 3, 4, 5];
359 let checksum1 = crc32(&buf);
360 let checksum2 = crc32_bytes_offset(&buf, 0, buf.len());
361 assert_eq!(checksum1, checksum2);
362 }
363
364 #[test]
365 fn test_crc32_bytes_offset_empty_array() {
366 let buf: [u8; 0] = [];
367 assert_eq!(crc32_bytes_offset(&buf, 0, 0), 0);
368 }
369
370 #[test]
371 fn test_crc32_bytes_offset_invalid_range() {
372 let buf = [1, 2, 3, 4, 5];
373 assert_eq!(crc32_bytes_offset(&buf, 0, 10), 0);
374 assert_eq!(crc32_bytes_offset(&buf, 10, 1), 0);
375 }
376
377 #[test]
380 fn test_crc32_bytebuffer_with_data() {
381 let buffer = vec![1, 2, 3, 4, 5];
382 let checksum = crc32_bytebuffer(&buffer);
383 assert!(checksum > 0);
384 }
385
386 #[test]
387 fn test_crc32_bytebuffer_empty() {
388 let buffer: Vec<u8> = vec![];
389 assert_eq!(crc32_bytebuffer(&buffer), 0);
390 }
391
392 #[test]
393 fn test_crc32_bytebuffer_matches_slice() {
394 let data = vec![1, 2, 3, 4, 5];
395 let checksum1 = crc32(&data);
396 let checksum2 = crc32_bytebuffer(&data);
397 assert_eq!(checksum1, checksum2);
398 }
399
400 #[test]
401 fn test_crc32_bytebuffer_large_data() {
402 let buffer = vec![0x42; 10000]; let checksum = crc32_bytebuffer(&buffer);
404 assert!(checksum > 0);
405 }
406
407 #[test]
410 fn test_crc32_bytebuffers_single_buffer() {
411 let buffers = vec![vec![1, 2, 3, 4, 5]];
412 let checksum = crc32_bytebuffers(&buffers);
413 assert!(checksum > 0);
414 }
415
416 #[test]
417 fn test_crc32_bytebuffers_multiple_buffers() {
418 let buffers = vec![vec![1, 2, 3], vec![4, 5]];
419 let checksum = crc32_bytebuffers(&buffers);
420 assert!(checksum > 0);
421 }
422
423 #[test]
424 fn test_crc32_bytebuffers_matches_concatenated() {
425 let buffers = vec![vec![1, 2, 3], vec![4, 5]];
426 let concatenated = vec![1, 2, 3, 4, 5];
427
428 let checksum1 = crc32_bytebuffers(&buffers);
429 let checksum2 = crc32(&concatenated);
430
431 assert_eq!(checksum1, checksum2);
432 }
433
434 #[test]
435 fn test_crc32_bytebuffers_empty() {
436 let buffers: Vec<Vec<u8>> = vec![];
437 assert_eq!(crc32_bytebuffers(&buffers), 0);
438 }
439
440 #[test]
441 fn test_crc32_bytebuffers_with_empty_buffers() {
442 let buffers = vec![vec![], vec![1, 2, 3], vec![]];
443 let checksum = crc32_bytebuffers(&buffers);
444 assert!(checksum > 0);
445 }
446
447 #[test]
448 fn test_crc32_bytebuffers_many_small_buffers() {
449 let buffers = vec![vec![1], vec![2], vec![3], vec![4], vec![5]];
450 let concatenated = vec![1, 2, 3, 4, 5];
451
452 assert_eq!(crc32_bytebuffers(&buffers), crc32(&concatenated));
453 }
454
455 #[test]
458 fn test_all_functions_return_same_for_same_data() {
459 let data = b"RocketMQ";
460 let bytes = Bytes::from(&data[..]);
461 let buffer = data.to_vec();
462 let buffers = vec![data.to_vec()];
463
464 let c1 = crc32(data);
465 let c2 = crc32_range(data, 0, data.len());
466 let c3 = crc32_bytes(Some(&bytes));
467 let c4 = crc32_bytes_offset(data, 0, data.len());
468 let c5 = crc32_bytebuffer(&buffer);
469 let c6 = crc32_bytebuffers(&buffers);
470
471 assert_eq!(c1, c2);
472 assert_eq!(c1, c3);
473 assert_eq!(c1, c4);
474 assert_eq!(c1, c5);
475 assert_eq!(c1, c6);
476 }
477
478 #[test]
479 fn test_crc32_with_special_characters() {
480 let data = b"!@#$%^&*()_+-=[]{}|;':\",./<>?";
481 let checksum = crc32(data);
482 assert!(checksum > 0);
483 }
484
485 #[test]
486 fn test_crc32_with_unicode_bytes() {
487 let data = "你好,世界!".as_bytes();
488 let checksum = crc32(data);
489 assert!(checksum > 0);
490 }
491
492 #[test]
493 fn test_crc32_with_binary_data() {
494 let data = [0x00, 0xFF, 0xAA, 0x55, 0x12, 0x34, 0x56, 0x78];
495 let checksum = crc32(&data);
496 assert!(checksum > 0);
497 }
498}