54
54
//! Implements the [std::io::Write](https://doc.rust-lang.org/std/io/trait.Write.html) trait for
55
55
//! easier integration with existing code.
56
56
//!
57
- //! ```no_run
57
+ //! ```rust
58
58
//! use std::env;
59
59
//! use std::fs::File;
60
60
//! use crc_fast::{Digest, CrcAlgorithm::Crc32IsoHdlc};
@@ -261,6 +261,19 @@ impl Digest {
261
261
}
262
262
}
263
263
264
+ /// Creates a new `Digest` instance with custom parameters.
265
+ #[ inline( always) ]
266
+ pub fn new_with_params ( params : CrcParams ) -> Self {
267
+ let calculator = Calculator :: calculate as CalculatorFn ;
268
+
269
+ Self {
270
+ state : params. init ,
271
+ amount : 0 ,
272
+ params,
273
+ calculator,
274
+ }
275
+ }
276
+
264
277
/// Updates the CRC state with the given data.
265
278
#[ inline( always) ]
266
279
pub fn update ( & mut self , data : & [ u8 ] ) {
@@ -361,6 +374,13 @@ pub fn checksum(algorithm: CrcAlgorithm, buf: &[u8]) -> u64 {
361
374
calculator ( params. init , buf, params) ^ params. xorout
362
375
}
363
376
377
+ /// Computes the CRC checksum for the given data using the custom specified parameters.
378
+ pub fn checksum_with_params ( params : CrcParams , buf : & [ u8 ] ) -> u64 {
379
+ let calculator = Calculator :: calculate as CalculatorFn ;
380
+
381
+ calculator ( params. init , buf, params) ^ params. xorout
382
+ }
383
+
364
384
/// Computes the CRC checksum for the given file using the specified algorithm.
365
385
///
366
386
/// Appears to be much faster (~2X) than using Writer and io::*, at least on Apple M2 Ultra
@@ -371,7 +391,7 @@ pub fn checksum(algorithm: CrcAlgorithm, buf: &[u8]) -> u64 {
371
391
///
372
392
/// # Examples
373
393
/// ### checksum_file
374
- ///```no_run
394
+ ///```rust
375
395
/// use std::env;
376
396
/// use crc_fast::{checksum_file, CrcAlgorithm::Crc32IsoHdlc};
377
397
///
@@ -389,7 +409,32 @@ pub fn checksum_file(
389
409
path : & str ,
390
410
chunk_size : Option < usize > ,
391
411
) -> Result < u64 , std:: io:: Error > {
392
- let mut digest = Digest :: new ( algorithm) ;
412
+ checksum_file_with_digest ( Digest :: new ( algorithm) , path, chunk_size)
413
+ }
414
+
415
+ /// Computes the CRC checksum for the given file using the custom specified parameters.
416
+ ///
417
+ /// # Errors
418
+ ///
419
+ /// This function will return an error if the file cannot be read.
420
+ pub fn checksum_file_with_params (
421
+ params : CrcParams ,
422
+ path : & str ,
423
+ chunk_size : Option < usize > ,
424
+ ) -> Result < u64 , std:: io:: Error > {
425
+ checksum_file_with_digest ( Digest :: new_with_params ( params) , path, chunk_size)
426
+ }
427
+
428
+ /// Computes the CRC checksum for the given file using the specified Digest.
429
+ ///
430
+ /// # Errors
431
+ ///
432
+ /// This function will return an error if the file cannot be read.
433
+ fn checksum_file_with_digest (
434
+ mut digest : Digest ,
435
+ path : & str ,
436
+ chunk_size : Option < usize > ,
437
+ ) -> Result < u64 , std:: io:: Error > {
393
438
let mut file = File :: open ( path) ?;
394
439
395
440
// 512KiB KiB was fastest in my benchmarks on an Apple M2 Ultra
@@ -540,19 +585,78 @@ mod lib {
540
585
}
541
586
}
542
587
588
+ #[ test]
589
+ fn test_checksum_with_custom_params ( ) {
590
+ // CRC-32 reflected
591
+ assert_eq ! (
592
+ checksum_with_params( CRC32_ISCSI , TEST_CHECK_STRING ) ,
593
+ CRC32_ISCSI . check,
594
+ ) ;
595
+
596
+ // CRC-32 forward
597
+ assert_eq ! (
598
+ checksum_with_params( CRC32_BZIP2 , TEST_CHECK_STRING ) ,
599
+ CRC32_BZIP2 . check,
600
+ ) ;
601
+
602
+ // CRC-64 reflected
603
+ assert_eq ! (
604
+ checksum_with_params( CRC64_NVME , TEST_CHECK_STRING ) ,
605
+ CRC64_NVME . check,
606
+ ) ;
607
+
608
+ // CRC-64 forward
609
+ assert_eq ! (
610
+ checksum_with_params( CRC64_ECMA_182 , TEST_CHECK_STRING ) ,
611
+ CRC64_ECMA_182 . check,
612
+ ) ;
613
+ }
614
+
543
615
#[ test]
544
616
fn test_digest_updates_check ( ) {
545
617
for config in TEST_ALL_CONFIGS {
546
618
let mut digest = Digest :: new ( config. get_algorithm ( ) ) ;
547
- digest. update ( b"123" ) ;
548
- digest. update ( b"456" ) ;
549
- digest. update ( b"789" ) ;
550
- let result = digest. finalize ( ) ;
551
-
552
- assert_eq ! ( result, config. get_check( ) ) ;
619
+ check_digest ( Digest :: new ( config. get_algorithm ( ) ) , config. get_check ( ) ) ;
553
620
}
554
621
}
555
622
623
+ #[ test]
624
+ fn test_digest_updates_check_with_custom_params ( ) {
625
+ // CRC-32 reflected
626
+ check_digest (
627
+ Digest :: new_with_params ( CRC32_ISCSI ) ,
628
+ CRC32_ISCSI . check ,
629
+ ) ;
630
+
631
+ // CRC-32 forward
632
+ check_digest (
633
+ Digest :: new_with_params ( CRC32_BZIP2 ) ,
634
+ CRC32_BZIP2 . check ,
635
+ ) ;
636
+
637
+ // CRC-64 reflected
638
+ check_digest (
639
+ Digest :: new_with_params ( CRC64_NVME ) ,
640
+ CRC64_NVME . check ,
641
+ ) ;
642
+
643
+ // CRC-64 forward
644
+ check_digest (
645
+ Digest :: new_with_params ( CRC64_ECMA_182 ) ,
646
+ CRC64_ECMA_182 . check ,
647
+ ) ;
648
+ }
649
+
650
+ fn check_digest ( mut digest : Digest , check : u64 ) {
651
+ digest. update ( b"123" ) ;
652
+ digest. update ( b"456" ) ;
653
+ digest. update ( b"789" ) ;
654
+ assert_eq ! (
655
+ digest. finalize( ) ,
656
+ check,
657
+ ) ;
658
+ }
659
+
556
660
#[ test]
557
661
fn test_small_all_lengths ( ) {
558
662
for config in TEST_ALL_CONFIGS {
@@ -634,7 +738,7 @@ mod lib {
634
738
// Create a test file with repeating zeros
635
739
let test_file_path = "test/test_crc32_hash_file.bin" ;
636
740
let data = vec ! [ 0u8 ; 1024 * 1024 ] ; // 1 MiB of zeros
637
- if let Err ( e) = std :: fs :: write ( test_file_path, & data) {
741
+ if let Err ( e) = write ( test_file_path, & data) {
638
742
eprintln ! ( "Skipping test due to write error: {}" , e) ;
639
743
return ;
640
744
}
@@ -647,6 +751,52 @@ mod lib {
647
751
std:: fs:: remove_file ( test_file_path) . unwrap ( ) ;
648
752
}
649
753
754
+ #[ test]
755
+ fn test_checksum_file_with_custom_params ( ) {
756
+ // Create a test file with repeating zeros
757
+ let test_file_path = "test/test_crc32_hash_file_custom.bin" ;
758
+ let data = vec ! [ 0u8 ; 1024 * 1024 ] ; // 1 MiB of zeros
759
+ if let Err ( e) = write ( test_file_path, & data) {
760
+ eprintln ! ( "Skipping test due to write error: {}" , e) ;
761
+ return ;
762
+ }
763
+
764
+ // CRC-32 reflected
765
+ check_file (
766
+ CRC32_ISCSI ,
767
+ test_file_path,
768
+ CRC32_ISCSI . check ,
769
+ ) ;
770
+
771
+ // CRC-32 forward
772
+ check_file (
773
+ CRC32_BZIP2 ,
774
+ test_file_path,
775
+ CRC32_BZIP2 . check ,
776
+ ) ;
777
+
778
+ // CRC-64 reflected
779
+ check_file (
780
+ CRC64_NVME ,
781
+ test_file_path,
782
+ CRC64_NVME . check ,
783
+ ) ;
784
+
785
+ // CRC-64 forward
786
+ check_file (
787
+ CRC64_ECMA_182 ,
788
+ test_file_path,
789
+ CRC64_ECMA_182 . check ,
790
+ ) ;
791
+
792
+ std:: fs:: remove_file ( test_file_path) . unwrap ( ) ;
793
+ }
794
+
795
+ fn check_file ( params : CrcParams , file_path : & str , check : u64 ) {
796
+ let result = checksum_file_with_params ( params, file_path, None ) . unwrap ( ) ;
797
+ assert_eq ! ( result, check) ;
798
+ }
799
+
650
800
#[ test]
651
801
fn test_writer ( ) {
652
802
// Create a test file with repeating zeros
0 commit comments