anyhash_macros/
lib.rs

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}