]> git.lizzy.rs Git - rust.git/blob - src/librustc_macros/src/hash_stable.rs
Rollup merge of #68469 - ollie27:skip_count, r=sfackler
[rust.git] / src / librustc_macros / src / hash_stable.rs
1 use proc_macro2::{self, Ident};
2 use quote::quote;
3 use syn::{self, parse_quote, Meta, NestedMeta};
4 use synstructure;
5
6 struct Attributes {
7     ignore: bool,
8     project: Option<Ident>,
9 }
10
11 fn parse_attributes(field: &syn::Field) -> Attributes {
12     let mut attrs = Attributes { ignore: false, project: None };
13     for attr in &field.attrs {
14         if let Ok(meta) = attr.parse_meta() {
15             if !meta.path().is_ident("stable_hasher") {
16                 continue;
17             }
18             let mut any_attr = false;
19             if let Meta::List(list) = meta {
20                 for nested in list.nested.iter() {
21                     if let NestedMeta::Meta(meta) = nested {
22                         if meta.path().is_ident("ignore") {
23                             attrs.ignore = true;
24                             any_attr = true;
25                         }
26                         if meta.path().is_ident("project") {
27                             if let Meta::List(list) = meta {
28                                 if let Some(nested) = list.nested.iter().next() {
29                                     if let NestedMeta::Meta(meta) = nested {
30                                         attrs.project = meta.path().get_ident().cloned();
31                                         any_attr = true;
32                                     }
33                                 }
34                             }
35                         }
36                     }
37                 }
38             }
39             if !any_attr {
40                 panic!("error parsing stable_hasher");
41             }
42         }
43     }
44     attrs
45 }
46
47 pub fn hash_stable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
48     let generic: syn::GenericParam = parse_quote!(__CTX);
49     s.add_bounds(synstructure::AddBounds::Generics);
50     s.add_impl_generic(generic);
51     s.add_where_predicate(parse_quote! { __CTX: crate::HashStableContext });
52     let body = s.each(|bi| {
53         let attrs = parse_attributes(bi.ast());
54         if attrs.ignore {
55             quote! {}
56         } else if let Some(project) = attrs.project {
57             quote! {
58                 &#bi.#project.hash_stable(__hcx, __hasher);
59             }
60         } else {
61             quote! {
62                 #bi.hash_stable(__hcx, __hasher);
63             }
64         }
65     });
66
67     let discriminant = match s.ast().data {
68         syn::Data::Enum(_) => quote! {
69             ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
70         },
71         syn::Data::Struct(_) => quote! {},
72         syn::Data::Union(_) => panic!("cannot derive on union"),
73     };
74
75     s.bound_impl(
76         quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>),
77         quote! {
78             fn hash_stable(
79                 &self,
80                 __hcx: &mut __CTX,
81                 __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
82                 #discriminant
83                 match *self { #body }
84             }
85         },
86     )
87 }
88
89 pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
90     let generic: syn::GenericParam = parse_quote!('__ctx);
91     s.add_bounds(synstructure::AddBounds::Generics);
92     s.add_impl_generic(generic);
93     let body = s.each(|bi| {
94         let attrs = parse_attributes(bi.ast());
95         if attrs.ignore {
96             quote! {}
97         } else if let Some(project) = attrs.project {
98             quote! {
99                 &#bi.#project.hash_stable(__hcx, __hasher);
100             }
101         } else {
102             quote! {
103                 #bi.hash_stable(__hcx, __hasher);
104             }
105         }
106     });
107
108     let discriminant = match s.ast().data {
109         syn::Data::Enum(_) => quote! {
110             ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
111         },
112         syn::Data::Struct(_) => quote! {},
113         syn::Data::Union(_) => panic!("cannot derive on union"),
114     };
115
116     s.bound_impl(
117         quote!(
118             ::rustc_data_structures::stable_hasher::HashStable<
119                 ::rustc::ich::StableHashingContext<'__ctx>,
120             >
121         ),
122         quote! {
123             fn hash_stable(
124                 &self,
125                 __hcx: &mut ::rustc::ich::StableHashingContext<'__ctx>,
126                 __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
127                 #discriminant
128                 match *self { #body }
129             }
130         },
131     )
132 }