overloading 0.1.2

A POC crate that utilizes `Fn*` traits to implement partial overloading
Documentation
#![doc = include_str!("../README.md")]

use proc_macro2::{Ident, TokenStream};
use quote::quote;
use syn::{parse_macro_input, spanned::Spanned, Signature};

extern crate proc_macro;
use syn::ItemFn;

#[proc_macro_attribute]
pub fn overloading(
    attrs: proc_macro::TokenStream,
    input: proc_macro::TokenStream,
) -> proc_macro::TokenStream {
    let ItemFn {
        vis, sig, block, ..
    } = parse_macro_input!(input as ItemFn);

    let error = filter_sig(&sig);
    if !error.is_empty() {
        return error.into();
    }
    let Signature {
        mut ident,
        generics,
        inputs,
        output,
        ..
    } = sig;
    let struct_def = if attrs.is_empty() {
        quote! {
            #[allow(non_camel_case_types)]
            #vis struct #ident;
        }
    } else {
        let new_ident = parse_macro_input!(attrs as Ident);
        ident = new_ident;
        quote!()
    };

    let mut tys = vec![];
    let mut pats = vec![];
    for input in inputs {
        match input {
            syn::FnArg::Receiver(kw) => {
                return syn::Error::new(kw.span(), "Method is not implemented")
                    .into_compile_error()
                    .into();
            }
            syn::FnArg::Typed(typed) => {
                tys.push(typed.ty.clone());
                pats.push(typed.pat);
            }
        }
    }
    let output = match output {
        syn::ReturnType::Default => quote!(()),
        syn::ReturnType::Type(_, ty) => quote!(#ty),
    };
    let pat = if pats.is_empty() {
        quote!(_)
    } else {
        quote!( (#(#pats),*,) )
    };
    let arg = if tys.is_empty() {
        quote!(())
    } else {
        quote!( (#(#tys),*,) )
    };

    quote! {
        #struct_def

        impl #generics std::ops::FnOnce<#arg> for #ident {
            type Output = #output;

            extern "rust-call" fn call_once(self, #pat: #arg) -> Self::Output #block
        }

        impl #generics std::ops::FnMut<#arg> for #ident {
            extern "rust-call" fn call_mut(&mut self, #pat: #arg) -> Self::Output #block
        }

        impl #generics std::ops::Fn<#arg> for #ident {
            extern "rust-call" fn call(&self, #pat: #arg) -> Self::Output #block
        }
    }
    .into()
}

fn filter_sig(sig: &Signature) -> TokenStream {
    let Signature {
        constness,
        asyncness,
        unsafety,
        abi,
        variadic,
        ..
    } = sig;

    if let Some(kw) = constness {
        return syn::Error::new(kw.span(), "Const overloading is not implemented")
            .into_compile_error();
    };
    if let Some(kw) = asyncness {
        return syn::Error::new(kw.span(), "Async overloading is not implemented")
            .into_compile_error();
    }
    if let Some(kw) = unsafety {
        return syn::Error::new(kw.span(), "Unsafe Fn* is not supported").to_compile_error();
    }
    if let Some(kw) = abi {
        return syn::Error::new(kw.span(), "Custom ABI is not supported").to_compile_error();
    }
    if let Some(kw) = variadic {
        return syn::Error::new(kw.span(), "Variadic is not supported").to_compile_error();
    }

    TokenStream::new()
}

#[test]
fn test() {}