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