about summary refs log tree commit diff
path: root/compiler/rustc_macros/src/hash_stable.rs
diff options
context:
space:
mode:
Diffstat (limited to 'compiler/rustc_macros/src/hash_stable.rs')
-rw-r--r--compiler/rustc_macros/src/hash_stable.rs131
1 files changed, 131 insertions, 0 deletions
diff --git a/compiler/rustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs
new file mode 100644
index 00000000000..c955c137782
--- /dev/null
+++ b/compiler/rustc_macros/src/hash_stable.rs
@@ -0,0 +1,131 @@
+use proc_macro2::{self, Ident};
+use quote::quote;
+use syn::{self, parse_quote, Meta, NestedMeta};
+
+struct Attributes {
+    ignore: bool,
+    project: Option<Ident>,
+}
+
+fn parse_attributes(field: &syn::Field) -> Attributes {
+    let mut attrs = Attributes { ignore: false, project: None };
+    for attr in &field.attrs {
+        if let Ok(meta) = attr.parse_meta() {
+            if !meta.path().is_ident("stable_hasher") {
+                continue;
+            }
+            let mut any_attr = false;
+            if let Meta::List(list) = meta {
+                for nested in list.nested.iter() {
+                    if let NestedMeta::Meta(meta) = nested {
+                        if meta.path().is_ident("ignore") {
+                            attrs.ignore = true;
+                            any_attr = true;
+                        }
+                        if meta.path().is_ident("project") {
+                            if let Meta::List(list) = meta {
+                                if let Some(nested) = list.nested.iter().next() {
+                                    if let NestedMeta::Meta(meta) = nested {
+                                        attrs.project = meta.path().get_ident().cloned();
+                                        any_attr = true;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            if !any_attr {
+                panic!("error parsing stable_hasher");
+            }
+        }
+    }
+    attrs
+}
+
+pub fn hash_stable_generic_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    let generic: syn::GenericParam = parse_quote!(__CTX);
+    s.add_bounds(synstructure::AddBounds::Generics);
+    s.add_impl_generic(generic);
+    s.add_where_predicate(parse_quote! { __CTX: crate::HashStableContext });
+    let body = s.each(|bi| {
+        let attrs = parse_attributes(bi.ast());
+        if attrs.ignore {
+            quote! {}
+        } else if let Some(project) = attrs.project {
+            quote! {
+                &#bi.#project.hash_stable(__hcx, __hasher);
+            }
+        } else {
+            quote! {
+                #bi.hash_stable(__hcx, __hasher);
+            }
+        }
+    });
+
+    let discriminant = match s.ast().data {
+        syn::Data::Enum(_) => quote! {
+            ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
+        },
+        syn::Data::Struct(_) => quote! {},
+        syn::Data::Union(_) => panic!("cannot derive on union"),
+    };
+
+    s.bound_impl(
+        quote!(::rustc_data_structures::stable_hasher::HashStable<__CTX>),
+        quote! {
+            fn hash_stable(
+                &self,
+                __hcx: &mut __CTX,
+                __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
+                #discriminant
+                match *self { #body }
+            }
+        },
+    )
+}
+
+pub fn hash_stable_derive(mut s: synstructure::Structure<'_>) -> proc_macro2::TokenStream {
+    let generic: syn::GenericParam = parse_quote!('__ctx);
+    s.add_bounds(synstructure::AddBounds::Generics);
+    s.add_impl_generic(generic);
+    let body = s.each(|bi| {
+        let attrs = parse_attributes(bi.ast());
+        if attrs.ignore {
+            quote! {}
+        } else if let Some(project) = attrs.project {
+            quote! {
+                &#bi.#project.hash_stable(__hcx, __hasher);
+            }
+        } else {
+            quote! {
+                #bi.hash_stable(__hcx, __hasher);
+            }
+        }
+    });
+
+    let discriminant = match s.ast().data {
+        syn::Data::Enum(_) => quote! {
+            ::std::mem::discriminant(self).hash_stable(__hcx, __hasher);
+        },
+        syn::Data::Struct(_) => quote! {},
+        syn::Data::Union(_) => panic!("cannot derive on union"),
+    };
+
+    s.bound_impl(
+        quote!(
+            ::rustc_data_structures::stable_hasher::HashStable<
+                ::rustc_middle::ich::StableHashingContext<'__ctx>,
+            >
+        ),
+        quote! {
+            fn hash_stable(
+                &self,
+                __hcx: &mut ::rustc_middle::ich::StableHashingContext<'__ctx>,
+                __hasher: &mut ::rustc_data_structures::stable_hasher::StableHasher) {
+                #discriminant
+                match *self { #body }
+            }
+        },
+    )
+}