1#![no_std]
2extern crate libc;
3#[cfg(test)]
4#[macro_use]
5extern crate std;
6
7use core::mem::size_of;
8use core::ops::Deref;
9use core::ptr::read_unaligned;
10pub use libc::c_char;
11
12#[repr(C)]
13#[derive(Debug, PartialEq)]
14pub struct Hash128(pub u64, pub u64);
15
16impl Hash128 {
17 #[cfg(int128)]
18 #[inline(always)]
19 fn to_u128(self) -> u128 {
20 (self.0 as u128) << 64 | self.1 as u128
21 }
22}
23
24impl Deref for Hash128 {
25 type Target = [u8; 16];
26 #[inline]
27 fn deref(&self) -> &Self::Target {
28 unsafe { &*(self as *const Hash128 as *const [u8; 16]) }
29 }
30}
31
32#[allow(clippy::cast_ptr_alignment)]
33#[inline]
34pub fn fetch64(src: &[u8]) -> u64 {
35 debug_assert!(src.len() >= size_of::<u64>());
36 let ptr = src.as_ptr() as *const u64;
37 unsafe { read_unaligned(ptr) }
38}
39
40#[allow(clippy::cast_ptr_alignment)]
41#[inline]
42pub fn fetch128(src: &[u8]) -> u128 {
43 debug_assert!(src.len() >= size_of::<u128>());
44 let ptr = src.as_ptr() as *const u128;
45 unsafe { read_unaligned(ptr) }
46}
47
48#[cfg(not(int128))]
49impl PartialEq<&[u8]> for Hash128 {
50 fn eq(&self, other: &&[u8]) -> bool {
51 other.len() == 16 && (self.0 == fetch64(*other)) && (self.1 == fetch64(&other[8..]))
52 }
53}
54
55#[cfg(int128)]
56impl PartialEq<&[u8]> for Pair {
57 fn eq(&self, other: &&[u8]) -> bool {
58 (other.len() == 16) && (self.to_u128() == fetch128(other))
59 }
60}
61
62extern "C" {
63 pub fn _CityHash128(s: *const c_char, len: usize) -> Hash128;
64 pub fn _CityHash64(s: *const c_char, len: usize) -> u64;
65 pub fn _CityMurmur(s: *const c_char, len: usize, seed: Hash128) -> Hash128;
66}
67
68#[cfg(test)]
69extern "C" {
70 }
74
75pub fn city_hash_128(source: &[u8]) -> Hash128 {
76 unsafe { _CityHash128(source.as_ptr() as *const c_char, source.len()) }
77}
78
79pub fn city_hash_64(source: &[u8]) -> u64 {
80 unsafe { _CityHash64(source.as_ptr() as *const c_char, source.len()) }
81}
82
83#[cfg(test)]
84mod test {
85 use crate::*;
86
87 #[test]
88 fn test_city_hash_128() {
89 assert_eq!(
90 city_hash_128(b"abc"),
91 [
92 0xfe, 0x48, 0x77, 0x57, 0x95, 0xf1, 0x0f, 0x90, 0x7e, 0x0d, 0xb2, 0x55, 0x63, 0x17,
93 0xa9, 0x13
94 ]
95 .as_ref()
96 );
97 assert_ne!(
98 city_hash_128(b"abc"),
99 [
100 0x00, 0x48, 0x77, 0x57, 0x95, 0xf1, 0x0f, 0x90, 0x7e, 0x0d, 0xb2, 0x55, 0x63, 0x17,
101 0xa9, 0x13
102 ]
103 .as_ref()
104 );
105 assert_eq!(
106 city_hash_128(b"01234567890abc"),
107 [
108 0x36, 0x20, 0xe9, 0x1b, 0x54, 0x23, 0x04, 0xbe, 0x2d, 0xc7, 0x32, 0x8d, 0x93, 0xd2,
109 0x3b, 0x89
110 ]
111 .as_ref()
112 );
113 assert_eq!(
114 city_hash_128(b"01234567890123456789012345678901234567890123456789012345678901234"),
115 [
116 0x24, 0xd7, 0xd5, 0xdc, 0x8e, 0xb6, 0x85, 0xb2, 0xb1, 0xd9, 0x78, 0x15, 0xa2, 0x2a,
117 0xb0, 0x3d
118 ]
119 .as_ref()
120 );
121 assert_eq!(
122 city_hash_128(b""),
123 [
124 0x2b, 0x9a, 0xc0, 0x64, 0xfc, 0x9d, 0xf0, 0x3d, 0x29, 0x1e, 0xe5, 0x92, 0xc3, 0x40,
125 0xb5, 0x3c
126 ]
127 .as_ref()
128 );
129
130 assert_ne!(
131 city_hash_128(b"abc"),
132 [
133 0xfe, 0x48, 0x77, 0x57, 0x95, 0xf1, 0x0f, 0x90, 0x7e, 0x0d, 0xb2, 0x55, 0x63, 0x17,
134 0xa9, 0x11
135 ]
136 .as_ref()
137 );
138 }
139}