1 use std::collections::hash_map;
2 use std::fmt::{self, Display, Write};
3 use std::hash::{Hash, Hasher};
4 use syn::Ident;
5
6 // 8-character symbol hash consisting of a-zA-Z0-9. We use 8 character because
7 // Mach-O section specifiers are restricted to at most 16 characters (see
8 // https://github.com/dtolnay/linkme/issues/35) and we leave room for a
9 // linkme-specific prefix.
10 pub(crate) struct Symbol(u64);
11
hash(ident: &Ident) -> Symbol12 pub(crate) fn hash(ident: &Ident) -> Symbol {
13 let mut hasher = hash_map::DefaultHasher::new();
14 ident.hash(&mut hasher);
15 Symbol(hasher.finish())
16 }
17
18 impl Display for Symbol {
fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result19 fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
20 // log(62^8)/log(2) is 47.6 so we have enough bits in the 64-bit
21 // standard library hash to produce a good distribution over 8 digits
22 // from a 62-character alphabet.
23 let mut remainder = self.0;
24 for _ in 0..8 {
25 let digit = (remainder % 62) as u8;
26 remainder /= 62;
27 formatter.write_char(match digit {
28 0..=25 => b'a' + digit,
29 26..=51 => b'A' + digit - 26,
30 52..=61 => b'0' + digit - 52,
31 _ => unreachable!(),
32 } as char)?;
33 }
34 Ok(())
35 }
36 }
37
38 #[test]
test_hash()39 fn test_hash() {
40 let ident = Ident::new("EXAMPLE", proc_macro2::Span::call_site());
41 assert_eq!(hash(&ident).to_string(), "0GPSzIoo");
42 }
43