1#![warn(unsafe_op_in_unsafe_fn)]
2
3#[cfg(target_arch = "x86_64")]
4mod avx2;
5mod generic;
6#[cfg(target_arch = "aarch64")]
7mod neon;
8#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
9mod wasm;
10
11pub fn adler32(start_checksum: u32, data: &[u8]) -> u32 {
12 #[cfg(target_arch = "x86_64")]
13 if crate::cpu_features::is_enabled_avx2() {
14 return avx2::adler32_avx2(start_checksum, data);
15 }
16
17 #[cfg(target_arch = "aarch64")]
18 if crate::cpu_features::is_enabled_neon() {
19 return self::neon::adler32_neon(start_checksum, data);
20 }
21
22 #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
23 if crate::cpu_features::is_enabled_simd128() {
24 return self::wasm::adler32_wasm(start_checksum, data);
25 }
26
27 generic::adler32_rust(start_checksum, data)
28}
29
30pub fn adler32_fold_copy(start_checksum: u32, dst: &mut [u8], src: &[u8]) -> u32 {
31 debug_assert!(dst.len() >= src.len(), "{} < {}", dst.len(), src.len());
32
33 dst[..src.len()].copy_from_slice(src);
36 adler32(start_checksum, src)
37}
38
39pub fn adler32_combine(adler1: u32, adler2: u32, len2: u64) -> u32 {
40 const BASE: u64 = self::BASE as u64;
41
42 let rem = len2 % BASE;
43
44 let adler1 = adler1 as u64;
45 let adler2 = adler2 as u64;
46
47 let mut sum1 = adler1 & 0xffff;
49 let mut sum2 = rem * sum1;
50 sum2 %= BASE;
51 sum1 += (adler2 & 0xffff) + BASE - 1;
52 sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
53
54 if sum1 >= BASE {
55 sum1 -= BASE;
56 }
57 if sum1 >= BASE {
58 sum1 -= BASE;
59 }
60 if sum2 >= (BASE << 1) {
61 sum2 -= BASE << 1;
62 }
63 if sum2 >= BASE {
64 sum2 -= BASE;
65 }
66
67 (sum1 | (sum2 << 16)) as u32
68}
69
70#[cfg(test)]
72fn naive_adler32(start_checksum: u32, data: &[u8]) -> u32 {
73 const MOD_ADLER: u32 = 65521; let mut a = start_checksum & 0xFFFF;
76 let mut b = (start_checksum >> 16) & 0xFFFF;
77
78 for &byte in data {
79 a = (a + byte as u32) % MOD_ADLER;
80 b = (b + a) % MOD_ADLER;
81 }
82
83 (b << 16) | a
84}
85
86const BASE: u32 = 65521; const NMAX: u32 = 5552;
88
89#[cfg(test)]
90mod test {
91 use super::*;
92
93 #[test]
94 fn naive_is_fancy_small_inputs() {
95 for i in 0..128 {
96 let v = (0u8..i).collect::<Vec<_>>();
97 assert_eq!(naive_adler32(1, &v), generic::adler32_rust(1, &v));
98 }
99 }
100
101 #[test]
102 fn test_adler32_combine() {
103 ::quickcheck::quickcheck(test as fn(_) -> _);
104
105 fn test(data: Vec<u8>) -> bool {
106 let Some(buf_len) = data.first().copied() else {
107 return true;
108 };
109
110 let buf_size = Ord::max(buf_len, 1) as usize;
111
112 let mut adler1 = 1;
113 let mut adler2 = 1;
114
115 for chunk in data.chunks(buf_size) {
116 adler1 = adler32(adler1, chunk);
117 }
118
119 adler2 = adler32(adler2, &data);
120
121 assert_eq!(adler1, adler2);
122
123 let combine1 = adler32_combine(adler1, adler2, data.len() as _);
124 let combine2 = adler32_combine(adler1, adler1, data.len() as _);
125 assert_eq!(combine1, combine2);
126
127 true
128 }
129 }
130}