farmhash_sys/
lib.rs

1#![allow(non_upper_case_globals)]
2#![allow(non_camel_case_types)]
3#![allow(non_snake_case)]
4
5include!(concat!(env!("OUT_DIR"), "/bindings.rs"));
6
7use std::os::raw::c_char;
8
9/// Compute FarmHash32 for a byte slice
10pub fn farm_hash_32(bytes: &[u8]) -> u32 {
11    unsafe { farmhash_hash32(bytes.as_ptr() as *const c_char, bytes.len()) }
12}
13
14/// Compute FarmHash32 for a byte slice with a seed
15pub fn farm_hash_32_with_seed(bytes: &[u8], seed: u32) -> u32 {
16    unsafe { farmhash_hash32_with_seed(bytes.as_ptr() as *const c_char, bytes.len(), seed) }
17}
18
19/// Compute FarmHash64 for a byte slice
20pub fn farm_hash_64(bytes: &[u8]) -> u64 {
21    unsafe { farmhash_hash64(bytes.as_ptr() as *const c_char, bytes.len()) }
22}
23
24/// Compute FarmHash64 for a byte slice with a seed
25pub fn farm_hash_64_with_seed(bytes: &[u8], seed: u64) -> u64 {
26    unsafe { farmhash_hash64_with_seed(bytes.as_ptr() as *const c_char, bytes.len(), seed) }
27}
28
29/// Compute FarmHash64 for a byte slice with two seeds
30pub fn farm_hash_64_with_seeds(bytes: &[u8], seed0: u64, seed1: u64) -> u64 {
31    unsafe {
32        farmhash_hash64_with_seeds(bytes.as_ptr() as *const c_char, bytes.len(), seed0, seed1)
33    }
34}
35
36/// Compute FarmHash128 (fingerprint) for a byte slice
37pub fn farm_hash_128(bytes: &[u8]) -> (u64, u64) {
38    unsafe {
39        let result = farmhash_fingerprint128(bytes.as_ptr() as *const c_char, bytes.len());
40        (result.low, result.high)
41    }
42}
43
44/// Compute FarmHash128 (fingerprint) for a byte slice with a seed
45pub fn farm_hash_128_with_seed(bytes: &[u8], seed: u64) -> (u64, u64) {
46    // Implement using hash64_with_seed for each half
47    let low = farm_hash_64_with_seed(bytes, seed);
48    let high = farm_hash_64_with_seed(bytes, seed.wrapping_add(1));
49    (low, high)
50}
51
52use std::hash::Hasher;
53
54/// Hasher implementation for FarmHash
55pub struct FarmHashHasher {
56    buffer: Vec<u8>,
57    seed: Option<u64>,
58}
59
60impl FarmHashHasher {
61    /// Create a new FarmHashHasher with no seed
62    pub fn new() -> Self {
63        Self {
64            buffer: Vec::new(),
65            seed: None,
66        }
67    }
68
69    /// Create a new FarmHashHasher with the specified seed
70    pub fn with_seed(seed: u64) -> Self {
71        Self {
72            buffer: Vec::new(),
73            seed: Some(seed),
74        }
75    }
76}
77
78impl Default for FarmHashHasher {
79    fn default() -> Self {
80        Self::new()
81    }
82}
83
84impl Hasher for FarmHashHasher {
85    fn finish(&self) -> u64 {
86        if self.seed.is_some() {
87            farm_hash_64_with_seed(&self.buffer, self.seed.unwrap())
88        } else {
89            farm_hash_64(&self.buffer)
90        }
91    }
92
93    fn write(&mut self, bytes: &[u8]) {
94        // FarmHash hasher does not support incremental hashing, so we accumulate the bytes
95        // and hash the entire buffer at once
96        self.buffer.extend_from_slice(bytes);
97    }
98}
99
100#[allow(dead_code)]
101/// Default hasher for FarmHash
102type FarmHashHasherDefault = std::hash::BuildHasherDefault<FarmHashHasher>;
103
104// We also provide the original module for backward compatibility or for users who prefer that style
105pub mod farmhash {
106    use super::*;
107
108    /// Hash function for a byte array, returning a 32-bit hash
109    pub fn hash32(bytes: &[u8]) -> u32 {
110        farm_hash_32(bytes)
111    }
112
113    /// Hash function for a byte array with a 32-bit seed, returning a 32-bit hash
114    pub fn hash32_with_seed(bytes: &[u8], seed: u32) -> u32 {
115        farm_hash_32_with_seed(bytes, seed)
116    }
117
118    /// Hash function for a byte array, returning a 64-bit hash
119    pub fn hash64(bytes: &[u8]) -> u64 {
120        farm_hash_64(bytes)
121    }
122
123    /// Hash function for a byte array with a 64-bit seed, returning a 64-bit hash
124    pub fn hash64_with_seed(bytes: &[u8], seed: u64) -> u64 {
125        farm_hash_64_with_seed(bytes, seed)
126    }
127
128    /// Hash function for a byte array with two 64-bit seeds, returning a 64-bit hash
129    pub fn hash64_with_seeds(bytes: &[u8], seed0: u64, seed1: u64) -> u64 {
130        farm_hash_64_with_seeds(bytes, seed0, seed1)
131    }
132
133    /// Fingerprint function for a byte array, returning a 128-bit fingerprint
134    pub fn fingerprint128(bytes: &[u8]) -> (u64, u64) {
135        farm_hash_128(bytes)
136    }
137
138    /// Fingerprint function for a byte array with a seed, returning a 128-bit fingerprint
139    pub fn fingerprint128_with_seed(bytes: &[u8], seed: u64) -> (u64, u64) {
140        farm_hash_128_with_seed(bytes, seed)
141    }
142}
143
144#[cfg(test)]
145mod tests {
146    use super::*;
147
148    #[test]
149    fn test_farm_hash_32() {
150        let data = b"hello world";
151        let hash = farm_hash_32(data);
152        // Test consistency
153        assert_eq!(hash, farm_hash_32(data));
154        assert_ne!(hash, 0);
155    }
156
157    #[test]
158    fn test_farm_hash_32_with_seed() {
159        let data = b"hello world";
160        let seed = 123456789;
161        let hash = farm_hash_32_with_seed(data, seed);
162        // Test consistency
163        assert_eq!(hash, farm_hash_32_with_seed(data, seed));
164        // Test that different seeds produce different hashes
165        assert_ne!(hash, farm_hash_32_with_seed(data, seed + 1));
166    }
167
168    #[test]
169    fn test_farm_hash_64() {
170        let data = b"hello world";
171        let hash = farm_hash_64(data);
172        // Test consistency
173        assert_eq!(hash, farm_hash_64(data));
174        assert_ne!(hash, 0);
175    }
176
177    #[test]
178    fn test_farm_hash_64_with_seed() {
179        let data = b"hello world";
180        let seed = 123456789;
181        let hash = farm_hash_64_with_seed(data, seed);
182        // Test consistency
183        assert_eq!(hash, farm_hash_64_with_seed(data, seed));
184        // Test that different seeds produce different hashes
185        assert_ne!(hash, farm_hash_64_with_seed(data, seed + 1));
186    }
187
188    #[test]
189    fn test_farm_hash_64_with_seeds() {
190        let data = b"hello world";
191        let seed0 = 123456789;
192        let seed1 = 987654321;
193        let hash = farm_hash_64_with_seeds(data, seed0, seed1);
194        // Test consistency
195        assert_eq!(hash, farm_hash_64_with_seeds(data, seed0, seed1));
196        // Test that different seeds produce different hashes
197        assert_ne!(hash, farm_hash_64_with_seeds(data, seed0 + 1, seed1));
198    }
199
200    #[test]
201    fn test_farm_hash_128() {
202        let data = b"hello world";
203        let (low, high) = farm_hash_128(data);
204        // Test consistency
205        let (low2, high2) = farm_hash_128(data);
206        assert_eq!((low, high), (low2, high2));
207        // Simple verification that we get non-zero values
208        assert!(low != 0 || high != 0);
209    }
210
211    #[test]
212    fn test_farm_hash_128_with_seed() {
213        let data = b"hello world";
214        let seed = 123456789;
215        let (low1, high1) = farm_hash_128_with_seed(data, seed);
216        // Test consistency
217        assert_eq!(farm_hash_128_with_seed(data, seed), (low1, high1));
218        // Different seeds should produce different fingerprints
219        let (low2, high2) = farm_hash_128_with_seed(data, seed + 1);
220        assert!(low1 != low2 || high1 != high2);
221    }
222
223    #[test]
224    fn test_farmhash_module_compatibility() {
225        let data = b"hello world";
226        // Verify that the farmhash module functions match the top-level functions
227        assert_eq!(farmhash::hash32(data), farm_hash_32(data));
228        assert_eq!(farmhash::hash64(data), farm_hash_64(data));
229        assert_eq!(farmhash::fingerprint128(data), farm_hash_128(data));
230    }
231
232    #[test]
233    fn test_farm_hash_hasher() {
234        let data = b"hello world";
235        let mut hasher = FarmHashHasher::new();
236        hasher.write(data);
237        let hash = hasher.finish();
238        // Test consistency with direct call
239        assert_eq!(hash, farm_hash_64(data));
240    }
241
242    #[test]
243    fn test_farm_hash_hasher_with_seed() {
244        let data = b"hello world";
245        let seed = 123456789;
246        let mut hasher = FarmHashHasher::with_seed(seed);
247        hasher.write(data);
248        let hash = hasher.finish();
249        // Test consistency with direct call
250        assert_eq!(hash, farm_hash_64_with_seed(data, seed));
251    }
252}