Coverage Report

Created: 2026-06-30 07:02

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/hash32-0.3.1/src/murmur3.rs
Line
Count
Source
1
use core::slice;
2
use core::mem::MaybeUninit;
3
4
use byteorder::{ByteOrder, LE};
5
6
use crate::Hasher as _;
7
8
/// 32-bit MurmurHash3 hasher
9
pub struct Hasher {
10
    buf: Buffer,
11
    index: Index,
12
    processed: u32,
13
    state: State,
14
}
15
16
struct State(u32);
17
18
#[derive(Clone, Copy)]
19
#[repr(align(4))]
20
struct Buffer {
21
    bytes: MaybeUninit<[u8; 4]>,
22
}
23
24
#[derive(Clone, Copy, PartialEq)]
25
enum Index {
26
    _0,
27
    _1,
28
    _2,
29
    _3,
30
}
31
32
impl Index {
33
0
    fn usize(&self) -> usize {
34
0
        match *self {
35
0
            Index::_0 => 0,
36
0
            Index::_1 => 1,
37
0
            Index::_2 => 2,
38
0
            Index::_3 => 3,
39
        }
40
0
    }
41
}
42
43
impl From<usize> for Index {
44
0
    fn from(x: usize) -> Self {
45
0
        match x % 4 {
46
0
            0 => Index::_0,
47
0
            1 => Index::_1,
48
0
            2 => Index::_2,
49
0
            3 => Index::_3,
50
0
            _ => unreachable!(),
51
        }
52
0
    }
53
}
54
55
impl Hasher {
56
0
    fn push(&mut self, buf: &[u8]) {
57
0
        let start = self.index.usize();
58
0
        let len = buf.len();
59
        // NOTE(unsafe) avoid calling `memcpy` on a 0-3 byte copy
60
        // self.buf.bytes[start..start+len].copy_from(buf);
61
0
        for i in 0..len {
62
0
            unsafe {
63
0
                *self.buf.bytes.assume_init_mut().get_unchecked_mut(start + i) = *buf.get_unchecked(i);
64
0
            }
65
        }
66
0
        self.index = Index::from(start + len);
67
0
    }
68
}
69
70
impl Default for Hasher {
71
    #[allow(deprecated)]
72
0
    fn default() -> Self {
73
0
        Hasher {
74
0
            buf: Buffer { bytes: MaybeUninit::uninit() },
75
0
            index: Index::_0,
76
0
            processed: 0,
77
0
            state: State(0),
78
0
        }
79
0
    }
80
}
81
82
impl crate::Hasher for Hasher {
83
0
    fn finish32(&self) -> u32 {
84
        // tail
85
0
        let mut state = match self.index {
86
            Index::_3 => {
87
0
                let mut block = 0;
88
0
                unsafe {
89
0
                    block ^= u32::from(self.buf.bytes.assume_init_ref()[2]) << 16;
90
0
                    block ^= u32::from(self.buf.bytes.assume_init_ref()[1]) << 8;
91
0
                    block ^= u32::from(self.buf.bytes.assume_init_ref()[0]);
92
0
                }
93
0
                self.state.0 ^ pre_mix(block)
94
            }
95
            Index::_2 => {
96
0
                let mut block = 0;
97
0
                unsafe {
98
0
                    block ^= u32::from(self.buf.bytes.assume_init_ref()[1]) << 8;
99
0
                    block ^= u32::from(self.buf.bytes.assume_init_ref()[0]);
100
0
                }
101
0
                self.state.0 ^ pre_mix(block)
102
            }
103
            Index::_1 => {
104
0
                let mut block = 0;
105
0
                unsafe {
106
0
                    block ^= u32::from(self.buf.bytes.assume_init_ref()[0]);
107
0
                }
108
0
                self.state.0 ^ pre_mix(block)
109
            }
110
0
            Index::_0 => self.state.0,
111
        };
112
113
        // finalization mix
114
0
        state ^= self.processed;
115
0
        state ^= state >> 16;
116
0
        state = state.wrapping_mul(0x85ebca6b);
117
0
        state ^= state >> 13;
118
0
        state = state.wrapping_mul(0xc2b2ae35);
119
0
        state ^= state >> 16;
120
121
0
        state
122
0
    }
123
}
124
125
impl core::hash::Hasher for Hasher {
126
    #[inline]
127
0
    fn write(&mut self, bytes: &[u8]) {
128
0
        let len = bytes.len();
129
0
        self.processed += len as u32;
130
131
0
        let body = if self.index == Index::_0 {
132
0
            bytes
133
        } else {
134
0
            let index = self.index.usize();
135
0
            if len + index >= 4 {
136
                // we can complete a block using the data left in the buffer
137
                // NOTE(unsafe) avoid panicking branch (`slice_index_len_fail`)
138
                // let (head, body) = bytes.split_at(4 - index);
139
0
                let mid = 4 - index;
140
0
                let head = unsafe { slice::from_raw_parts(bytes.as_ptr(), mid) };
141
0
                let body = unsafe {
142
0
                    slice::from_raw_parts(bytes.as_ptr().offset(mid as isize), len - mid)
143
                };
144
145
                // NOTE(unsafe) avoid calling `memcpy` on a 0-3 byte copy
146
                // self.buf.bytes[index..].copy_from_slice(head);
147
0
                for i in 0..4 - index {
148
0
                    unsafe {
149
0
                        *self.buf.bytes.assume_init_mut().get_unchecked_mut(index + i) = *head.get_unchecked(i);
150
0
                    }
151
                }
152
153
0
                self.index = Index::_0;
154
155
0
                self.state.process_block(&self.buf.bytes);
156
157
0
                body
158
            } else {
159
0
                bytes
160
            }
161
        };
162
163
0
        for block in body.chunks(4) {
164
0
            if block.len() == 4 {
165
0
                self.state
166
0
                    .process_block(unsafe { &*(block.as_ptr() as *const _) });
167
0
            } else {
168
0
                self.push(block);
169
0
            }
170
        }
171
172
        // XXX is this faster?
173
        // for block in body.exact_chunks(4) {
174
        //     self.state
175
        //         .process_block(unsafe { &*(block.as_ptr() as *const _) });
176
        // }
177
178
        // let tail = body.split_at(body.len() / 4 * 4).1;
179
180
        // self.push(tail);
181
0
    }
182
183
    #[inline]
184
0
    fn finish(&self) -> u64 {
185
0
        self.finish32().into()
186
0
    }
187
}
188
189
const C1: u32 = 0xcc9e2d51;
190
const C2: u32 = 0x1b873593;
191
const R1: u32 = 15;
192
193
impl State {
194
0
    fn process_block(&mut self, block: &MaybeUninit<[u8; 4]>) {
195
0
        self.0 ^= pre_mix(LE::read_u32(unsafe { block.assume_init_ref() }));
196
0
        self.0 = self.0.rotate_left(13);
197
0
        self.0 = 5u32.wrapping_mul(self.0).wrapping_add(0xe6546b64);
198
0
    }
199
}
200
201
0
fn pre_mix(mut block: u32) -> u32 {
202
0
    block = block.wrapping_mul(C1);
203
0
    block = block.rotate_left(R1);
204
0
    block = block.wrapping_mul(C2);
205
0
    block
206
0
}