rustc_macros/
hash_stable.rs1use proc_macro2::Ident;
2use quote::quote;
3
4struct Attributes {
5 ignore: bool,
6 project: Option<Ident>,
7}
8
9fn parse_attributes(field: &syn::Field) -> Attributes {
10 let mut attrs = Attributes { ignore: false, project: None };
11 for attr in &field.attrs {
12 let meta = &attr.meta;
13 if !meta.path().is_ident("stable_hasher") {
14 continue;
15 }
16 let mut any_attr = false;
17 let _ = attr.parse_nested_meta(|nested| {
18 if nested.path.is_ident("ignore") {
19 attrs.ignore = true;
20 any_attr = true;
21 }
22 if nested.path.is_ident("project") {
23 let _ = nested.parse_nested_meta(|meta| {
24 if attrs.project.is_none() {
25 attrs.project = meta.path.get_ident().cloned();
26 }
27 any_attr = true;
28 Ok(())
29 });
30 }
31 Ok(())
32 });
33 if !any_attr {
34 panic!("error parsing stable_hasher");
35 }
36 }
37 attrs
38}
39
40pub(crate) fn hash_stable_derive(s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
41 hash_stable_derive_with_mode(s, HashStableMode::Normal)
42}
43
44pub(crate) fn hash_stable_no_context_derive(
45 s: synstructure::Structure<'_>,
46) -> proc_macro2::TokenStream {
47 hash_stable_derive_with_mode(s, HashStableMode::NoContext)
48}
49
50enum HashStableMode {
51 Normal,
55
56 NoContext,
65}
66
67fn hash_stable_derive_with_mode(
68 mut s: synstructure::Structure<'_>,
69 mode: HashStableMode,
70) -> proc_macro2::TokenStream {
71 let add_bounds = match mode {
72 HashStableMode::Normal => synstructure::AddBounds::Generics,
73 HashStableMode::NoContext => synstructure::AddBounds::Fields,
74 };
75
76 s.add_bounds(add_bounds);
77
78 let discriminant = hash_stable_discriminant(&mut s);
79 let body = hash_stable_body(&mut s);
80
81 s.bound_impl(
82 quote!(::rustc_data_structures::stable_hasher::StableHash),
83 quote! {
84 #[inline]
85 fn stable_hash<__Hcx: ::rustc_data_structures::stable_hasher::StableHashCtxt>(
86 &self,
87 __hcx: &mut __Hcx,
88 __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher
89 ) {
90 #discriminant
91 match *self { #body }
92 }
93 },
94 )
95}
96
97fn hash_stable_discriminant(s: &mut synstructure::Structure<'_>) -> proc_macro2::TokenStream {
98 match s.ast().data {
99 syn::Data::Enum(_) => quote! {
100 ::std::mem::discriminant(self).stable_hash(__hcx, __hasher);
101 },
102 syn::Data::Struct(_) => quote! {},
103 syn::Data::Union(_) => panic!("cannot derive on union"),
104 }
105}
106
107fn hash_stable_body(s: &mut synstructure::Structure<'_>) -> proc_macro2::TokenStream {
108 s.each(|bi| {
109 let attrs = parse_attributes(bi.ast());
110 if attrs.ignore {
111 quote! {}
112 } else if let Some(project) = attrs.project {
113 quote! {
114 (&#bi.#project).stable_hash(__hcx, __hasher);
115 }
116 } else {
117 quote! {
118 #bi.stable_hash(__hcx, __hasher);
119 }
120 }
121 })
122}