derive_asref/
lib.rs

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}