Coverage Report

Created: 2026-09-19 07:25

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/foldhash-0.2.0/src/quality.rs
Line
Count
Source
1
//! The foldhash implementation optimized for quality.
2
3
use core::hash::{BuildHasher, Hasher};
4
5
use crate::seed::SharedSeed;
6
7
use crate::{fast, folded_multiply, ARBITRARY0, ARBITRARY4};
8
9
/// A [`Hasher`] instance implementing foldhash, optimized for quality.
10
///
11
/// While you can create one directly with [`FoldHasher::with_seed`], you
12
/// most likely want to use [`RandomState`], [`SeedableRandomState`] or
13
/// [`FixedState`] to create [`FoldHasher`]s.
14
#[derive(Clone)]
15
pub struct FoldHasher<'a> {
16
    pub(crate) inner: fast::FoldHasher<'a>,
17
}
18
19
impl<'a> FoldHasher<'a> {
20
    /// Initializes this [`FoldHasher`] with the given per-hasher seed and
21
    /// [`SharedSeed`].
22
    #[inline(always)]
23
0
    pub const fn with_seed(per_hasher_seed: u64, shared_seed: &'a SharedSeed) -> FoldHasher<'a> {
24
0
        FoldHasher {
25
0
            inner: fast::FoldHasher::with_seed(per_hasher_seed, shared_seed),
26
0
        }
27
0
    }
28
}
29
30
impl<'a> Hasher for FoldHasher<'a> {
31
    #[inline(always)]
32
0
    fn write(&mut self, bytes: &[u8]) {
33
0
        self.inner.write(bytes);
34
0
    }
35
36
    #[inline(always)]
37
0
    fn write_u8(&mut self, i: u8) {
38
0
        self.inner.write_u8(i);
39
0
    }
40
41
    #[inline(always)]
42
0
    fn write_u16(&mut self, i: u16) {
43
0
        self.inner.write_u16(i);
44
0
    }
45
46
    #[inline(always)]
47
0
    fn write_u32(&mut self, i: u32) {
48
0
        self.inner.write_u32(i);
49
0
    }
50
51
    #[inline(always)]
52
0
    fn write_u64(&mut self, i: u64) {
53
0
        self.inner.write_u64(i);
54
0
    }
55
56
    #[inline(always)]
57
0
    fn write_u128(&mut self, i: u128) {
58
0
        self.inner.write_u128(i);
59
0
    }
60
61
    #[inline(always)]
62
0
    fn write_usize(&mut self, i: usize) {
63
0
        self.inner.write_usize(i);
64
0
    }
65
66
    #[cfg(feature = "nightly")]
67
    #[inline(always)]
68
    fn write_str(&mut self, s: &str) {
69
        self.inner.write_str(s);
70
    }
71
72
    #[inline(always)]
73
0
    fn finish(&self) -> u64 {
74
0
        folded_multiply(self.inner.finish(), ARBITRARY0)
75
0
    }
76
}
77
78
/// A [`BuildHasher`] for [`quality::FoldHasher`](FoldHasher) that is randomly initialized.
79
#[derive(Clone, Default, Debug)]
80
pub struct RandomState {
81
    inner: fast::RandomState,
82
}
83
84
impl BuildHasher for RandomState {
85
    type Hasher = FoldHasher<'static>;
86
87
    #[inline(always)]
88
0
    fn build_hasher(&self) -> FoldHasher<'static> {
89
0
        FoldHasher {
90
0
            inner: self.inner.build_hasher(),
91
0
        }
92
0
    }
93
}
94
95
/// A [`BuildHasher`] for [`quality::FoldHasher`](FoldHasher) that is randomly
96
/// initialized by default, but can also be initialized with a specific seed.
97
///
98
/// This can be useful for e.g. testing, but the downside is that this type
99
/// has a size of 16 bytes rather than the 8 bytes [`RandomState`] is.
100
#[derive(Clone, Default, Debug)]
101
pub struct SeedableRandomState {
102
    inner: fast::SeedableRandomState,
103
}
104
105
impl SeedableRandomState {
106
    /// Generates a random [`SeedableRandomState`], similar to [`RandomState`].
107
    #[inline(always)]
108
0
    pub fn random() -> Self {
109
0
        Self {
110
0
            inner: fast::SeedableRandomState::random(),
111
0
        }
112
0
    }
113
114
    /// Generates a fixed [`SeedableRandomState`], similar to [`FixedState`].
115
    #[inline(always)]
116
0
    pub fn fixed() -> Self {
117
0
        Self {
118
0
            inner: fast::SeedableRandomState::fixed(),
119
0
        }
120
0
    }
121
122
    /// Generates a [`SeedableRandomState`] with the given per-hasher seed
123
    /// and [`SharedSeed`].
124
    #[inline(always)]
125
0
    pub fn with_seed(per_hasher_seed: u64, shared_seed: &'static SharedSeed) -> Self {
126
0
        Self {
127
0
            // We do an additional folded multiply with the seed here for
128
0
            // the quality hash to ensure better independence between seed
129
0
            // and hash.
130
0
            inner: fast::SeedableRandomState::with_seed(
131
0
                folded_multiply(per_hasher_seed, ARBITRARY4),
132
0
                shared_seed,
133
0
            ),
134
0
        }
135
0
    }
136
}
137
138
impl BuildHasher for SeedableRandomState {
139
    type Hasher = FoldHasher<'static>;
140
141
    #[inline(always)]
142
0
    fn build_hasher(&self) -> FoldHasher<'static> {
143
0
        FoldHasher {
144
0
            inner: self.inner.build_hasher(),
145
0
        }
146
0
    }
147
}
148
149
/// A [`BuildHasher`] for [`quality::FoldHasher`](FoldHasher) that always has the same fixed seed.
150
///
151
/// Not recommended unless you absolutely need determinism.
152
#[derive(Clone, Default, Debug)]
153
pub struct FixedState {
154
    inner: fast::FixedState,
155
}
156
157
impl FixedState {
158
    /// Creates a [`FixedState`] with the given per-hasher seed.
159
    #[inline(always)]
160
0
    pub const fn with_seed(per_hasher_seed: u64) -> Self {
161
0
        Self {
162
0
            // We do an additional folded multiply with the seed here for
163
0
            // the quality hash to ensure better independence between seed
164
0
            // and hash. If the seed is zero the folded multiply is zero,
165
0
            // preserving with_seed(0) == default().
166
0
            inner: fast::FixedState::with_seed(folded_multiply(per_hasher_seed, ARBITRARY4)),
167
0
        }
168
0
    }
169
}
170
171
impl BuildHasher for FixedState {
172
    type Hasher = FoldHasher<'static>;
173
174
    #[inline(always)]
175
0
    fn build_hasher(&self) -> FoldHasher<'static> {
176
0
        FoldHasher {
177
0
            inner: self.inner.build_hasher(),
178
0
        }
179
0
    }
180
}