mirror of
https://github.com/martinvonz/jj.git
synced 2025-02-07 04:51:45 +00:00
965d6ce4e4
This is a no-op in terms of function, but provides a nicer way to derive the ContentHash trait for structs using the `#[derive(ContentHash)]` syntax used for other traits such as `Debug`. This commit only adds the macro. A subsequent commit will replace uses of `content_hash!{}` with `#[derive(ContentHash)]`. The new macro generates nice error messages, just like the old macro: ``` error[E0277]: the trait bound `NotImplemented: content_hash::ContentHash` is not satisfied --> lib/src/content_hash.rs:265:16 | 265 | z: NotImplemented, | ^^^^^^^^^^^^^^ the trait `content_hash::ContentHash` is not implemented for `NotImplemented` | = help: the following other types implement trait `content_hash::ContentHash`: bool i32 i64 u8 u32 u64 std::collections::HashMap<K, V> BTreeMap<K, V> and 38 others ``` This commit does two things to make proc macros re-exported by jj_lib useable by deps: 1. jj_lib needs to be able refer to itself as `jj_lib` which it does by adding an `extern crate self as jj_lib` declaration. 2. jj_lib::content_hash needs to re-export the `digest::Update` type so that users of jj_lib can use the `#[derive(ContentHash)]` proc macro without directly depending on the digest crate. This is done by re-exporting it as `DigestUpdate`. #3054
40 lines
1.4 KiB
Rust
40 lines
1.4 KiB
Rust
use proc_macro2::TokenStream;
|
|
use quote::{quote, quote_spanned};
|
|
use syn::spanned::Spanned;
|
|
use syn::{Data, Fields, Index};
|
|
|
|
pub fn generate_hash_impl(data: &Data) -> TokenStream {
|
|
match *data {
|
|
Data::Struct(ref data) => match data.fields {
|
|
Fields::Named(ref fields) => {
|
|
let hash_statements = fields.named.iter().map(|f| {
|
|
let field_name = &f.ident;
|
|
let ty = &f.ty;
|
|
quote_spanned! {ty.span()=>
|
|
<#ty as ::jj_lib::content_hash::ContentHash>::hash(
|
|
&self.#field_name, state);
|
|
}
|
|
});
|
|
quote! {
|
|
#(#hash_statements)*
|
|
}
|
|
}
|
|
Fields::Unnamed(ref fields) => {
|
|
let hash_statements = fields.unnamed.iter().enumerate().map(|(i, f)| {
|
|
let index = Index::from(i);
|
|
let ty = &f.ty;
|
|
quote_spanned! {ty.span() =>
|
|
<#ty as ::jj_lib::content_hash::ContentHash>::hash(&self.#index, state);
|
|
}
|
|
});
|
|
quote! {
|
|
#(#hash_statements)*
|
|
}
|
|
}
|
|
Fields::Unit => {
|
|
quote! {}
|
|
}
|
|
},
|
|
_ => unimplemented!("ContentHash can only be derived for structs."),
|
|
}
|
|
}
|