fields-converter-derive 0.1.4

Fields-wise type conversions derive macros
Documentation
use proc_macro2::{Span, TokenStream};
use quote::ToTokens;
use syn;

pub struct Field {
    pub id: FieldId,
    pub ty: syn::Type,
}

pub enum FieldId {
    Named(syn::Ident),
    Unnamed(syn::Index),
}

impl Field {
    fn from_syn(index: usize, orig: &syn::Field, span: Span) -> Self {
        let id = orig.ident.clone().map(FieldId::Named).unwrap_or_else(|| {
            FieldId::Unnamed(syn::Index {
                index: index as u32,
                span,
            })
        });
        Field {
            id,
            ty: orig.ty.clone(),
        }
    }
}

impl ToTokens for FieldId {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        match self {
            FieldId::Named(id) => id.to_tokens(tokens),
            FieldId::Unnamed(idx) => idx.to_tokens(tokens),
        }
    }
}

pub struct StructData {
    pub name: syn::Ident,
    pub field_idents: Vec<Field>,
    pub generics: syn::Generics,
}

impl StructData {
    pub fn new(data_struct: &syn::DataStruct, ident: syn::Ident, generics: syn::Generics) -> Self {
        let span = ident.span();
        StructData {
            name: ident,
            field_idents: get_fields(data_struct.fields.iter(), span),
            generics,
        }
    }

    pub fn add_bound(&mut self, bound: &str) {
        let bound = syn::TraitBound {
            paren_token: None,
            modifier: syn::TraitBoundModifier::None,
            lifetimes: None,
            path: syn::Ident::new(bound, Span::call_site()).into(),
        };
        self.generics.type_params_mut().for_each(|param| {
            param.bounds.push(bound.clone().into());
        });
    }
}

fn get_fields<'a>(fields: impl IntoIterator<Item = &'a syn::Field>, span: Span) -> Vec<Field> {
    fields
        .into_iter()
        .enumerate()
        .map(|(i, field)| Field::from_syn(i, field, span))
        .collect()
}