Coverage Report

Created: 2026-08-05 07:37

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/zlib-rs-0.6.7/src/adler32.rs
Line
Count
Source
1
//! The adler32 checksum algorithm.
2
3
#[cfg(target_arch = "x86_64")]
4
mod avx2;
5
#[cfg(feature = "avx512")]
6
#[cfg(target_arch = "x86_64")]
7
mod avx512;
8
#[cfg(feature = "avx512")]
9
#[cfg(target_arch = "x86_64")]
10
mod avx512_vnni;
11
mod generic;
12
#[cfg(all(target_arch = "loongarch64", feature = "lsx"))]
13
mod lsx;
14
#[cfg(target_arch = "aarch64")]
15
mod neon;
16
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
17
mod wasm;
18
19
2.96k
pub fn adler32(start_checksum: u32, data: &[u8]) -> u32 {
20
    #[cfg(feature = "avx512")]
21
    #[cfg(target_arch = "x86_64")]
22
    if cfg!(all(target_feature = "avx512f", target_feature = "avx512bw")) {
23
        return avx512::adler32_avx512(start_checksum, data);
24
    }
25
26
    #[cfg(target_arch = "x86_64")]
27
2.96k
    if crate::cpu_features::is_enabled_avx2_and_bmi2() {
28
2.96k
        return avx2::adler32_avx2(start_checksum, data);
29
0
    }
30
31
    #[cfg(target_arch = "aarch64")]
32
    if crate::cpu_features::is_enabled_neon() {
33
        return self::neon::adler32_neon(start_checksum, data);
34
    }
35
36
    #[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
37
    if crate::cpu_features::is_enabled_simd128() {
38
        return self::wasm::adler32_wasm(start_checksum, data);
39
    }
40
41
    #[cfg(all(target_arch = "loongarch64", feature = "lsx"))]
42
    if crate::cpu_features::is_enabled_lsx() {
43
        return self::lsx::adler32_lsx(start_checksum, data);
44
    }
45
46
0
    generic::adler32_rust(start_checksum, data)
47
2.96k
}
48
49
2.47k
pub(crate) fn adler32_fold_copy(start_checksum: u32, dst: &mut [u8], src: &[u8]) -> u32 {
50
2.47k
    debug_assert!(dst.len() >= src.len(), "{} < {}", dst.len(), src.len());
51
52
    // integrating the memcpy into the adler32 function did not have any benefits, and in fact was
53
    // a bit slower for very small chunk sizes.
54
2.47k
    dst[..src.len()].copy_from_slice(src);
55
2.47k
    adler32(start_checksum, src)
56
2.47k
}
57
58
0
pub fn adler32_combine(adler1: u32, adler2: u32, len2: u64) -> u32 {
59
    const BASE: u64 = self::BASE as u64;
60
61
0
    let rem = len2 % BASE;
62
63
0
    let adler1 = adler1 as u64;
64
0
    let adler2 = adler2 as u64;
65
66
    /* the derivation of this formula is left as an exercise for the reader */
67
0
    let mut sum1 = adler1 & 0xffff;
68
0
    let mut sum2 = rem * sum1;
69
0
    sum2 %= BASE;
70
0
    sum1 += (adler2 & 0xffff) + BASE - 1;
71
0
    sum2 += ((adler1 >> 16) & 0xffff) + ((adler2 >> 16) & 0xffff) + BASE - rem;
72
73
0
    if sum1 >= BASE {
74
0
        sum1 -= BASE;
75
0
    }
76
0
    if sum1 >= BASE {
77
0
        sum1 -= BASE;
78
0
    }
79
0
    if sum2 >= (BASE << 1) {
80
0
        sum2 -= BASE << 1;
81
0
    }
82
0
    if sum2 >= BASE {
83
0
        sum2 -= BASE;
84
0
    }
85
86
0
    (sum1 | (sum2 << 16)) as u32
87
0
}
88
89
// inefficient but correct, useful for testing
90
#[cfg(test)]
91
fn naive_adler32(start_checksum: u32, data: &[u8]) -> u32 {
92
    const MOD_ADLER: u32 = 65521; // Largest prime smaller than 2^16
93
94
    let mut a = start_checksum & 0xFFFF;
95
    let mut b = (start_checksum >> 16) & 0xFFFF;
96
97
    for &byte in data {
98
        a = (a + byte as u32) % MOD_ADLER;
99
        b = (b + a) % MOD_ADLER;
100
    }
101
102
    (b << 16) | a
103
}
104
105
const BASE: u32 = 65521; /* largest prime smaller than 65536 */
106
const NMAX: u32 = 5552;
107
108
#[cfg(test)]
109
mod test {
110
    use super::*;
111
112
    #[test]
113
    fn naive_is_fancy_small_inputs() {
114
        for i in 0..128 {
115
            let v = (0u8..i).collect::<Vec<_>>();
116
            assert_eq!(naive_adler32(1, &v), generic::adler32_rust(1, &v));
117
        }
118
    }
119
120
    #[test]
121
    fn test_adler32_combine() {
122
        ::quickcheck::quickcheck(test as fn(_) -> _);
123
124
        fn test(data: Vec<u8>) -> bool {
125
            let Some(buf_len) = data.first().copied() else {
126
                return true;
127
            };
128
129
            let buf_size = Ord::max(buf_len, 1) as usize;
130
131
            let mut adler1 = 1;
132
            let mut adler2 = 1;
133
134
            for chunk in data.chunks(buf_size) {
135
                adler1 = adler32(adler1, chunk);
136
            }
137
138
            adler2 = adler32(adler2, &data);
139
140
            assert_eq!(adler1, adler2);
141
142
            let combine1 = adler32_combine(adler1, adler2, data.len() as _);
143
            let combine2 = adler32_combine(adler1, adler1, data.len() as _);
144
            assert_eq!(combine1, combine2);
145
146
            true
147
        }
148
    }
149
}