1extern crate proc_macro;
2
3mod attrs;
4mod structs;
5
6use attrs::Attribute;
7use structs::{Field, Struct};
8
9use proc_macro::TokenStream as StdTokenStream;
10use proc_macro2::TokenStream;
11use quote::quote;
12use std::convert::TryFrom;
13
14#[proc_macro_derive(AsRef, attributes(as_ref))]
15pub fn derive(tokens: StdTokenStream) -> StdTokenStream {
16 let origin = syn::parse_macro_input!(tokens as syn::DeriveInput);
17 let input = match Struct::try_from(origin) {
18 Ok(input) => input,
19 Err(e) => return e.to_compile_error().into(),
20 };
21
22 produce_all_impl_asref(&input).into()
23}
24
25fn produce_all_impl_asref(input: &Struct) -> TokenStream {
26 input
27 .fields
28 .iter()
29 .flat_map(|field| {
30 field
31 .attrs
32 .iter()
33 .filter_map(Attribute::to_target)
34 .map(move |target| produce_impl_asref(input, field, &target.target))
35 })
36 .collect()
37}
38
39fn produce_impl_asref(input: &Struct, field: &Field, target: &syn::Ident) -> TokenStream {
40 let name = &input.ident;
41 let field_name = &field.ident;
42
43 quote! {
44 impl std::convert::AsRef<#target> for #name {
45 fn as_ref(&self) -> &#target {
46 &self.#field_name
47 }
48 }
49 }
50}