]> git.proxmox.com Git - rustc.git/blob - src/librustc_macros/src/hash_stable.rs
New upstream version 1.41.1+dfsg1
[rustc.git] / src / librustc_macros / src / hash_stable.rs
1 use synstructure;
2 use syn::{self, Meta, NestedMeta, parse_quote};
3 use proc_macro2::{self, Ident};
4 use quote::quote;
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 {
13 ignore: false,
14 project: None,
15 };
16 for attr in &field.attrs {
17 if let Ok(meta) = attr.parse_meta() {
18 if !meta.path().is_ident("stable_hasher") {
19 continue;
20 }
21 let mut any_attr = false;
22 if let Meta::List(list) = meta {
23 for nested in list.nested.iter() {
24 if let NestedMeta::Meta(meta) = nested {
25 if meta.path().is_ident("ignore") {
26 attrs.ignore = true;
27 any_attr = true;
28 }
29 if meta.path().is_ident("project") {
30 if let Meta::List(list) = meta {
31 if let Some(nested) = list.nested.iter().next() {
32 if let NestedMeta::Meta(meta) = nested {
33 attrs.project = meta.path().get_ident().cloned();
34 any_attr = true;
35 }
36 }
37 }
38 }
39 }
40 }
41 }
42 if !any_attr {
43 panic!("error parsing stable_hasher");
44 }
45 }
46 }
47 attrs
48 }
49
50 pub fn hash_stable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
51 let generic: syn::GenericParam = parse_quote!(__CTX);
52 s.add_bounds(synstructure::AddBounds::Generics);
53 s.add_impl_generic(generic);
54 s.add_where_predicate(parse_quote!{ __CTX: crate::HashStableContext });
55 let body = s.each(|bi| {
56 let attrs = parse_attributes(bi.ast());
57 if attrs.ignore {
58 quote!{}
59 } else if let Some(project) = attrs.project {
60 quote!{
61 &#bi.#project.hash_stable(__hcx, __hasher);
62 }
63 } else {
64 quote!{
65 #bi.hash_stable(__hcx, __hasher);
66 }
67 }
68 });
69
70 let discriminant = match s.ast().data {
71 syn::Data::Enum(_) => quote! {
72 ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
73 },
74 syn::Data::Struct(_) => quote! {},
75 syn::Data::Union(_) => panic!("cannot derive on union"),
76 };
77
78 s.bound_impl(quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>), quote!{
79 fn hash_stable(
80 &self,
81 __hcx: &mut __CTX,
82 __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
83 #discriminant
84 match *self { #body }
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(quote!(::rustc_data_structures::stable_hasher::HashStable
117 <::rustc::ich::StableHashingContext<'__ctx>>), quote!{
118 fn hash_stable(
119 &self,
120 __hcx: &mut ::rustc::ich::StableHashingContext<'__ctx>,
121 __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
122 #discriminant
123 match *self { #body }
124 }
125 })
126 }