11// Copyright 2025 Don MacAskill. Licensed under MIT or Apache-2.0.
22
33//! This module contains a software fallback for unsupported architectures.
4- //!
5- //! Software fallback is conditionally compiled based on target architecture:
6- //! - Always included for non-SIMD architectures (not x86/x86_64/aarch64)
7- //! - Included for x86 when SSE4.1/PCLMULQDQ may not be available
8- //! - Included for aarch64 for runtime fallback when AES is not detected
9- //! - Excluded for x86_64 since SSE4.1/PCLMULQDQ are always available (but included for testing)
10-
11- #![ cfg( any(
12- // Non-aarch64/x86/x86_64 architectures always need software fallback
13- not( any( target_arch = "x86" , target_arch = "x86_64" , target_arch = "aarch64" ) ) ,
14- // x86 may not have SSE4.1/PCLMULQDQ support
15- all( target_arch = "x86" , any( not( target_feature = "sse4.1" ) , not( target_feature = "pclmulqdq" ) ) ) ,
16- // aarch64 needs software fallback for runtime detection when AES is not available...
17- // NEON doesn't guarantee AES, so for rare outlier CPUs this might not work 100%...
18- all( target_arch = "aarch64" , not( target_feature = "aes" ) ) ,
19- // Include for testing on all architectures
20- test
21- ) ) ]
224
235use crate :: consts:: CRC_64_NVME ;
246use crate :: CrcAlgorithm ;
257use crate :: CrcParams ;
268use crc:: { Algorithm , Table } ;
9+ use std:: collections:: HashMap ;
10+ use std:: sync:: { Mutex , OnceLock } ;
2711
2812#[ allow( unused) ]
2913const RUST_CRC32_AIXM : crc:: Crc < u32 , Table < 16 > > =
@@ -96,6 +80,9 @@ const RUST_CRC64_WE: crc::Crc<u64, Table<16>> = crc::Crc::<u64, Table<16>>::new(
9680#[ allow( unused) ]
9781const RUST_CRC64_XZ : crc:: Crc < u64 , Table < 16 > > = crc:: Crc :: < u64 , Table < 16 > > :: new ( & crc:: CRC_64_XZ ) ;
9882
83+ static CUSTOM_CRC32_CACHE : OnceLock < Mutex < HashMap < u32 , & ' static Algorithm < u32 > > > > = OnceLock :: new ( ) ;
84+ static CUSTOM_CRC64_CACHE : OnceLock < Mutex < HashMap < u64 , & ' static Algorithm < u64 > > > > = OnceLock :: new ( ) ;
85+
9986#[ allow( unused) ]
10087// Dispatch function that handles the generic case
10188pub ( crate ) fn update ( state : u64 , data : & [ u8 ] , params : CrcParams ) -> u64 {
@@ -115,19 +102,25 @@ pub(crate) fn update(state: u64, data: &[u8], params: CrcParams) -> u64 {
115102 CrcAlgorithm :: Crc32Mpeg2 => RUST_CRC32_MPEG_2 ,
116103 CrcAlgorithm :: Crc32Xfer => RUST_CRC32_XFER ,
117104 CrcAlgorithm :: Crc32Custom => {
118- let algorithm: Algorithm < u32 > = Algorithm {
119- width : params. width ,
120- poly : params. poly as u32 ,
121- init : params. init as u32 ,
122- refin : params. refin ,
123- refout : params. refout ,
124- xorout : params. xorout as u32 ,
125- check : params. check as u32 ,
126- residue : 0x00000000 , // unused in this context
127- } ;
128-
129- // ugly, but the crc crate is difficult to work with...
130- let static_algorithm = Box :: leak ( Box :: new ( algorithm) ) ;
105+ let cache = CUSTOM_CRC32_CACHE . get_or_init ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
106+ let mut cache = cache. lock ( ) . unwrap ( ) ;
107+
108+ // Create a key from params that uniquely identifies this algorithm
109+ let key = params. poly as u32 ;
110+
111+ let static_algorithm = cache. entry ( key) . or_insert_with ( || {
112+ let algorithm = Algorithm {
113+ width : params. width ,
114+ poly : params. poly as u32 ,
115+ init : params. init as u32 ,
116+ refin : params. refin ,
117+ refout : params. refout ,
118+ xorout : params. xorout as u32 ,
119+ check : params. check as u32 ,
120+ residue : 0x00000000 ,
121+ } ;
122+ Box :: leak ( Box :: new ( algorithm) )
123+ } ) ;
131124
132125 crc:: Crc :: < u32 , Table < 16 > > :: new ( static_algorithm)
133126 }
@@ -145,19 +138,24 @@ pub(crate) fn update(state: u64, data: &[u8], params: CrcParams) -> u64 {
145138 CrcAlgorithm :: Crc64We => RUST_CRC64_WE ,
146139 CrcAlgorithm :: Crc64Xz => RUST_CRC64_XZ ,
147140 CrcAlgorithm :: Crc64Custom => {
148- let algorithm: Algorithm < u64 > = Algorithm {
149- width : params. width ,
150- poly : params. poly ,
151- init : params. init ,
152- refin : params. refin ,
153- refout : params. refout ,
154- xorout : params. xorout ,
155- check : params. check ,
156- residue : 0x0000000000000000 , // unused in this context
157- } ;
158-
159- // ugly, but the crc crate is difficult to work with...
160- let static_algorithm = Box :: leak ( Box :: new ( algorithm) ) ;
141+ let cache = CUSTOM_CRC64_CACHE . get_or_init ( || Mutex :: new ( HashMap :: new ( ) ) ) ;
142+ let mut cache = cache. lock ( ) . unwrap ( ) ;
143+
144+ let key = params. poly ;
145+
146+ let static_algorithm = cache. entry ( key) . or_insert_with ( || {
147+ let algorithm = Algorithm {
148+ width : params. width ,
149+ poly : params. poly ,
150+ init : params. init ,
151+ refin : params. refin ,
152+ refout : params. refout ,
153+ xorout : params. xorout ,
154+ check : params. check ,
155+ residue : 0x0000000000000000 ,
156+ } ;
157+ Box :: leak ( Box :: new ( algorithm) )
158+ } ) ;
161159
162160 crc:: Crc :: < u64 , Table < 16 > > :: new ( static_algorithm)
163161 }
0 commit comments