use std::collections::hash_map; use std::fmt::{self, Display, Write}; use std::hash::{Hash, Hasher}; use syn::Ident; // 8-character symbol hash consisting of a-zA-Z0-9. We use 8 character because // Mach-O section specifiers are restricted to at most 16 characters (see // https://github.com/dtolnay/linkme/issues/35) and we leave room for a // linkme-specific prefix. pub(crate) struct Symbol(u64); pub(crate) fn hash(ident: &Ident) -> Symbol { let mut hasher = hash_map::DefaultHasher::new(); ident.hash(&mut hasher); Symbol(hasher.finish()) } impl Display for Symbol { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { // log(62^8)/log(2) is 47.6 so we have enough bits in the 64-bit // standard library hash to produce a good distribution over 8 digits // from a 62-character alphabet. let mut remainder = self.0; for _ in 0..8 { let digit = (remainder % 62) as u8; remainder /= 62; formatter.write_char(match digit { 0..=25 => b'a' + digit, 26..=51 => b'A' + digit - 26, 52..=61 => b'0' + digit - 52, _ => unreachable!(), } as char)?; } Ok(()) } } #[test] fn test_hash() { let ident = Ident::new("EXAMPLE", proc_macro2::Span::call_site()); assert_eq!(hash(&ident).to_string(), "0GPSzIoo"); }