Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- extern crate proc_macro;
- use proc_macro2::TokenStream;
- use syn::{parse_macro_input, DeriveInput, Ident, Data, Field};
- use quote::{quote, quote_spanned};
- #[proc_macro_derive(Builder)]
- pub fn derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
- let input = parse_macro_input!(input as DeriveInput);
- let typ = input.ident;
- let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
- let visibility = input.vis;
- let builder_typ = Ident::new(&format!("{}Builder", typ), typ.span());
- let builder_data = create_builder_data(&input.data);
- let expanded = quote! {
- impl #impl_generics #typ #ty_generics #where_clause {
- pub fn builder() {}
- }
- #visibility struct #builder_typ {
- #builder_data
- }
- };
- proc_macro::TokenStream::from(expanded)
- }
- fn create_builder_data(data: &Data) -> TokenStream {
- //Wrap each of the fields in an Option type
- let mut func = Box::new(|f: &Field| {
- let name = &f.ident;
- let typ = &f.ty;
- quote!{
- #name: Option<#typ>
- }
- });
- map_on_fields(data, &func)
- }
- fn map_on_fields(data: &Data, func: &Box<FnMut(Field) -> TokenStream>) -> TokenStream {
- use syn::Fields;
- match *data {
- Data::Struct(ref data) => {
- match data.fields {
- Fields::Named(ref fields) => {
- let recurse = fields.named.iter().map(*func);
- quote!{
- #(#recurse,)*
- }
- },
- _ => unimplemented!(),// only create builder if fields are named
- }
- },
- _ => unimplemented!(),// only create builder if it's a struct
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement