1#![doc = include_str!("../README.md")]
2
3use proc_macro::TokenStream as TokenStream1;
4use proc_macro2::{Ident, TokenStream};
5use quote::{format_ident, quote, ToTokens};
6use syn::{
7 parse::{Parse, ParseStream},
8 parse_macro_input,
9 punctuated::Punctuated,
10 ConstParam, Data, DeriveInput, Error, Fields, GenericArgument, Generics, Index, Lifetime,
11 LifetimeParam, Token, TypeParam, WhereClause,
12};
13
14fn crate_root() -> TokenStream {
15 quote!(::anyhash)
16}
17
18#[proc_macro_derive(Hash)]
19#[allow(non_snake_case)]
20pub fn derive_anyhash(input: TokenStream1) -> TokenStream1 {
21 let root = crate_root();
22 let hash = quote!(#root::Hash);
23 let hasher_write = quote!(#root::HasherWrite);
24
25 let mut input = parse_macro_input!(input as DeriveInput);
26 let ident = input.ident;
27
28 let mut tokens = TokenStream::new();
29 let mut types = Vec::new();
30
31 match input.data {
32 Data::Struct(x) => match x.fields {
33 Fields::Named(x) => {
34 let fields = x.named.iter().map(|x| {
35 types.push(x.ty.clone());
36 x.ident.as_ref().unwrap()
37 });
38 quote! {
39 #( #hash::hash(&self.#fields, state); )*
40 }
41 .to_tokens(&mut tokens)
42 }
43
44 Fields::Unnamed(x) => {
45 let fields = x.unnamed.iter().enumerate().map(|(i, x)| {
46 types.push(x.ty.clone());
47 Index::from(i)
48 });
49 quote! {
50 #( #hash::hash(&self.#fields, state); )*
51 }
52 .to_tokens(&mut tokens)
53 }
54
55 Fields::Unit => (),
56 },
57
58 Data::Enum(x) => {
59 let mut variant_tokens = TokenStream::new();
60
61 for x in x.variants.iter() {
62 let var = &x.ident;
63
64 match &x.fields {
65 Fields::Named(x) => {
66 let fields: Vec<_> = x
67 .named
68 .iter()
69 .map(|x| {
70 types.push(x.ty.clone());
71 x.ident.as_ref().unwrap()
72 })
73 .collect();
74 quote! {
75 Self::#var { #(#fields),* } => { #( #hash::hash(#fields, state); )* }
76 }
77 .to_tokens(&mut variant_tokens);
78 }
79
80 Fields::Unnamed(x) => {
81 let fields: Vec<_> = x
82 .unnamed
83 .iter()
84 .enumerate()
85 .map(|(i, x)| {
86 types.push(x.ty.clone());
87 format_ident!("_{i}")
88 })
89 .collect();
90 quote! {
91 Self::#var(#(#fields),*) => { #( #hash::hash(#fields, state); )* }
92 }
93 .to_tokens(&mut variant_tokens);
94 }
95
96 Fields::Unit => quote! {
97 Self::#var => (),
98 }
99 .to_tokens(&mut variant_tokens),
100 }
101 }
102
103 quote! {
104 #hash::hash(&core::mem::discriminant(self), state);
105 match self {
106 #variant_tokens
107 }
108 }
109 .to_tokens(&mut tokens);
110 }
111
112 Data::Union(_) => {
113 return Error::new(ident.span(), "can't derive `Hash` for union")
114 .to_compile_error()
115 .into()
116 }
117 }
118
119 input.generics.make_where_clause();
120 let wc = input.generics.where_clause.as_mut().unwrap();
121 let where_ = fix_where(Some(wc));
122 let SplitGenerics {
123 lti,
124 ltt,
125 tpi,
126 tpt,
127 cpi,
128 cpt,
129 wc,
130 } = split_generics(&input.generics);
131 quote! {
132 impl<#(#lti,)* #(#tpi,)* #(#cpi,)*> #hash for #ident<#(#ltt,)* #(#tpt,)* #(#cpt),*> #where_ #wc
133 #( #types: #hash ),*
134 {
135 #[inline]
136 fn hash<H: #hasher_write>(&self, state: &mut H) {
137 #tokens
138 }
139 }
140 }
141 .into()
142}
143
144#[proc_macro]
145pub fn impl_core_hash(input: TokenStream1) -> TokenStream1 {
146 let root = crate_root();
147 let hash = quote!(#root::Hash);
148
149 let input = parse_macro_input!(input as IdentsWithGenerics);
150 let mut output = TokenStream::new();
151
152 for IdentWithGenerics {
153 impl_generics,
154 ident,
155 use_generics,
156 mut where_clause,
157 } in input.punctuated
158 {
159 let where_ = fix_where(where_clause.as_mut());
160 quote! {
161 impl #impl_generics ::core::hash::Hash for #ident #use_generics #where_ #where_clause
162 Self: #hash,
163 {
164 #[inline]
165 fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
166 <Self as #hash>::hash(
167 self, &mut #root::internal::WrapCoreForHasherU64::new(state)
168 )
169 }
170 }
171 }
172 .to_tokens(&mut output);
173 }
174 output.into()
175}
176
177#[proc_macro]
178pub fn impl_core_hasher(input: TokenStream1) -> TokenStream1 {
179 let root = crate_root();
180 let hasher_t = quote!(#root::Hasher);
181 let hasher_write = quote!(#root::HasherWrite);
182
183 let input = parse_macro_input!(input as IdentsWithGenerics);
184 let mut output = TokenStream::new();
185
186 for IdentWithGenerics {
187 impl_generics,
188 ident,
189 use_generics,
190 mut where_clause,
191 } in input.punctuated
192 {
193 let mut body = quote! {
194 #[inline(always)]
195 fn finish(&self) -> u64 {
196 <Self as #hasher_t::<u64>>::finish(self)
197 }
198
199 #[inline(always)]
200 fn write(&mut self, bytes: &[u8]) {
201 <Self as #hasher_write>::write(self, bytes)
202 }
203 };
204
205 for t in [
206 quote!(u8),
207 quote!(u16),
208 quote!(u32),
209 quote!(u64),
210 quote!(u128),
211 quote!(usize),
212 quote!(i8),
213 quote!(i16),
214 quote!(i32),
215 quote!(i64),
216 quote!(i128),
217 quote!(isize),
218 ] {
219 let wid = format_ident!("write_{t}");
220 quote! {
221 #[inline(always)]
222 fn #wid(&mut self, i: #t) {
223 <Self as #hasher_write>::#wid(self, i);
224 }
225 }
226 .to_tokens(&mut body);
227 }
228
229 let where_ = fix_where(where_clause.as_mut());
230 quote! {
231 impl #impl_generics ::core::hash::Hasher for #ident #use_generics #where_ #where_clause
232 Self: #hasher_t<u64>,
233 {
234 #body
235 }
236 }
237 .to_tokens(&mut output);
238 }
239 output.into()
240}
241
242#[proc_macro]
243pub fn impl_core_build_hasher(input: TokenStream1) -> TokenStream1 {
244 let root = crate_root();
245 let build_hasher_t = quote!(#root::BuildHasher);
246
247 let input = parse_macro_input!(input as IdentsWithGenerics);
248 let mut output = TokenStream::new();
249
250 for IdentWithGenerics {
251 impl_generics,
252 ident,
253 use_generics,
254 mut where_clause,
255 } in input.punctuated
256 {
257 let where_ = fix_where(where_clause.as_mut());
258 quote! {
259 impl #impl_generics ::core::hash::BuildHasher for #ident #use_generics #where_ #where_clause
260 Self: #build_hasher_t<u64>,
261 {
262 type Hasher = #root::internal::WrapHasherU64ForCore<<Self as #build_hasher_t::<u64>>::Hasher>;
263
264 #[inline]
265 fn build_hasher(&self) -> Self::Hasher {
266 Self::Hasher::new(<Self as #build_hasher_t::<u64>>::build_hasher(self))
267 }
268 }
269 }
270 .to_tokens(&mut output);
271 }
272 output.into()
273}
274
275#[proc_macro]
276#[allow(non_snake_case)]
277pub fn impl_hash(input: TokenStream1) -> TokenStream1 {
278 let root = crate_root();
279 let hash = quote!(#root::Hash);
280 let hasher_write = quote!(#root::HasherWrite);
281
282 let input = parse_macro_input!(input as IdentsWithGenerics);
283 let mut output = TokenStream::new();
284
285 for IdentWithGenerics {
286 impl_generics,
287 ident,
288 use_generics,
289 mut where_clause,
290 } in input.punctuated
291 {
292 let SplitGenerics {
293 lti,
294 ltt: _,
295 tpi,
296 tpt: _,
297 cpi,
298 cpt: _,
299 wc: _,
300 } = split_generics(&impl_generics);
301 let where_ = fix_where(where_clause.as_mut());
302
303 quote! {
304 impl<#(#lti,)* #(#tpi,)* #(#cpi,)*> #hash for #ident #use_generics #where_ #where_clause {
305 #[inline]
306 fn hash<H: #hasher_write>(&self, state: &mut H) {
307 <Self as ::core::hash::Hash>::hash(
308 self, &mut #root::internal::WrapHasherWriteForCore::new(state)
309 )
310 }
311 }
312 }
313 .to_tokens(&mut output);
314 }
315 output.into()
316}
317
318fn fix_where(wc: Option<&mut WhereClause>) -> Option<Token![where]> {
319 if let Some(wc) = wc {
320 if wc.predicates.is_empty() {
321 Some(wc.where_token)
322 } else {
323 if !wc.predicates.trailing_punct() {
324 wc.predicates.push_punct(<Token![,]>::default());
325 }
326 None
327 }
328 } else {
329 Some(<Token![where]>::default())
330 }
331}
332
333struct SplitGenerics<
334 'a,
335 LTI: Iterator<Item = &'a LifetimeParam>,
336 LTT: Iterator<Item = &'a Lifetime>,
337 TPI: Iterator<Item = &'a TypeParam>,
338 TPT: Iterator<Item = &'a Ident>,
339 CPI: Iterator<Item = &'a ConstParam>,
340 CPT: Iterator<Item = &'a Ident>,
341> {
342 lti: LTI,
343 ltt: LTT,
344 tpi: TPI,
345 tpt: TPT,
346 cpi: CPI,
347 cpt: CPT,
348 wc: &'a Option<WhereClause>,
349}
350
351fn split_generics(
352 generics: &Generics,
353) -> SplitGenerics<
354 impl Iterator<Item = &LifetimeParam>,
355 impl Iterator<Item = &Lifetime>,
356 impl Iterator<Item = &TypeParam>,
357 impl Iterator<Item = &Ident>,
358 impl Iterator<Item = &ConstParam>,
359 impl Iterator<Item = &Ident>,
360> {
361 SplitGenerics {
362 lti: generics.lifetimes(),
363 ltt: generics.lifetimes().map(|l| &l.lifetime),
364 tpi: generics.type_params(),
365 tpt: generics.type_params().map(|t| &t.ident),
366 cpi: generics.const_params(),
367 cpt: generics.const_params().map(|c| &c.ident),
368 wc: &generics.where_clause,
369 }
370}
371
372struct IdentsWithGenerics {
373 punctuated: Punctuated<IdentWithGenerics, Token![;]>,
374}
375
376impl Parse for IdentsWithGenerics {
377 fn parse(input: ParseStream) -> syn::Result<Self> {
378 let punctuated = Punctuated::parse_terminated(input)?;
379 Ok(Self { punctuated })
380 }
381}
382
383struct IdentWithGenerics {
384 impl_generics: Generics,
385 ident: Ident,
386 use_generics: Option<GenericArguments>,
387 where_clause: Option<WhereClause>,
388}
389
390impl Parse for IdentWithGenerics {
391 fn parse(input: ParseStream) -> syn::Result<Self> {
392 let impl_generics = if Option::<Token![impl]>::parse(input)?.is_some() {
393 Generics::parse(input)?
394 } else {
395 Generics::default()
396 };
397 let ident = Ident::parse(input)?;
398 let use_generics = if input.peek(Token![<]) {
399 Some(GenericArguments::parse(input)?)
400 } else {
401 None
402 };
403 let where_clause = Option::<WhereClause>::parse(input)?;
404
405 Ok(Self {
406 impl_generics,
407 ident,
408 use_generics,
409 where_clause,
410 })
411 }
412}
413
414struct GenericArguments {
415 lt_token: Token![<],
416 args: Punctuated<GenericArgument, Token![,]>,
417 rt_token: Token![>],
418}
419
420impl Parse for GenericArguments {
421 fn parse(input: ParseStream) -> syn::Result<Self> {
422 let lt_token = <Token![<]>::parse(input)?;
423
424 let mut args = Punctuated::new();
425 while let Ok(arg) = GenericArgument::parse(input) {
426 args.push(arg);
427 if let Ok(comma) = <Token![,]>::parse(input) {
428 args.push_punct(comma);
429 } else {
430 break;
431 }
432 }
433
434 let rt_token = <Token![>]>::parse(input)?;
435
436 Ok(Self {
437 lt_token,
438 args,
439 rt_token,
440 })
441 }
442}
443
444impl ToTokens for GenericArguments {
445 fn to_tokens(&self, tokens: &mut TokenStream) {
446 self.lt_token.to_tokens(tokens);
447 self.args.to_tokens(tokens);
448 self.rt_token.to_tokens(tokens);
449 }
450}