Instantly share code, notes, and snippets.

Embed
What would you like to do?
#![feature(proc_macro)]
extern crate proc_macro;
extern crate proc_macro2;
extern crate syn;
#[macro_use]
extern crate quote;
use proc_macro2::{Span};
use syn::{ItemFn, FnArg, ArgCaptured, Pat, PatIdent, Ident, ReturnType};
#[proc_macro_attribute]
pub fn auto_into(args: proc_macro::TokenStream, input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let input: ItemFn = syn::parse(input).unwrap();
let name = input.ident;
let (tys, args): (Vec<_>, Vec<_>) = input.decl.inputs.iter().map(|arg| {
if let FnArg::Captured(ArgCaptured { ty, pat, .. }) = arg {
if let Pat::Ident(PatIdent { ident, .. }) = pat {
(ty, ident)
} else {
unimplemented!()
}
} else {
unimplemented!()
}
}).unzip();
let new_tys = (0..tys.len()).map(|i| {
Ident::new(&format!("T{}", i), Span::call_site())
}).collect::<Vec<_>>();
let ty_quotes = tys.iter().zip(new_tys.iter()).map(|(ty, new_ty)| {
quote! { #new_ty: Into_<#ty> }
}).collect::<Vec<_>>();
let arg_quotes = args.iter().zip(new_tys.iter()).map(|(arg, new_ty)| {
quote! { #arg: #new_ty }
}).collect::<Vec<_>>();
let args2 = args.clone();
let body = input.block;
let ret = input.decl.output.clone();
let expanded = quote! {
fn #name<#(#ty_quotes),*>(#(#arg_quotes),*) #ret {
#(
let #args: #tys = #args2.into_();
)*
(#body).into_()
}
};
expanded.into()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment