instrs-derive 0.1.0

Derive macro for instrs crate
Documentation

use proc_macro2::TokenStream;
use proc_macro::TokenStream as TStream;
use quote_into::quote_into;
use syn::{*, spanned::Spanned};

pub trait Callback = FnMut(&Field, &Ident, &mut TokenStream);

pub fn unnamed_field_ident(field: &Field, i: usize) -> Ident {
    let ident_str = format!("ident_{}", i);
    let ident_span = field.ty.span();
    Ident::new(&ident_str, ident_span)
}

pub fn idents(fields: &Fields, s: &mut TokenStream) {
    foreach_field(fields, s, |_, ident, s| {
        quote_into!{s +=
            #(ident),
        }
    })
}

pub fn foreach_field(fields: &Fields, s: &mut TokenStream, mut callback: impl Callback) {
    match fields {
        Fields::Named(fields) => for field in fields.named.iter() {
            let ident = field.clone().ident.unwrap();
            callback(field, &ident, s);
        },
        Fields::Unnamed(fields) => for (i, field) in fields.unnamed.iter().enumerate() {
            let ident = unnamed_field_ident(&field, i);
            callback(field, &ident, s);
        },
        Fields::Unit => {},
    }
}

pub fn match_fields(fields: &Fields, s: &mut TokenStream) {
    if let Fields::Unit {..} = fields {return;}

    if let Fields::Unnamed {..} = fields {
        quote_into!{ s +=
            (#{
                foreach_field(fields, s, |_, ident, s| {
                    quote_into!{s += #(ident),}
                })
            })
        }
    }

    if let Fields::Named {..} = fields {
        quote_into!{ s +=
            {#{
                foreach_field(fields, s, |_, ident, s| {
                    quote_into!{s += #(ident),}
                })
            }}
        }
    }
}