reflica 0.2.0

Automatically implements Deref / DerefMut / AsRef / AsMut from the given deref / deref_mut
Documentation
use proc_macro2::TokenStream;
use quote::quote;
use syn::{ImplItem, ItemImpl, ReturnType, Type, TypeReference};

pub fn generate(input: &ItemImpl) -> TokenStream {
    let ItemImpl {
        generics,
        self_ty,
        items,
        ..
    } = input;

    let Some(deref) = items.iter().find_map(|item| match item {
        ImplItem::Fn(fn_) if fn_.sig.ident == "deref" => Some(fn_),
        _ => None,
    }) else {
        return TokenStream::new();
    };

    let target = if let Some(target) = items.iter().find_map(|item| match item {
        ImplItem::Type(target) if target.ident == "Target" => Some(target),
        _ => None,
    }) {
        &target.ty
    } else if let ReturnType::Type(_, ref ty) = deref.sig.output {
        if let Type::Reference(TypeReference {
            lifetime: None,
            mutability: None,
            elem: ref ty,
            ..
        }) = **ty
        {
            ty
        } else {
            panic!("invalid return type for deref")
        }
    } else {
        panic!("Target type is not specified")
    };
    let fn_attrs = &deref.attrs;
    let fn_stmts = &deref.block.stmts;
    let (impl_generics, _, where_clause) = generics.split_for_impl();

    quote! {
        impl #impl_generics ::core::ops::Deref for #self_ty
        #where_clause {
            type Target = #target;

            #(#fn_attrs)*
            fn deref(&self) -> &Self::Target {
                #(#fn_stmts)*
            }
        }

        impl #impl_generics ::core::convert::AsRef<<Self as ::core::ops::Deref>::Target> for #self_ty
        #where_clause {
            fn as_ref(&self) -> &<Self as ::core::ops::Deref>::Target {
                <Self as ::core::ops::Deref>::deref(self)
            }
        }
    }
}